From 74ee59a825f9c0e6b5a95bea3b7ac4627526f42d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 19 Jul 2012 19:34:38 -0300 Subject: [PATCH 01/48] monitor: drop unused monitor debug code In the old QMP days, this code was used to find out QMP commands that might be calling monitor_printf() down its call chain. This is almost impossible to happen today, because the qapi converted commands don't even have a monitor object. Besides, it's been more than a year since I used this last time. Let's just drop it. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- configure | 10 --------- monitor.c | 65 ------------------------------------------------------- 2 files changed, 75 deletions(-) diff --git a/configure b/configure index f0dbc03af2..8a06c11a46 100755 --- a/configure +++ b/configure @@ -171,7 +171,6 @@ vhost_net="no" kvm="no" gprof="no" debug_tcg="no" -debug_mon="no" debug="no" strip_opt="yes" tcg_interpreter="no" @@ -657,14 +656,9 @@ for opt do ;; --disable-debug-tcg) debug_tcg="no" ;; - --enable-debug-mon) debug_mon="yes" - ;; - --disable-debug-mon) debug_mon="no" - ;; --enable-debug) # Enable debugging options that aren't excessively noisy debug_tcg="yes" - debug_mon="yes" debug="yes" strip_opt="no" ;; @@ -3064,7 +3058,6 @@ echo "host CPU $cpu" echo "host big endian $bigendian" echo "target list $target_list" echo "tcg debug enabled $debug_tcg" -echo "Mon debug enabled $debug_mon" echo "gprof enabled $gprof" echo "sparse enabled $sparse" echo "strip binaries $strip_opt" @@ -3157,9 +3150,6 @@ echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak fi -if test "$debug_mon" = "yes" ; then - echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak -fi if test "$debug" = "yes" ; then echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak fi diff --git a/monitor.c b/monitor.c index 49dccfe854..aa5716782a 100644 --- a/monitor.c +++ b/monitor.c @@ -172,41 +172,11 @@ struct Monitor { CPUArchState *mon_cpu; BlockDriverCompletionFunc *password_completion_cb; void *password_opaque; -#ifdef CONFIG_DEBUG_MONITOR - int print_calls_nr; -#endif QError *error; QLIST_HEAD(,mon_fd_t) fds; QLIST_ENTRY(Monitor) entry; }; -#ifdef CONFIG_DEBUG_MONITOR -#define MON_DEBUG(fmt, ...) do { \ - fprintf(stderr, "Monitor: "); \ - fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) - -static inline void mon_print_count_inc(Monitor *mon) -{ - mon->print_calls_nr++; -} - -static inline void mon_print_count_init(Monitor *mon) -{ - mon->print_calls_nr = 0; -} - -static inline int mon_print_count_get(const Monitor *mon) -{ - return mon->print_calls_nr; -} - -#else /* !CONFIG_DEBUG_MONITOR */ -#define MON_DEBUG(fmt, ...) do { } while (0) -static inline void mon_print_count_inc(Monitor *mon) { } -static inline void mon_print_count_init(Monitor *mon) { } -static inline int mon_print_count_get(const Monitor *mon) { return 0; } -#endif /* CONFIG_DEBUG_MONITOR */ - /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 @@ -299,8 +269,6 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) if (!mon) return; - mon_print_count_inc(mon); - if (monitor_ctrl_mode(mon)) { return; } @@ -3860,8 +3828,6 @@ void monitor_set_error(Monitor *mon, QError *qerror) if (!mon->error) { mon->error = qerror; } else { - MON_DEBUG("Additional error report at %s:%d\n", - qerror->file, qerror->linenr); QDECREF(qerror); } } @@ -3875,36 +3841,7 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) * Action: Report an internal error to the client if in QMP. */ qerror_report(QERR_UNDEFINED_ERROR); - MON_DEBUG("command '%s' returned failure but did not pass an error\n", - cmd->name); } - -#ifdef CONFIG_DEBUG_MONITOR - if (!ret && monitor_has_error(mon)) { - /* - * If it returns success, it must not have passed an error. - * - * Action: Report the passed error to the client. - */ - MON_DEBUG("command '%s' returned success but passed an error\n", - cmd->name); - } - - if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { - /* - * Handlers should not call Monitor print functions. - * - * Action: Ignore them in QMP. - * - * (XXX: we don't check any 'info' or 'query' command here - * because the user print function _is_ called by do_info(), hence - * we will trigger this check. This problem will go away when we - * make 'query' commands real and kill do_info()) - */ - MON_DEBUG("command '%s' called print functions %d time(s)\n", - cmd->name, mon_print_count_get(mon)); - } -#endif } static void handle_user_command(Monitor *mon, const char *cmdline) @@ -4433,8 +4370,6 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd, int ret; QObject *data = NULL; - mon_print_count_init(mon); - ret = cmd->mhandler.cmd_new(mon, params, &data); handler_audit(mon, cmd, ret); monitor_protocol_emitter(mon, data); From 484051b9960736a6ebff3cfed78c4b29758e63c0 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 25 Jul 2012 13:18:41 -0300 Subject: [PATCH 02/48] qerror: QERR_AMBIGUOUS_PATH: drop %(object) from human msg Actually, renames it to 'object'. This must be what the original author meant to write, as there's no 'object' in the error's data member. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qerror.c b/qerror.c index 92c4eff179..082de987ed 100644 --- a/qerror.c +++ b/qerror.c @@ -49,7 +49,7 @@ static const QErrorStringTable qerror_table[] = { }, { .error_fmt = QERR_AMBIGUOUS_PATH, - .desc = "Path '%(path)' does not uniquely identify a %(object)" + .desc = "Path '%(path)' does not uniquely identify an object" }, { .error_fmt = QERR_BAD_BUS_FOR_DEVICE, From b5d90f0424ea27eb126a4eaed2554908fc463d9f Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 25 Jul 2012 13:16:53 -0300 Subject: [PATCH 03/48] qerror: QERR_DEVICE_ENCRYPTED: change error message Match what HMP commands print on DeviceEncrypted errors. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qerror.c b/qerror.c index 082de987ed..de0a79e17d 100644 --- a/qerror.c +++ b/qerror.c @@ -81,7 +81,7 @@ static const QErrorStringTable qerror_table[] = { }, { .error_fmt = QERR_DEVICE_ENCRYPTED, - .desc = "Device '%(device)' is encrypted", + .desc = "'%(device)' (%(filename)) is encrypted", }, { .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, From 2a74440547ea0a15195224fa2b7784b267cbfe15 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 19 Jul 2012 17:29:34 -0300 Subject: [PATCH 04/48] qerror: reduce public exposure qerror will be dropped in a near future, let's reduce its public exposure by making functions only used in qerror.c static. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 10 +++++----- qerror.h | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/qerror.c b/qerror.c index de0a79e17d..bfb875a951 100644 --- a/qerror.c +++ b/qerror.c @@ -336,7 +336,7 @@ static const QErrorStringTable qerror_table[] = { * * Return strong reference. */ -QError *qerror_new(void) +static QError *qerror_new(void) { QError *qerr; @@ -424,8 +424,8 @@ static void qerror_set_desc(QError *qerr, const char *fmt) * * Return strong reference. */ -QError *qerror_from_info(const char *file, int linenr, const char *func, - const char *fmt, va_list *va) +static QError *qerror_from_info(const char *file, int linenr, const char *func, + const char *fmt, va_list *va) { QError *qerr; @@ -549,7 +549,7 @@ QString *qerror_human(const QError *qerror) * it uses error_report() for this, so that the output is routed to the right * place (ie. stderr or Monitor's device). */ -void qerror_print(QError *qerror) +static void qerror_print(QError *qerror) { QString *qstring = qerror_human(qerror); loc_push_restore(&qerror->loc); @@ -620,7 +620,7 @@ void assert_no_error(Error *err) /** * qobject_to_qerror(): Convert a QObject into a QError */ -QError *qobject_to_qerror(const QObject *obj) +static QError *qobject_to_qerror(const QObject *obj) { if (qobject_type(obj) != QTYPE_QERROR) { return NULL; diff --git a/qerror.h b/qerror.h index b4c8758f40..fe8870c062 100644 --- a/qerror.h +++ b/qerror.h @@ -33,11 +33,7 @@ typedef struct QError { const QErrorStringTable *entry; } QError; -QError *qerror_new(void); -QError *qerror_from_info(const char *file, int linenr, const char *func, - const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0); QString *qerror_human(const QError *qerror); -void qerror_print(QError *qerror); void qerror_report_internal(const char *file, int linenr, const char *func, const char *fmt, ...) GCC_FMT_ATTR(4, 5); void qerror_report_err(Error *err); @@ -45,7 +41,6 @@ void assert_no_error(Error *err); QString *qerror_format(const char *fmt, QDict *error); #define qerror_report(fmt, ...) \ qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) -QError *qobject_to_qerror(const QObject *obj); /* * QError class list From fbe0a831f68348d228acd9a4ec8a25582396282a Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 20 Jul 2012 10:35:18 -0300 Subject: [PATCH 05/48] qerror: drop qerror_abort() qerror_abort() depends on the 'file', 'func' and 'linenr' members of QError. However, these members are going to be dropped by the next commit, so let's drop qerror_abort() in favor of printing an error message to stderr plus a call to abort(). Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/qerror.c b/qerror.c index bfb875a951..7cb7c12bd4 100644 --- a/qerror.c +++ b/qerror.c @@ -346,22 +346,6 @@ static QError *qerror_new(void) return qerr; } -static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr, - const char *fmt, ...) -{ - va_list ap; - - fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func); - fprintf(stderr, "qerror: -> "); - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr); - abort(); -} - static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, const char *fmt, va_list *va) { @@ -369,28 +353,34 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, obj = qobject_from_jsonv(fmt, va); if (!obj) { - qerror_abort(qerr, "invalid format '%s'", fmt); + fprintf(stderr, "invalid json in error dict '%s'\n", fmt); + abort(); } if (qobject_type(obj) != QTYPE_QDICT) { - qerror_abort(qerr, "error format is not a QDict '%s'", fmt); + fprintf(stderr, "error is not a dict '%s'\n", fmt); + abort(); } qerr->error = qobject_to_qdict(obj); obj = qdict_get(qerr->error, "class"); if (!obj) { - qerror_abort(qerr, "missing 'class' key in '%s'", fmt); + fprintf(stderr, "missing 'class' key in '%s'\n", fmt); + abort(); } if (qobject_type(obj) != QTYPE_QSTRING) { - qerror_abort(qerr, "'class' key value should be a QString"); + fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt); + abort(); } obj = qdict_get(qerr->error, "data"); if (!obj) { - qerror_abort(qerr, "missing 'data' key in '%s'", fmt); + fprintf(stderr, "missing 'data' key in '%s'\n", fmt); + abort(); } if (qobject_type(obj) != QTYPE_QDICT) { - qerror_abort(qerr, "'data' key value should be a QDICT"); + fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt); + abort(); } } @@ -407,7 +397,8 @@ static void qerror_set_desc(QError *qerr, const char *fmt) } } - qerror_abort(qerr, "error format '%s' not found", fmt); + fprintf(stderr, "error format '%s' not found\n", fmt); + abort(); } /** @@ -435,10 +426,6 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func, qerr->file = file; qerr->func = func; - if (!fmt) { - qerror_abort(qerr, "QDict not specified"); - } - qerror_set_data(qerr, fmt, va); qerror_set_desc(qerr, fmt); From f2dd1d69edf0080d7d08dd3e8c7bfc6b488d59e4 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 31 Jul 2012 15:41:13 -0300 Subject: [PATCH 06/48] qerror: avoid passing qerr pointer Helps dropping/modifying qerror functions. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/qerror.c b/qerror.c index 7cb7c12bd4..e717496142 100644 --- a/qerror.c +++ b/qerror.c @@ -346,10 +346,10 @@ static QError *qerror_new(void) return qerr; } -static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, - const char *fmt, va_list *va) +static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va) { QObject *obj; + QDict *ret; obj = qobject_from_jsonv(fmt, va); if (!obj) { @@ -361,9 +361,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, abort(); } - qerr->error = qobject_to_qdict(obj); - - obj = qdict_get(qerr->error, "class"); + ret = qobject_to_qdict(obj); + obj = qdict_get(ret, "class"); if (!obj) { fprintf(stderr, "missing 'class' key in '%s'\n", fmt); abort(); @@ -372,8 +371,8 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt); abort(); } - - obj = qdict_get(qerr->error, "data"); + + obj = qdict_get(ret, "data"); if (!obj) { fprintf(stderr, "missing 'data' key in '%s'\n", fmt); abort(); @@ -382,9 +381,11 @@ static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr, fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt); abort(); } + + return ret; } -static void qerror_set_desc(QError *qerr, const char *fmt) +static const QErrorStringTable *get_desc_no_fail(const char *fmt) { int i; @@ -392,8 +393,7 @@ static void qerror_set_desc(QError *qerr, const char *fmt) for (i = 0; qerror_table[i].error_fmt; i++) { if (strcmp(qerror_table[i].error_fmt, fmt) == 0) { - qerr->entry = &qerror_table[i]; - return; + return &qerror_table[i]; } } @@ -426,8 +426,8 @@ static QError *qerror_from_info(const char *file, int linenr, const char *func, qerr->file = file; qerr->func = func; - qerror_set_data(qerr, fmt, va); - qerror_set_desc(qerr, fmt); + qerr->error = error_obj_from_fmt_no_fail(fmt, va); + qerr->entry = get_desc_no_fail(fmt); return qerr; } From 5f0f0e13e1f714704d96f04050674c3102376409 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 20 Jul 2012 11:08:17 -0300 Subject: [PATCH 07/48] qerror: QError: drop file, linenr, func They have never been fully used and conflict with future error improvements. Also makes qerror_report() a proper function, as there's no point in having it as a macro anymore. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 20 +++----------------- qerror.h | 8 +------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/qerror.c b/qerror.c index e717496142..6f9f49c5e3 100644 --- a/qerror.c +++ b/qerror.c @@ -404,27 +404,14 @@ static const QErrorStringTable *get_desc_no_fail(const char *fmt) /** * qerror_from_info(): Create a new QError from error information * - * The information consists of: - * - * - file the file name of where the error occurred - * - linenr the line number of where the error occurred - * - func the function name of where the error occurred - * - fmt JSON printf-like dictionary, there must exist keys 'class' and - * 'data' - * - va va_list of all arguments specified by fmt - * * Return strong reference. */ -static QError *qerror_from_info(const char *file, int linenr, const char *func, - const char *fmt, va_list *va) +static QError *qerror_from_info(const char *fmt, va_list *va) { QError *qerr; qerr = qerror_new(); loc_save(&qerr->loc); - qerr->linenr = linenr; - qerr->file = file; - qerr->func = func; qerr->error = error_obj_from_fmt_no_fail(fmt, va); qerr->entry = get_desc_no_fail(fmt); @@ -545,14 +532,13 @@ static void qerror_print(QError *qerror) QDECREF(qstring); } -void qerror_report_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) +void qerror_report(const char *fmt, ...) { va_list va; QError *qerror; va_start(va, fmt); - qerror = qerror_from_info(file, linenr, func, fmt, &va); + qerror = qerror_from_info(fmt, &va); va_end(va); if (monitor_cur_is_qmp()) { diff --git a/qerror.h b/qerror.h index fe8870c062..3c0b14c645 100644 --- a/qerror.h +++ b/qerror.h @@ -27,20 +27,14 @@ typedef struct QError { QObject_HEAD; QDict *error; Location loc; - int linenr; - const char *file; - const char *func; const QErrorStringTable *entry; } QError; QString *qerror_human(const QError *qerror); -void qerror_report_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) GCC_FMT_ATTR(4, 5); +void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); void qerror_report_err(Error *err); void assert_no_error(Error *err); QString *qerror_format(const char *fmt, QDict *error); -#define qerror_report(fmt, ...) \ - qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__) /* * QError class list From 2b38cf2e033d90fb50fc967f535935b170dc507d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 20 Jul 2012 13:30:18 -0300 Subject: [PATCH 08/48] qerror: qerror_format(): return an allocated string Simplifies current and future users. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 5 +---- qerror.c | 10 ++++++++-- qerror.h | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/error.c b/error.c index 58f55a012e..3a62592261 100644 --- a/error.c +++ b/error.c @@ -65,10 +65,7 @@ bool error_is_set(Error **errp) const char *error_get_pretty(Error *err) { if (err->msg == NULL) { - QString *str; - str = qerror_format(err->fmt, err->obj); - err->msg = g_strdup(qstring_get_str(str)); - QDECREF(str); + err->msg = qerror_format(err->fmt, err->obj); } return err->msg; diff --git a/qerror.c b/qerror.c index 6f9f49c5e3..d073ed7c5a 100644 --- a/qerror.c +++ b/qerror.c @@ -493,9 +493,11 @@ static QString *qerror_format_desc(QDict *error, return qstring; } -QString *qerror_format(const char *fmt, QDict *error) +char *qerror_format(const char *fmt, QDict *error) { const QErrorStringTable *entry = NULL; + QString *qstr; + char *ret; int i; for (i = 0; qerror_table[i].error_fmt; i++) { @@ -505,7 +507,11 @@ QString *qerror_format(const char *fmt, QDict *error) } } - return qerror_format_desc(error, entry); + qstr = qerror_format_desc(error, entry); + ret = g_strdup(qstring_get_str(qstr)); + QDECREF(qstr); + + return ret; } /** diff --git a/qerror.h b/qerror.h index 3c0b14c645..aec76b24e1 100644 --- a/qerror.h +++ b/qerror.h @@ -34,7 +34,7 @@ QString *qerror_human(const QError *qerror); void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); void qerror_report_err(Error *err); void assert_no_error(Error *err); -QString *qerror_format(const char *fmt, QDict *error); +char *qerror_format(const char *fmt, QDict *error); /* * QError class list From 18da7c0f1f24cc00f7c2f80c27cb85e4b234e091 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 20 Jul 2012 12:02:58 -0300 Subject: [PATCH 09/48] qerror: don't delay error message construction Today, the error message is only constructed when it's used. This commit changes qerror to construct the error message when the error object is built (ie. when the error is reported). This eliminates the need of storing a pointer to qerror_table[], which will be dropped soon, and also simplifies the code. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 29 ++++------------------------- qerror.h | 2 +- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/qerror.c b/qerror.c index d073ed7c5a..a254f88531 100644 --- a/qerror.c +++ b/qerror.c @@ -385,22 +385,6 @@ static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va) return ret; } -static const QErrorStringTable *get_desc_no_fail(const char *fmt) -{ - int i; - - // FIXME: inefficient loop - - for (i = 0; qerror_table[i].error_fmt; i++) { - if (strcmp(qerror_table[i].error_fmt, fmt) == 0) { - return &qerror_table[i]; - } - } - - fprintf(stderr, "error format '%s' not found\n", fmt); - abort(); -} - /** * qerror_from_info(): Create a new QError from error information * @@ -414,7 +398,7 @@ static QError *qerror_from_info(const char *fmt, va_list *va) loc_save(&qerr->loc); qerr->error = error_obj_from_fmt_no_fail(fmt, va); - qerr->entry = get_desc_no_fail(fmt); + qerr->err_msg = qerror_format(fmt, qerr->error); return qerr; } @@ -519,7 +503,7 @@ char *qerror_format(const char *fmt, QDict *error) */ QString *qerror_human(const QError *qerror) { - return qerror_format_desc(qerror->error, qerror->entry); + return qstring_from_str(qerror->err_msg); } /** @@ -566,19 +550,13 @@ struct Error void qerror_report_err(Error *err) { QError *qerr; - int i; qerr = qerror_new(); loc_save(&qerr->loc); QINCREF(err->obj); qerr->error = err->obj; - for (i = 0; qerror_table[i].error_fmt; i++) { - if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) { - qerr->entry = &qerror_table[i]; - break; - } - } + qerr->err_msg = qerror_format(err->fmt, qerr->error); if (monitor_cur_is_qmp()) { monitor_set_error(cur_mon, qerr); @@ -619,5 +597,6 @@ static void qerror_destroy_obj(QObject *obj) qerr = qobject_to_qerror(obj); QDECREF(qerr->error); + g_free(qerr->err_msg); g_free(qerr); } diff --git a/qerror.h b/qerror.h index aec76b24e1..de8497d1eb 100644 --- a/qerror.h +++ b/qerror.h @@ -27,7 +27,7 @@ typedef struct QError { QObject_HEAD; QDict *error; Location loc; - const QErrorStringTable *entry; + char *err_msg; } QError; QString *qerror_human(const QError *qerror); From dd7520f0646985b08024c73ba2285c31d7318755 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 20 Jul 2012 13:43:37 -0300 Subject: [PATCH 10/48] error: don't delay error message construction Today, the error message is only constructed when it's used. This commit changes that to construct the error message when the error object is built (ie. when the error is reported). This simplifies the Error object. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 8 +------- qerror.c | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/error.c b/error.c index 3a62592261..2ade99b080 100644 --- a/error.c +++ b/error.c @@ -20,7 +20,6 @@ struct Error { QDict *obj; - const char *fmt; char *msg; }; @@ -39,7 +38,7 @@ void error_set(Error **errp, const char *fmt, ...) va_start(ap, fmt); err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap)); va_end(ap); - err->fmt = fmt; + err->msg = qerror_format(fmt, err->obj); *errp = err; } @@ -50,7 +49,6 @@ Error *error_copy(const Error *err) err_new = g_malloc0(sizeof(*err)); err_new->msg = g_strdup(err->msg); - err_new->fmt = err->fmt; err_new->obj = err->obj; QINCREF(err_new->obj); @@ -64,10 +62,6 @@ bool error_is_set(Error **errp) const char *error_get_pretty(Error *err) { - if (err->msg == NULL) { - err->msg = qerror_format(err->fmt, err->obj); - } - return err->msg; } diff --git a/qerror.c b/qerror.c index a254f88531..5d3842863f 100644 --- a/qerror.c +++ b/qerror.c @@ -543,7 +543,6 @@ void qerror_report(const char *fmt, ...) struct Error { QDict *obj; - const char *fmt; char *msg; }; @@ -555,8 +554,7 @@ void qerror_report_err(Error *err) loc_save(&qerr->loc); QINCREF(err->obj); qerr->error = err->obj; - - qerr->err_msg = qerror_format(err->fmt, qerr->error); + qerr->err_msg = g_strdup(err->msg); if (monitor_cur_is_qmp()) { monitor_set_error(cur_mon, qerr); From c75a1a8a5a34ef10f704c521c475a6dd4de5e887 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Jul 2012 20:28:44 -0300 Subject: [PATCH 11/48] qmp: query-block: add 'encryption_key_missing' field Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- block.c | 1 + qapi-schema.json | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 24323c11d0..016858bf8c 100644 --- a/block.c +++ b/block.c @@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp) info->value->inserted->ro = bs->read_only; info->value->inserted->drv = g_strdup(bs->drv->format_name); info->value->inserted->encrypted = bs->encrypted; + info->value->inserted->encryption_key_missing = bdrv_key_required(bs); if (bs->backing_file[0]) { info->value->inserted->has_backing_file = true; info->value->inserted->backing_file = g_strdup(bs->backing_file); diff --git a/qapi-schema.json b/qapi-schema.json index bd9c450029..a62bf6867b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -402,6 +402,9 @@ # # @encrypted: true if the backing device is encrypted # +# @encryption_key_missing: true if the backing device is encrypted but an +# valid encryption key is missing +# # @bps: total throughput limit in bytes per second is specified # # @bps_rd: read throughput limit in bytes per second is specified @@ -421,9 +424,9 @@ { 'type': 'BlockDeviceInfo', 'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str', '*backing_file': 'str', 'backing_file_depth': 'int', - 'encrypted': 'bool', 'bps': 'int', 'bps_rd': 'int', - 'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int', - 'iops_wr': 'int'} } + 'encrypted': 'bool', 'encryption_key_missing': 'bool', + 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int', + 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} } ## # @BlockDeviceIoStatus: From 8b7f6fbbdc5545f749864fdf295f2fae14c7ef0a Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Jul 2012 20:41:53 -0300 Subject: [PATCH 12/48] hmp: hmp_cont(): don't rely on QERR_DEVICE_ENCRYPTED This commit changes hmp_cont() to loop through all block devices and proactively set an encryption key for any encrypted device missing a key. This change is needed because QERR_DEVICE_ENCRYPTED is going to be dropped by a future commit. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- hmp.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/hmp.c b/hmp.c index 25688ab0e2..4efaf516ff 100644 --- a/hmp.c +++ b/hmp.c @@ -612,34 +612,35 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) static void hmp_cont_cb(void *opaque, int err) { - Monitor *mon = opaque; - if (!err) { - hmp_cont(mon, NULL); + qmp_cont(NULL); } } +static bool key_is_missing(const BlockInfo *bdev) +{ + return (bdev->inserted && bdev->inserted->encryption_key_missing); +} + void hmp_cont(Monitor *mon, const QDict *qdict) { + BlockInfoList *bdev_list, *bdev; Error *errp = NULL; - qmp_cont(&errp); - if (error_is_set(&errp)) { - if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) { - const char *device; - - /* The device is encrypted. Ask the user for the password - and retry */ - - device = error_get_field(errp, "device"); - assert(device != NULL); - - monitor_read_block_device_key(mon, device, hmp_cont_cb, mon); - error_free(errp); - return; + bdev_list = qmp_query_block(NULL); + for (bdev = bdev_list; bdev; bdev = bdev->next) { + if (key_is_missing(bdev->value)) { + monitor_read_block_device_key(mon, bdev->value->device, + hmp_cont_cb, NULL); + goto out; } - hmp_handle_error(mon, &errp); } + + qmp_cont(&errp); + hmp_handle_error(mon, &errp); + +out: + qapi_free_BlockInfoList(bdev_list); } void hmp_system_wakeup(Monitor *mon, const QDict *qdict) From eef5ad1086403d8ac8d91208a0e8dc34734b671c Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 6 Aug 2012 15:49:34 -0300 Subject: [PATCH 13/48] hmp_change(): don't access DeviceEncrypted's data It's not needed. As the device name is already known, we can replace the duplicated password prompting code by monitor_read_block_device_key(). This overly simplifies hmp_change(). Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- hmp.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/hmp.c b/hmp.c index 4efaf516ff..54c37d7254 100644 --- a/hmp.c +++ b/hmp.c @@ -776,22 +776,6 @@ static void hmp_change_read_arg(Monitor *mon, const char *password, monitor_read_command(mon, 1); } -static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password, - void *opaque) -{ - Error *encryption_err = opaque; - Error *err = NULL; - const char *device; - - device = error_get_field(encryption_err, "device"); - - qmp_block_passwd(device, password, &err); - hmp_handle_error(mon, &err); - error_free(encryption_err); - - monitor_read_command(mon, 1); -} - void hmp_change(Monitor *mon, const QDict *qdict) { const char *device = qdict_get_str(qdict, "device"); @@ -810,17 +794,8 @@ void hmp_change(Monitor *mon, const QDict *qdict) qmp_change(device, target, !!arg, arg, &err); if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) { - monitor_printf(mon, "%s (%s) is encrypted.\n", - error_get_field(err, "device"), - error_get_field(err, "filename")); - if (!monitor_get_rs(mon)) { - monitor_printf(mon, - "terminal does not support password prompting\n"); - error_free(err); - return; - } - readline_start(monitor_get_rs(mon), "Password: ", 1, - cb_hmp_change_bdrv_pwd, err); + error_free(err); + monitor_read_block_device_key(mon, device, NULL, NULL); return; } hmp_handle_error(mon, &err); From 02a08fef079469c005d48fe2d181f0e0eb5752ae Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 13:42:47 -0300 Subject: [PATCH 14/48] net: inet_connect(), inet_connect_opts(): add in_progress argument It's used to indicate the special case where a valid file-descriptor is returned (ie. success) but the connection can't be completed w/o blocking. This is needed because QERR_SOCKET_CONNECT_IN_PROGRESS is not treated like an error and a future commit will drop it. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- migration-tcp.c | 2 +- nbd.c | 2 +- qemu-char.c | 2 +- qemu-sockets.c | 14 +++++++++++--- qemu_socket.h | 4 ++-- ui/vnc.c | 2 +- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/migration-tcp.c b/migration-tcp.c index 440804db75..18944a41a3 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -86,7 +86,7 @@ int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, s->write = socket_write; s->close = tcp_close; - s->fd = inet_connect(host_port, false, errp); + s->fd = inet_connect(host_port, false, NULL, errp); if (!error_is_set(errp)) { migrate_fd_connect(s); diff --git a/nbd.c b/nbd.c index dc0adf90ed..0dd60c5f4c 100644 --- a/nbd.c +++ b/nbd.c @@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port) int tcp_socket_outgoing_spec(const char *address_and_port) { - return inet_connect(address_and_port, true, NULL); + return inet_connect(address_and_port, true, NULL, NULL); } int tcp_socket_incoming(const char *address, uint16_t port) diff --git a/qemu-char.c b/qemu-char.c index c2aaaeeb8f..382c71ebcd 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2446,7 +2446,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (is_listen) { fd = inet_listen_opts(opts, 0, NULL); } else { - fd = inet_connect_opts(opts, NULL); + fd = inet_connect_opts(opts, NULL, NULL); } } if (fd < 0) { diff --git a/qemu-sockets.c b/qemu-sockets.c index beb2bb6f4a..9cb47d4232 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -209,7 +209,7 @@ listen: return slisten; } -int inet_connect_opts(QemuOpts *opts, Error **errp) +int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; @@ -224,6 +224,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp) ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; + if (in_progress) { + *in_progress = false; + } + addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); block = qemu_opt_get_bool(opts, "block", 0); @@ -277,6 +281,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp) #else if (!block && (rc == -EINPROGRESS)) { #endif + if (in_progress) { + *in_progress = true; + } + error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS); } else if (rc < 0) { if (NULL == e->ai_next) @@ -487,7 +495,7 @@ int inet_listen(const char *str, char *ostr, int olen, return sock; } -int inet_connect(const char *str, bool block, Error **errp) +int inet_connect(const char *str, bool block, bool *in_progress, Error **errp) { QemuOpts *opts; int sock = -1; @@ -497,7 +505,7 @@ int inet_connect(const char *str, bool block, Error **errp) if (block) { qemu_opt_set(opts, "block", "on"); } - sock = inet_connect_opts(opts, errp); + sock = inet_connect_opts(opts, in_progress, errp); } else { error_set(errp, QERR_SOCKET_CREATE_FAILED); } diff --git a/qemu_socket.h b/qemu_socket.h index 4689ff340d..30ae6af8b8 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -42,8 +42,8 @@ int send_all(int fd, const void *buf, int len1); int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp); -int inet_connect_opts(QemuOpts *opts, Error **errp); -int inet_connect(const char *str, bool block, Error **errp); +int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp); +int inet_connect(const char *str, bool block, bool *in_progress, Error **errp); int inet_dgram_opts(QemuOpts *opts); const char *inet_strfamily(int family); diff --git a/ui/vnc.c b/ui/vnc.c index 312ad7fe36..385e345c31 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display) if (strncmp(display, "unix:", 5) == 0) vs->lsock = unix_connect(display+5); else - vs->lsock = inet_connect(display, true, NULL); + vs->lsock = inet_connect(display, true, NULL, NULL); if (-1 == vs->lsock) { g_free(vs->display); vs->display = NULL; From 540c79fec9e8b6a6582ec4c65aa2c4c5366e4b89 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 6 Aug 2012 16:26:47 -0300 Subject: [PATCH 15/48] migration: don't rely on any QERR_SOCKET_* Use the in_progress argument for QERR_SOCKET_CONNECT_IN_PROGRESS. The other errors are handled the same by checking if the error is set and then calling migrate_fd_error() if it's. It's also necessary to change inet_connect_opts() not to set QERR_SOCKET_CONNECT_IN_PROGRESS. This error is only used by tcp_start_outgoing_migration() and not changing it along with the usage of in_progress would break migration. Furthermore this commit fixes a bug. Today, there's a spurious error report when migration succeeds: (qemu) migrate tcp:0:4444 migrate: Connection can not be completed immediately (qemu) After this commit no spurious error is reported anymore. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- migration-tcp.c | 24 ++++++++++-------------- qemu-sockets.c | 2 -- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/migration-tcp.c b/migration-tcp.c index 18944a41a3..ac891c38a3 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -82,27 +82,23 @@ static void tcp_wait_for_connect(void *opaque) int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp) { + bool in_progress; + s->get_error = socket_errno; s->write = socket_write; s->close = tcp_close; - s->fd = inet_connect(host_port, false, NULL, errp); - - if (!error_is_set(errp)) { - migrate_fd_connect(s); - } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) { - DPRINTF("connect in progress\n"); - qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); - } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) { - DPRINTF("connect failed\n"); - return -1; - } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) { - DPRINTF("connect failed\n"); + s->fd = inet_connect(host_port, false, &in_progress, errp); + if (error_is_set(errp)) { migrate_fd_error(s); return -1; + } + + if (in_progress) { + DPRINTF("connect in progress\n"); + qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); } else { - DPRINTF("unknown error\n"); - return -1; + migrate_fd_connect(s); } return 0; diff --git a/qemu-sockets.c b/qemu-sockets.c index 9cb47d4232..361d890da3 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -284,8 +284,6 @@ int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) if (in_progress) { *in_progress = true; } - - error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS); } else if (rc < 0) { if (NULL == e->ai_next) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, From 75b81cf0f26f5bb7ada583fc434835adf03f8b77 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 14:26:53 -0300 Subject: [PATCH 16/48] qerror: drop QERR_SOCKET_CONNECT_IN_PROGRESS Unused since last commit. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 4 ---- qerror.h | 3 --- 2 files changed, 7 deletions(-) diff --git a/qerror.c b/qerror.c index 5d3842863f..452ec69188 100644 --- a/qerror.c +++ b/qerror.c @@ -308,10 +308,6 @@ static const QErrorStringTable qerror_table[] = { .error_fmt = QERR_VNC_SERVER_FAILED, .desc = "Could not start VNC server on %(target)", }, - { - .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS, - .desc = "Connection can not be completed immediately", - }, { .error_fmt = QERR_SOCKET_CONNECT_FAILED, .desc = "Failed to connect to socket", diff --git a/qerror.h b/qerror.h index de8497d1eb..52ce58dbc2 100644 --- a/qerror.h +++ b/qerror.h @@ -240,9 +240,6 @@ char *qerror_format(const char *fmt, QDict *error); #define QERR_VNC_SERVER_FAILED \ "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" -#define QERR_SOCKET_CONNECT_IN_PROGRESS \ - "{ 'class': 'SockConnectInprogress', 'data': {} }" - #define QERR_SOCKET_CONNECT_FAILED \ "{ 'class': 'SockConnectFailed', 'data': {} }" From 9aeaddff26d02633b228aceadecf36d28ac18823 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 10:52:18 -0300 Subject: [PATCH 17/48] block: block_int: include qerror.h Several block/ files are relying on qerror.h being provided by qapi-types.h. Fix this, as a future commit will change qapi-types.h not to provide qerror.h. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- block_int.h | 1 + 1 file changed, 1 insertion(+) diff --git a/block_int.h b/block_int.h index 6c1d9cafb1..4452f6f398 100644 --- a/block_int.h +++ b/block_int.h @@ -30,6 +30,7 @@ #include "qemu-coroutine.h" #include "qemu-timer.h" #include "qapi-types.h" +#include "qerror.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 From ff2f990b8212c8822d6a2f66ab4baeb48dae86bd Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 10:55:29 -0300 Subject: [PATCH 18/48] hmp: hmp.h: include qdict.h hmp.h is relying on qdict.h being provided by qapi-types.h. Fix this, as a future commit will change qapi-types.h not to provide qdict.h. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- hmp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hmp.h b/hmp.h index 8d2b0d76da..3275522bdc 100644 --- a/hmp.h +++ b/hmp.h @@ -16,6 +16,7 @@ #include "qemu-common.h" #include "qapi-types.h" +#include "qdict.h" void hmp_info_name(Monitor *mon); void hmp_info_version(Monitor *mon); From b68a8472c17d2d2127afcf1a8dc57884e6584173 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 10:56:33 -0300 Subject: [PATCH 19/48] qapi: qapi-types.h: don't include qapi/qapi-types-core.h qapi-types.h needs only qemu-common.h. Including qapi-types-core.h causes problems when qerror.h or error.h includes qapi-types.h. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- scripts/qapi-types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 4a734f58d5..3ed9f04895 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -253,7 +253,8 @@ fdecl.write(mcgen(''' #ifndef %(guard)s #define %(guard)s -#include "qapi/qapi-types-core.h" +#include "qemu-common.h" + ''', guard=guardname(h_file))) From f01f594b63becfc17cb23b4c15193230d01592e4 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 15:44:25 -0300 Subject: [PATCH 20/48] qapi: generate correct enum names for camel case enums An enum like GenericError in the schema, should generate GENERIC_ERROR and not GENERICERROR. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- scripts/qapi-types.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 3ed9f04895..9b7da96ef2 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -79,6 +79,16 @@ const char *%(name)s_lookup[] = { ''') return ret +def generate_enum_name(name): + if name.isupper(): + return c_fun(name) + new_name = '' + for c in c_fun(name): + if c.isupper(): + new_name += '_' + new_name += c + return new_name.lstrip('_').upper() + def generate_enum(name, values): lookup_decl = mcgen(''' extern const char *%(name)s_lookup[]; @@ -100,7 +110,7 @@ typedef enum %(name)s %(abbrev)s_%(value)s = %(i)d, ''', abbrev=de_camel_case(name).upper(), - value=c_fun(value).upper(), + value=generate_enum_name(value), i=i) i += 1 From ac4ff701d88c4c742b4a53b83eed7ce356535ef8 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 09:38:05 -0300 Subject: [PATCH 21/48] qapi: don't convert enum strings to lowercase Next commit will introduce enum strings in camel case. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- scripts/qapi-types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 9b7da96ef2..cf601ae2d2 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = { ret += mcgen(''' "%(value)s", ''', - value=value.lower()) + value=value) ret += mcgen(''' NULL, From dcafd32348a08490cc378bfc50b260e5229ad738 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 09:34:50 -0300 Subject: [PATCH 22/48] qapi-schema: add ErrorClass enum Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qapi-schema.json | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index a62bf6867b..b513935a39 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2,6 +2,36 @@ # # QAPI Schema +## +# @ErrorClass +# +# QEMU error classes +# +# @GenericError: this is used for errors that don't require a specific error +# class. This should be the default case for most errors +# +# @CommandNotFound: the requested command has not been found +# +# @DeviceEncrypted: the requested operation can't be fulfilled because the +# selected device is encrypted +# +# @DeviceNotActive: a device has failed to be become active +# +# @DeviceNotFound: the requested device has not been found +# +# @KVMMissingCap: the requested operation can't be fulfilled because a +# required KVM capability is missing +# +# @MigrationExpected: the requested operation can't be fulfilled because a +# migration process is expected +# +# Since: 1.2 +## +{ 'enum': 'ErrorClass', + 'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted', + 'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap', + 'MigrationExpected' ] } + ## # @NameInfo: # From 85465051e0e8a79c3c1df3187c2acaacb10d6232 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 13:58:30 -0300 Subject: [PATCH 23/48] qerror: qerror_table: don't use C99 struct initializers This allows for changing QERR_ macros to initialize two struct members at the same time. See next commit for more details. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 276 +++++++++++++++++++++++++++---------------------------- qerror.h | 2 +- 2 files changed, 139 insertions(+), 139 deletions(-) diff --git a/qerror.c b/qerror.c index 452ec69188..ff460b08ce 100644 --- a/qerror.c +++ b/qerror.c @@ -44,285 +44,285 @@ static const QType qerror_type = { */ static const QErrorStringTable qerror_table[] = { { - .error_fmt = QERR_ADD_CLIENT_FAILED, - .desc = "Could not add client", + QERR_ADD_CLIENT_FAILED, + "Could not add client", }, { - .error_fmt = QERR_AMBIGUOUS_PATH, - .desc = "Path '%(path)' does not uniquely identify an object" + QERR_AMBIGUOUS_PATH, + "Path '%(path)' does not uniquely identify an object" }, { - .error_fmt = QERR_BAD_BUS_FOR_DEVICE, - .desc = "Device '%(device)' can't go on a %(bad_bus_type) bus", + QERR_BAD_BUS_FOR_DEVICE, + "Device '%(device)' can't go on a %(bad_bus_type) bus", }, { - .error_fmt = QERR_BASE_NOT_FOUND, - .desc = "Base '%(base)' not found", + QERR_BASE_NOT_FOUND, + "Base '%(base)' not found", }, { - .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, - .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'", + QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'", }, { - .error_fmt = QERR_BUS_NO_HOTPLUG, - .desc = "Bus '%(bus)' does not support hotplugging", + QERR_BUS_NO_HOTPLUG, + "Bus '%(bus)' does not support hotplugging", }, { - .error_fmt = QERR_BUS_NOT_FOUND, - .desc = "Bus '%(bus)' not found", + QERR_BUS_NOT_FOUND, + "Bus '%(bus)' not found", }, { - .error_fmt = QERR_COMMAND_DISABLED, - .desc = "The command %(name) has been disabled for this instance", + QERR_COMMAND_DISABLED, + "The command %(name) has been disabled for this instance", }, { - .error_fmt = QERR_COMMAND_NOT_FOUND, - .desc = "The command %(name) has not been found", + QERR_COMMAND_NOT_FOUND, + "The command %(name) has not been found", }, { - .error_fmt = QERR_DEVICE_ENCRYPTED, - .desc = "'%(device)' (%(filename)) is encrypted", + QERR_DEVICE_ENCRYPTED, + "'%(device)' (%(filename)) is encrypted", }, { - .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, - .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'", + QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, + "Migration is disabled when using feature '%(feature)' in device '%(device)'", }, { - .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM, - .desc = "Device '%(device)' has no medium", + QERR_DEVICE_HAS_NO_MEDIUM, + "Device '%(device)' has no medium", }, { - .error_fmt = QERR_DEVICE_INIT_FAILED, - .desc = "Device '%(device)' could not be initialized", + QERR_DEVICE_INIT_FAILED, + "Device '%(device)' could not be initialized", }, { - .error_fmt = QERR_DEVICE_IN_USE, - .desc = "Device '%(device)' is in use", + QERR_DEVICE_IN_USE, + "Device '%(device)' is in use", }, { - .error_fmt = QERR_DEVICE_IS_READ_ONLY, - .desc = "Device '%(device)' is read only", + QERR_DEVICE_IS_READ_ONLY, + "Device '%(device)' is read only", }, { - .error_fmt = QERR_DEVICE_LOCKED, - .desc = "Device '%(device)' is locked", + QERR_DEVICE_LOCKED, + "Device '%(device)' is locked", }, { - .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES, - .desc = "Device '%(device)' has multiple child busses", + QERR_DEVICE_MULTIPLE_BUSSES, + "Device '%(device)' has multiple child busses", }, { - .error_fmt = QERR_DEVICE_NO_BUS, - .desc = "Device '%(device)' has no child bus", + QERR_DEVICE_NO_BUS, + "Device '%(device)' has no child bus", }, { - .error_fmt = QERR_DEVICE_NO_HOTPLUG, - .desc = "Device '%(device)' does not support hotplugging", + QERR_DEVICE_NO_HOTPLUG, + "Device '%(device)' does not support hotplugging", }, { - .error_fmt = QERR_DEVICE_NOT_ACTIVE, - .desc = "Device '%(device)' has not been activated", + QERR_DEVICE_NOT_ACTIVE, + "Device '%(device)' has not been activated", }, { - .error_fmt = QERR_DEVICE_NOT_ENCRYPTED, - .desc = "Device '%(device)' is not encrypted", + QERR_DEVICE_NOT_ENCRYPTED, + "Device '%(device)' is not encrypted", }, { - .error_fmt = QERR_DEVICE_NOT_FOUND, - .desc = "Device '%(device)' not found", + QERR_DEVICE_NOT_FOUND, + "Device '%(device)' not found", }, { - .error_fmt = QERR_DEVICE_NOT_REMOVABLE, - .desc = "Device '%(device)' is not removable", + QERR_DEVICE_NOT_REMOVABLE, + "Device '%(device)' is not removable", }, { - .error_fmt = QERR_DUPLICATE_ID, - .desc = "Duplicate ID '%(id)' for %(object)", + QERR_DUPLICATE_ID, + "Duplicate ID '%(id)' for %(object)", }, { - .error_fmt = QERR_FD_NOT_FOUND, - .desc = "File descriptor named '%(name)' not found", + QERR_FD_NOT_FOUND, + "File descriptor named '%(name)' not found", }, { - .error_fmt = QERR_FD_NOT_SUPPLIED, - .desc = "No file descriptor supplied via SCM_RIGHTS", + QERR_FD_NOT_SUPPLIED, + "No file descriptor supplied via SCM_RIGHTS", }, { - .error_fmt = QERR_FEATURE_DISABLED, - .desc = "The feature '%(name)' is not enabled", + QERR_FEATURE_DISABLED, + "The feature '%(name)' is not enabled", }, { - .error_fmt = QERR_INVALID_BLOCK_FORMAT, - .desc = "Invalid block format '%(name)'", + QERR_INVALID_BLOCK_FORMAT, + "Invalid block format '%(name)'", }, { - .error_fmt = QERR_INVALID_OPTION_GROUP, - .desc = "There is no option group '%(group)'", + QERR_INVALID_OPTION_GROUP, + "There is no option group '%(group)'", }, { - .error_fmt = QERR_INVALID_PARAMETER, - .desc = "Invalid parameter '%(name)'", + QERR_INVALID_PARAMETER, + "Invalid parameter '%(name)'", }, { - .error_fmt = QERR_INVALID_PARAMETER_COMBINATION, - .desc = "Invalid parameter combination", + QERR_INVALID_PARAMETER_COMBINATION, + "Invalid parameter combination", }, { - .error_fmt = QERR_INVALID_PARAMETER_TYPE, - .desc = "Invalid parameter type for '%(name)', expected: %(expected)", + QERR_INVALID_PARAMETER_TYPE, + "Invalid parameter type for '%(name)', expected: %(expected)", }, { - .error_fmt = QERR_INVALID_PARAMETER_VALUE, - .desc = "Parameter '%(name)' expects %(expected)", + QERR_INVALID_PARAMETER_VALUE, + "Parameter '%(name)' expects %(expected)", }, { - .error_fmt = QERR_INVALID_PASSWORD, - .desc = "Password incorrect", + QERR_INVALID_PASSWORD, + "Password incorrect", }, { - .error_fmt = QERR_IO_ERROR, - .desc = "An IO error has occurred", + QERR_IO_ERROR, + "An IO error has occurred", }, { - .error_fmt = QERR_JSON_PARSE_ERROR, - .desc = "JSON parse error, %(message)", + QERR_JSON_PARSE_ERROR, + "JSON parse error, %(message)", }, { - .error_fmt = QERR_JSON_PARSING, - .desc = "Invalid JSON syntax", + QERR_JSON_PARSING, + "Invalid JSON syntax", }, { - .error_fmt = QERR_KVM_MISSING_CAP, - .desc = "Using KVM without %(capability), %(feature) unavailable", + QERR_KVM_MISSING_CAP, + "Using KVM without %(capability), %(feature) unavailable", }, { - .error_fmt = QERR_MIGRATION_ACTIVE, - .desc = "There's a migration process in progress", + QERR_MIGRATION_ACTIVE, + "There's a migration process in progress", }, { - .error_fmt = QERR_MIGRATION_NOT_SUPPORTED, - .desc = "State blocked by non-migratable device '%(device)'", + QERR_MIGRATION_NOT_SUPPORTED, + "State blocked by non-migratable device '%(device)'", }, { - .error_fmt = QERR_MIGRATION_EXPECTED, - .desc = "An incoming migration is expected before this command can be executed", + QERR_MIGRATION_EXPECTED, + "An incoming migration is expected before this command can be executed", }, { - .error_fmt = QERR_MISSING_PARAMETER, - .desc = "Parameter '%(name)' is missing", + QERR_MISSING_PARAMETER, + "Parameter '%(name)' is missing", }, { - .error_fmt = QERR_NO_BUS_FOR_DEVICE, - .desc = "No '%(bus)' bus found for device '%(device)'", + QERR_NO_BUS_FOR_DEVICE, + "No '%(bus)' bus found for device '%(device)'", }, { - .error_fmt = QERR_NOT_SUPPORTED, - .desc = "Not supported", + QERR_NOT_SUPPORTED, + "Not supported", }, { - .error_fmt = QERR_OPEN_FILE_FAILED, - .desc = "Could not open '%(filename)'", + QERR_OPEN_FILE_FAILED, + "Could not open '%(filename)'", }, { - .error_fmt = QERR_PERMISSION_DENIED, - .desc = "Insufficient permission to perform this operation", + QERR_PERMISSION_DENIED, + "Insufficient permission to perform this operation", }, { - .error_fmt = QERR_PROPERTY_NOT_FOUND, - .desc = "Property '%(device).%(property)' not found", + QERR_PROPERTY_NOT_FOUND, + "Property '%(device).%(property)' not found", }, { - .error_fmt = QERR_PROPERTY_VALUE_BAD, - .desc = "Property '%(device).%(property)' doesn't take value '%(value)'", + QERR_PROPERTY_VALUE_BAD, + "Property '%(device).%(property)' doesn't take value '%(value)'", }, { - .error_fmt = QERR_PROPERTY_VALUE_IN_USE, - .desc = "Property '%(device).%(property)' can't take value '%(value)', it's in use", + QERR_PROPERTY_VALUE_IN_USE, + "Property '%(device).%(property)' can't take value '%(value)', it's in use", }, { - .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND, - .desc = "Property '%(device).%(property)' can't find value '%(value)'", + QERR_PROPERTY_VALUE_NOT_FOUND, + "Property '%(device).%(property)' can't find value '%(value)'", }, { - .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - .desc = "Property '%(device).%(property)' doesn't take " + QERR_PROPERTY_VALUE_NOT_POWER_OF_2, + "Property '%(device).%(property)' doesn't take " "value '%(value)', it's not a power of 2", }, { - .error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE, - .desc = "Property '%(device).%(property)' doesn't take " + QERR_PROPERTY_VALUE_OUT_OF_RANGE, + "Property '%(device).%(property)' doesn't take " "value %(value) (minimum: %(min), maximum: %(max))", }, { - .error_fmt = QERR_QGA_COMMAND_FAILED, - .desc = "Guest agent command failed, error was '%(message)'", + QERR_QGA_COMMAND_FAILED, + "Guest agent command failed, error was '%(message)'", }, { - .error_fmt = QERR_QGA_LOGGING_FAILED, - .desc = "Guest agent failed to log non-optional log statement", + QERR_QGA_LOGGING_FAILED, + "Guest agent failed to log non-optional log statement", }, { - .error_fmt = QERR_QMP_BAD_INPUT_OBJECT, - .desc = "Expected '%(expected)' in QMP input", + QERR_QMP_BAD_INPUT_OBJECT, + "Expected '%(expected)' in QMP input", }, { - .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER, - .desc = "QMP input object member '%(member)' expects '%(expected)'", + QERR_QMP_BAD_INPUT_OBJECT_MEMBER, + "QMP input object member '%(member)' expects '%(expected)'", }, { - .error_fmt = QERR_QMP_EXTRA_MEMBER, - .desc = "QMP input object member '%(member)' is unexpected", + QERR_QMP_EXTRA_MEMBER, + "QMP input object member '%(member)' is unexpected", }, { - .error_fmt = QERR_RESET_REQUIRED, - .desc = "Resetting the Virtual Machine is required", + QERR_RESET_REQUIRED, + "Resetting the Virtual Machine is required", }, { - .error_fmt = QERR_SET_PASSWD_FAILED, - .desc = "Could not set password", + QERR_SET_PASSWD_FAILED, + "Could not set password", }, { - .error_fmt = QERR_TOO_MANY_FILES, - .desc = "Too many open files", + QERR_TOO_MANY_FILES, + "Too many open files", }, { - .error_fmt = QERR_UNDEFINED_ERROR, - .desc = "An undefined error has occurred", + QERR_UNDEFINED_ERROR, + "An undefined error has occurred", }, { - .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - .desc = "'%(device)' uses a %(format) feature which is not " + QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, + "'%(device)' uses a %(format) feature which is not " "supported by this qemu version: %(feature)", }, { - .error_fmt = QERR_UNSUPPORTED, - .desc = "this feature or command is not currently supported", + QERR_UNSUPPORTED, + "this feature or command is not currently supported", }, { - .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, - .desc = "Migration is disabled when VirtFS export path '%(path)' " + QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, + "Migration is disabled when VirtFS export path '%(path)' " "is mounted in the guest using mount_tag '%(tag)'", }, { - .error_fmt = QERR_VNC_SERVER_FAILED, - .desc = "Could not start VNC server on %(target)", + QERR_VNC_SERVER_FAILED, + "Could not start VNC server on %(target)", }, { - .error_fmt = QERR_SOCKET_CONNECT_FAILED, - .desc = "Failed to connect to socket", + QERR_SOCKET_CONNECT_FAILED, + "Failed to connect to socket", }, { - .error_fmt = QERR_SOCKET_LISTEN_FAILED, - .desc = "Failed to set socket to listening mode", + QERR_SOCKET_LISTEN_FAILED, + "Failed to set socket to listening mode", }, { - .error_fmt = QERR_SOCKET_BIND_FAILED, - .desc = "Failed to bind socket", + QERR_SOCKET_BIND_FAILED, + "Failed to bind socket", }, { - .error_fmt = QERR_SOCKET_CREATE_FAILED, - .desc = "Failed to create socket", + QERR_SOCKET_CREATE_FAILED, + "Failed to create socket", }, {} }; diff --git a/qerror.h b/qerror.h index 52ce58dbc2..2e6a49d3f3 100644 --- a/qerror.h +++ b/qerror.h @@ -19,8 +19,8 @@ #include typedef struct QErrorStringTable { - const char *desc; const char *error_fmt; + const char *desc; } QErrorStringTable; typedef struct QError { From 13f59ae8157e8ec238fa8aefe5309909a1eeb7e2 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 14:09:29 -0300 Subject: [PATCH 24/48] error, qerror: add ErrorClass argument to error functions The new argument is added to functions qerror_report() and error_set(). It's stored in Error and QError. qerror_report_err() is also updated to take care of it. The QERR_ macros are changed to contain a place holder value for the new argument, so that the value is used on all current calls to qerror_report() and error_set() (and also to initialize qerror_table[]). Next commit will update the QERR_ macros with a proper ErrorClass value. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 8 ++- error.h | 5 +- qerror.c | 10 ++-- qerror.h | 145 ++++++++++++++++++++++++++++--------------------------- 4 files changed, 90 insertions(+), 78 deletions(-) diff --git a/error.c b/error.c index 2ade99b080..648706aa67 100644 --- a/error.c +++ b/error.c @@ -14,6 +14,7 @@ #include "error.h" #include "qjson.h" #include "qdict.h" +#include "qapi-types.h" #include "error_int.h" #include "qerror.h" @@ -21,9 +22,10 @@ struct Error { QDict *obj; char *msg; + ErrorClass err_class; }; -void error_set(Error **errp, const char *fmt, ...) +void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) { Error *err; va_list ap; @@ -39,6 +41,7 @@ void error_set(Error **errp, const char *fmt, ...) err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap)); va_end(ap); err->msg = qerror_format(fmt, err->obj); + err->err_class = err_class; *errp = err; } @@ -49,6 +52,7 @@ Error *error_copy(const Error *err) err_new = g_malloc0(sizeof(*err)); err_new->msg = g_strdup(err->msg); + err_new->err_class = err->err_class; err_new->obj = err->obj; QINCREF(err_new->obj); @@ -97,7 +101,7 @@ void error_free(Error *err) } } -bool error_is_type(Error *err, const char *fmt) +bool error_is_type(Error *err, ErrorClass err_class, const char *fmt) { const char *error_class; char *ptr; diff --git a/error.h b/error.h index 3d9d96def0..9678752152 100644 --- a/error.h +++ b/error.h @@ -13,6 +13,7 @@ #define ERROR_H #include "compiler.h" +#include "qapi-types.h" #include /** @@ -26,7 +27,7 @@ typedef struct Error Error; * Currently, qerror.h defines these error formats. This function is not * meant to be used outside of QEMU. */ -void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4); /** * Returns true if an indirect pointer to an error is pointing to a valid @@ -70,6 +71,6 @@ void error_free(Error *err); * Determine if an error is of a speific type (based on the qerror format). * Non-QEMU users should get the `class' field to identify the error type. */ -bool error_is_type(Error *err, const char *fmt); +bool error_is_type(Error *err, ErrorClass err_class, const char *fmt); #endif diff --git a/qerror.c b/qerror.c index ff460b08ce..0bf8aec947 100644 --- a/qerror.c +++ b/qerror.c @@ -386,13 +386,15 @@ static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va) * * Return strong reference. */ -static QError *qerror_from_info(const char *fmt, va_list *va) +static QError *qerror_from_info(ErrorClass err_class, const char *fmt, + va_list *va) { QError *qerr; qerr = qerror_new(); loc_save(&qerr->loc); + qerr->err_class = err_class; qerr->error = error_obj_from_fmt_no_fail(fmt, va); qerr->err_msg = qerror_format(fmt, qerr->error); @@ -518,13 +520,13 @@ static void qerror_print(QError *qerror) QDECREF(qstring); } -void qerror_report(const char *fmt, ...) +void qerror_report(ErrorClass eclass, const char *fmt, ...) { va_list va; QError *qerror; va_start(va, fmt); - qerror = qerror_from_info(fmt, &va); + qerror = qerror_from_info(eclass, fmt, &va); va_end(va); if (monitor_cur_is_qmp()) { @@ -540,6 +542,7 @@ struct Error { QDict *obj; char *msg; + ErrorClass err_class; }; void qerror_report_err(Error *err) @@ -551,6 +554,7 @@ void qerror_report_err(Error *err) QINCREF(err->obj); qerr->error = err->obj; qerr->err_msg = g_strdup(err->msg); + qerr->err_class = err->err_class; if (monitor_cur_is_qmp()) { monitor_set_error(cur_mon, qerr); diff --git a/qerror.h b/qerror.h index 2e6a49d3f3..bcc93f814f 100644 --- a/qerror.h +++ b/qerror.h @@ -16,9 +16,11 @@ #include "qstring.h" #include "qemu-error.h" #include "error.h" +#include "qapi-types.h" #include typedef struct QErrorStringTable { + ErrorClass err_class; const char *error_fmt; const char *desc; } QErrorStringTable; @@ -28,10 +30,11 @@ typedef struct QError { QDict *error; Location loc; char *err_msg; + ErrorClass err_class; } QError; QString *qerror_human(const QError *qerror); -void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2); +void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void qerror_report_err(Error *err); void assert_no_error(Error *err); char *qerror_format(const char *fmt, QDict *error); @@ -42,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error); * Use scripts/check-qerror.sh to check. */ #define QERR_ADD_CLIENT_FAILED \ - "{ 'class': 'AddClientFailed', 'data': {} }" + -1, "{ 'class': 'AddClientFailed', 'data': {} }" #define QERR_AMBIGUOUS_PATH \ - "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" + -1, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" #define QERR_BAD_BUS_FOR_DEVICE \ - "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" + -1, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" #define QERR_BASE_NOT_FOUND \ - "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }" + -1, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }" #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \ - "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" + -1, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" #define QERR_BUFFER_OVERRUN \ - "{ 'class': 'BufferOverrun', 'data': {} }" + -1, "{ 'class': 'BufferOverrun', 'data': {} }" #define QERR_BUS_NO_HOTPLUG \ - "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" + -1, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" #define QERR_BUS_NOT_FOUND \ - "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" + -1, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" #define QERR_COMMAND_DISABLED \ - "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" + -1, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" #define QERR_COMMAND_NOT_FOUND \ - "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" + -1, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" #define QERR_DEVICE_ENCRYPTED \ - "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" + -1, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \ - "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" + -1, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" #define QERR_DEVICE_HAS_NO_MEDIUM \ - "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }" #define QERR_DEVICE_INIT_FAILED \ - "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" #define QERR_DEVICE_IN_USE \ - "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" #define QERR_DEVICE_IS_READ_ONLY \ - "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" #define QERR_DEVICE_LOCKED \ - "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" #define QERR_DEVICE_MULTIPLE_BUSSES \ - "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" #define QERR_DEVICE_NO_BUS \ - "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" #define QERR_DEVICE_NO_HOTPLUG \ - "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_ACTIVE \ - "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_ENCRYPTED \ - "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_FOUND \ - "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_REMOVABLE \ - "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" + -1, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" #define QERR_DUPLICATE_ID \ - "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" + -1, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" #define QERR_FD_NOT_FOUND \ - "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" + -1, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" #define QERR_FD_NOT_SUPPLIED \ - "{ 'class': 'FdNotSupplied', 'data': {} }" + -1, "{ 'class': 'FdNotSupplied', 'data': {} }" #define QERR_FEATURE_DISABLED \ - "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }" + -1, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }" #define QERR_INVALID_BLOCK_FORMAT \ - "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" + -1, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" #define QERR_INVALID_OPTION_GROUP \ - "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" + -1, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" #define QERR_INVALID_PARAMETER \ - "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" + -1, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" #define QERR_INVALID_PARAMETER_COMBINATION \ - "{ 'class': 'InvalidParameterCombination', 'data': {} }" + -1, "{ 'class': 'InvalidParameterCombination', 'data': {} }" #define QERR_INVALID_PARAMETER_TYPE \ - "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + -1, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" #define QERR_INVALID_PARAMETER_VALUE \ - "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }" + -1, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }" #define QERR_INVALID_PASSWORD \ - "{ 'class': 'InvalidPassword', 'data': {} }" + -1, "{ 'class': 'InvalidPassword', 'data': {} }" #define QERR_IO_ERROR \ - "{ 'class': 'IOError', 'data': {} }" + -1, "{ 'class': 'IOError', 'data': {} }" #define QERR_JSON_PARSE_ERROR \ - "{ 'class': 'JSONParseError', 'data': { 'message': %s } }" + -1, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }" #define QERR_JSON_PARSING \ - "{ 'class': 'JSONParsing', 'data': {} }" + -1, "{ 'class': 'JSONParsing', 'data': {} }" #define QERR_KVM_MISSING_CAP \ - "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" + -1, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" #define QERR_MIGRATION_ACTIVE \ - "{ 'class': 'MigrationActive', 'data': {} }" + -1, "{ 'class': 'MigrationActive', 'data': {} }" #define QERR_MIGRATION_NOT_SUPPORTED \ - "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }" + -1, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }" #define QERR_MIGRATION_EXPECTED \ - "{ 'class': 'MigrationExpected', 'data': {} }" + -1, "{ 'class': 'MigrationExpected', 'data': {} }" #define QERR_MISSING_PARAMETER \ - "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" + -1, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" #define QERR_NO_BUS_FOR_DEVICE \ - "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" + -1, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" #define QERR_NOT_SUPPORTED \ - "{ 'class': 'NotSupported', 'data': {} }" + -1, "{ 'class': 'NotSupported', 'data': {} }" #define QERR_OPEN_FILE_FAILED \ - "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" + -1, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" #define QERR_PERMISSION_DENIED \ - "{ 'class': 'PermissionDenied', 'data': {} }" + -1, "{ 'class': 'PermissionDenied', 'data': {} }" #define QERR_PROPERTY_NOT_FOUND \ - "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" + -1, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" #define QERR_PROPERTY_VALUE_BAD \ - "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + -1, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_IN_USE \ - "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + -1, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_NOT_FOUND \ - "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + -1, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \ - "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \ + -1, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \ "'device': %s, 'property': %s, 'value': %"PRId64" } }" #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \ - "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" + -1, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" #define QERR_QGA_COMMAND_FAILED \ - "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" + -1, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" #define QERR_QGA_LOGGING_FAILED \ - "{ 'class': 'QgaLoggingFailed', 'data': {} }" + -1, "{ 'class': 'QgaLoggingFailed', 'data': {} }" #define QERR_QMP_BAD_INPUT_OBJECT \ - "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" + -1, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \ - "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }" + -1, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }" #define QERR_QMP_EXTRA_MEMBER \ - "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" + -1, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" #define QERR_RESET_REQUIRED \ - "{ 'class': 'ResetRequired', 'data': {} }" + -1, "{ 'class': 'ResetRequired', 'data': {} }" #define QERR_SET_PASSWD_FAILED \ - "{ 'class': 'SetPasswdFailed', 'data': {} }" + -1, "{ 'class': 'SetPasswdFailed', 'data': {} }" #define QERR_TOO_MANY_FILES \ - "{ 'class': 'TooManyFiles', 'data': {} }" + -1, "{ 'class': 'TooManyFiles', 'data': {} }" #define QERR_UNDEFINED_ERROR \ - "{ 'class': 'UndefinedError', 'data': {} }" + -1, "{ 'class': 'UndefinedError', 'data': {} }" #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ - "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" + -1, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" #define QERR_UNSUPPORTED \ - "{ 'class': 'Unsupported', 'data': {} }" + -1, "{ 'class': 'Unsupported', 'data': {} }" #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \ - "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" + -1, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" #define QERR_VNC_SERVER_FAILED \ - "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" + -1, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" #define QERR_SOCKET_CONNECT_FAILED \ - "{ 'class': 'SockConnectFailed', 'data': {} }" + -1, "{ 'class': 'SockConnectFailed', 'data': {} }" #define QERR_SOCKET_LISTEN_FAILED \ - "{ 'class': 'SockListenFailed', 'data': {} }" + -1, "{ 'class': 'SockListenFailed', 'data': {} }" #define QERR_SOCKET_BIND_FAILED \ - "{ 'class': 'SockBindFailed', 'data': {} }" + -1, "{ 'class': 'SockBindFailed', 'data': {} }" #define QERR_SOCKET_CREATE_FAILED \ - "{ 'class': 'SockCreateFailed', 'data': {} }" + -1, "{ 'class': 'SockCreateFailed', 'data': {} }" #endif /* QERROR_H */ From 0f32cf6abcea8006fbf1f9c9bc8bc5bedcf6e431 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 15:50:19 -0300 Subject: [PATCH 25/48] qerror: add proper ErrorClass value for QERR_ macros This commit replaces the place holder value for the ErrorClass argument with a proper ErrorClass value for all QERR_ macros. All current errors are mapped to GenericError, except for errors CommandNotFound, DeviceEncrypted, DeviceNotActive, DeviceNotFound, KVMMissingCap and MigrationExpected, which are maintained as they are today. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.h | 140 +++++++++++++++++++++++++++---------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/qerror.h b/qerror.h index bcc93f814f..4f92218d85 100644 --- a/qerror.h +++ b/qerror.h @@ -45,214 +45,214 @@ char *qerror_format(const char *fmt, QDict *error); * Use scripts/check-qerror.sh to check. */ #define QERR_ADD_CLIENT_FAILED \ - -1, "{ 'class': 'AddClientFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AddClientFailed', 'data': {} }" #define QERR_AMBIGUOUS_PATH \ - -1, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" #define QERR_BAD_BUS_FOR_DEVICE \ - -1, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" #define QERR_BASE_NOT_FOUND \ - -1, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }" #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \ - -1, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" #define QERR_BUFFER_OVERRUN \ - -1, "{ 'class': 'BufferOverrun', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BufferOverrun', 'data': {} }" #define QERR_BUS_NO_HOTPLUG \ - -1, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" #define QERR_BUS_NOT_FOUND \ - -1, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" #define QERR_COMMAND_DISABLED \ - -1, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" #define QERR_COMMAND_NOT_FOUND \ - -1, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" + ERROR_CLASS_COMMAND_NOT_FOUND, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" #define QERR_DEVICE_ENCRYPTED \ - -1, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" + ERROR_CLASS_DEVICE_ENCRYPTED, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \ - -1, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" #define QERR_DEVICE_HAS_NO_MEDIUM \ - -1, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }" #define QERR_DEVICE_INIT_FAILED \ - -1, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" #define QERR_DEVICE_IN_USE \ - -1, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" #define QERR_DEVICE_IS_READ_ONLY \ - -1, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" #define QERR_DEVICE_LOCKED \ - -1, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" #define QERR_DEVICE_MULTIPLE_BUSSES \ - -1, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" #define QERR_DEVICE_NO_BUS \ - -1, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" #define QERR_DEVICE_NO_HOTPLUG \ - -1, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_ACTIVE \ - -1, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + ERROR_CLASS_DEVICE_NOT_ACTIVE, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_ENCRYPTED \ - -1, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_FOUND \ - -1, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" + ERROR_CLASS_DEVICE_NOT_FOUND, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" #define QERR_DEVICE_NOT_REMOVABLE \ - -1, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" #define QERR_DUPLICATE_ID \ - -1, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" #define QERR_FD_NOT_FOUND \ - -1, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" #define QERR_FD_NOT_SUPPLIED \ - -1, "{ 'class': 'FdNotSupplied', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotSupplied', 'data': {} }" #define QERR_FEATURE_DISABLED \ - -1, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }" #define QERR_INVALID_BLOCK_FORMAT \ - -1, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" #define QERR_INVALID_OPTION_GROUP \ - -1, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" #define QERR_INVALID_PARAMETER \ - -1, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" #define QERR_INVALID_PARAMETER_COMBINATION \ - -1, "{ 'class': 'InvalidParameterCombination', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterCombination', 'data': {} }" #define QERR_INVALID_PARAMETER_TYPE \ - -1, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" #define QERR_INVALID_PARAMETER_VALUE \ - -1, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }" #define QERR_INVALID_PASSWORD \ - -1, "{ 'class': 'InvalidPassword', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidPassword', 'data': {} }" #define QERR_IO_ERROR \ - -1, "{ 'class': 'IOError', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'IOError', 'data': {} }" #define QERR_JSON_PARSE_ERROR \ - -1, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }" #define QERR_JSON_PARSING \ - -1, "{ 'class': 'JSONParsing', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParsing', 'data': {} }" #define QERR_KVM_MISSING_CAP \ - -1, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" + ERROR_CLASS_K_V_M_MISSING_CAP, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" #define QERR_MIGRATION_ACTIVE \ - -1, "{ 'class': 'MigrationActive', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationActive', 'data': {} }" #define QERR_MIGRATION_NOT_SUPPORTED \ - -1, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }" #define QERR_MIGRATION_EXPECTED \ - -1, "{ 'class': 'MigrationExpected', 'data': {} }" + ERROR_CLASS_MIGRATION_EXPECTED, "{ 'class': 'MigrationExpected', 'data': {} }" #define QERR_MISSING_PARAMETER \ - -1, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" #define QERR_NO_BUS_FOR_DEVICE \ - -1, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" #define QERR_NOT_SUPPORTED \ - -1, "{ 'class': 'NotSupported', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NotSupported', 'data': {} }" #define QERR_OPEN_FILE_FAILED \ - -1, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" #define QERR_PERMISSION_DENIED \ - -1, "{ 'class': 'PermissionDenied', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PermissionDenied', 'data': {} }" #define QERR_PROPERTY_NOT_FOUND \ - -1, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" #define QERR_PROPERTY_VALUE_BAD \ - -1, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_IN_USE \ - -1, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_NOT_FOUND \ - -1, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \ - -1, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \ + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \ "'device': %s, 'property': %s, 'value': %"PRId64" } }" #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \ - -1, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" #define QERR_QGA_COMMAND_FAILED \ - -1, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" #define QERR_QGA_LOGGING_FAILED \ - -1, "{ 'class': 'QgaLoggingFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaLoggingFailed', 'data': {} }" #define QERR_QMP_BAD_INPUT_OBJECT \ - -1, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \ - -1, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }" #define QERR_QMP_EXTRA_MEMBER \ - -1, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" #define QERR_RESET_REQUIRED \ - -1, "{ 'class': 'ResetRequired', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'ResetRequired', 'data': {} }" #define QERR_SET_PASSWD_FAILED \ - -1, "{ 'class': 'SetPasswdFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SetPasswdFailed', 'data': {} }" #define QERR_TOO_MANY_FILES \ - -1, "{ 'class': 'TooManyFiles', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'TooManyFiles', 'data': {} }" #define QERR_UNDEFINED_ERROR \ - -1, "{ 'class': 'UndefinedError', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UndefinedError', 'data': {} }" #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ - -1, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" #define QERR_UNSUPPORTED \ - -1, "{ 'class': 'Unsupported', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'Unsupported', 'data': {} }" #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \ - -1, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" #define QERR_VNC_SERVER_FAILED \ - -1, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" #define QERR_SOCKET_CONNECT_FAILED \ - -1, "{ 'class': 'SockConnectFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockConnectFailed', 'data': {} }" #define QERR_SOCKET_LISTEN_FAILED \ - -1, "{ 'class': 'SockListenFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockListenFailed', 'data': {} }" #define QERR_SOCKET_BIND_FAILED \ - -1, "{ 'class': 'SockBindFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockBindFailed', 'data': {} }" #define QERR_SOCKET_CREATE_FAILED \ - -1, "{ 'class': 'SockCreateFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockCreateFailed', 'data': {} }" #endif /* QERROR_H */ From ea25fbca88b223877c45c776b6c0e17e0247439f Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 16:29:38 -0300 Subject: [PATCH 26/48] error: add error_get_class() Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 5 +++++ error.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/error.c b/error.c index 648706aa67..2d34cde654 100644 --- a/error.c +++ b/error.c @@ -64,6 +64,11 @@ bool error_is_set(Error **errp) return (errp && *errp); } +ErrorClass error_get_class(const Error *err) +{ + return err->err_class; +} + const char *error_get_pretty(Error *err) { return err->msg; diff --git a/error.h b/error.h index 9678752152..114e24b34b 100644 --- a/error.h +++ b/error.h @@ -35,6 +35,11 @@ void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ */ bool error_is_set(Error **err); +/* + * Get the error class of an error object. + */ +ErrorClass error_get_class(const Error *err); + /** * Returns an exact copy of the error passed as an argument. */ From ab878ddfeee722db8e7f78a9c6e9882864c2fd66 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 6 Aug 2012 15:55:22 -0300 Subject: [PATCH 27/48] hmp: hmp_change(): use error_get_class() The error_is_type() function is going to be dropped. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- hmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hmp.c b/hmp.c index 54c37d7254..9b44dfcf3a 100644 --- a/hmp.c +++ b/hmp.c @@ -793,7 +793,8 @@ void hmp_change(Monitor *mon, const QDict *qdict) } qmp_change(device, target, !!arg, arg, &err); - if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) { + if (error_is_set(&err) && + error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) { error_free(err); monitor_read_block_device_key(mon, device, NULL, NULL); return; From a8cb2d302ea20d7ba1be184973fef29d7cab9407 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 26 Jul 2012 21:30:40 -0300 Subject: [PATCH 28/48] error: drop unused functions Besides being unused, they operate on the current error format, which is going to be replaced soon. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 48 ------------------------------------------------ error.h | 16 ---------------- error_int.h | 1 - 3 files changed, 65 deletions(-) diff --git a/error.c b/error.c index 2d34cde654..b1d5131470 100644 --- a/error.c +++ b/error.c @@ -74,29 +74,6 @@ const char *error_get_pretty(Error *err) return err->msg; } -const char *error_get_field(Error *err, const char *field) -{ - if (strcmp(field, "class") == 0) { - return qdict_get_str(err->obj, field); - } else { - QDict *dict = qdict_get_qdict(err->obj, "data"); - return qdict_get_str(dict, field); - } -} - -QDict *error_get_data(Error *err) -{ - QDict *data = qdict_get_qdict(err->obj, "data"); - QINCREF(data); - return data; -} - -void error_set_field(Error *err, const char *field, const char *value) -{ - QDict *dict = qdict_get_qdict(err->obj, "data"); - qdict_put(dict, field, qstring_from_str(value)); -} - void error_free(Error *err) { if (err) { @@ -106,31 +83,6 @@ void error_free(Error *err) } } -bool error_is_type(Error *err, ErrorClass err_class, const char *fmt) -{ - const char *error_class; - char *ptr; - char *end; - - if (!err) { - return false; - } - - ptr = strstr(fmt, "'class': '"); - assert(ptr != NULL); - ptr += strlen("'class': '"); - - end = strchr(ptr, '\''); - assert(end != NULL); - - error_class = error_get_field(err, "class"); - if (strlen(error_class) != end - ptr) { - return false; - } - - return strncmp(ptr, error_class, end - ptr) == 0; -} - void error_propagate(Error **dst_err, Error *local_err) { if (dst_err && !*dst_err) { diff --git a/error.h b/error.h index 114e24b34b..5336fc58b2 100644 --- a/error.h +++ b/error.h @@ -50,16 +50,6 @@ Error *error_copy(const Error *err); */ const char *error_get_pretty(Error *err); -/** - * Get an individual named error field. - */ -const char *error_get_field(Error *err, const char *field); - -/** - * Get an individual named error field. - */ -void error_set_field(Error *err, const char *field, const char *value); - /** * Propagate an error to an indirect pointer to an error. This function will * always transfer ownership of the error reference and handles the case where @@ -72,10 +62,4 @@ void error_propagate(Error **dst_err, Error *local_err); */ void error_free(Error *err); -/** - * Determine if an error is of a speific type (based on the qerror format). - * Non-QEMU users should get the `class' field to identify the error type. - */ -bool error_is_type(Error *err, ErrorClass err_class, const char *fmt); - #endif diff --git a/error_int.h b/error_int.h index 5e3942405a..4b00d0836e 100644 --- a/error_int.h +++ b/error_int.h @@ -22,7 +22,6 @@ * * These are used to convert QErrors to Errors */ -QDict *error_get_data(Error *err); QObject *error_get_qobject(Error *err); void error_set_qobject(Error **errp, QObject *obj); From de253f14912e88f45dbe66984440d27221a75a60 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 16:18:16 -0300 Subject: [PATCH 29/48] qmp: switch to the new error format on the wire IMPORTANT: this BREAKS QMP's compatibility for the error response. This commit changes QMP's wire protocol to make use of the simpler error format introduced by previous commits. There are two important (and mostly incompatible) changes: 1. Almost all error classes have been replaced by GenericError. The only classes that are still supported for compatibility with libvirt are: CommandNotFound, DeviceNotActive, KVMMissingCap, DeviceNotFound and MigrationExpected 2. The 'data' field of the error dictionary is gone As an example, an error response like: { "error": { "class": "DeviceNotRemovable", "data": { "device": "virtio0" }, "desc": "Device 'virtio0' is not removable" } } Will now be emitted as: { "error": { "class": "GenericError", "desc": "Device 'virtio0' is not removable" } } Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- QMP/qmp-spec.txt | 10 +++------ monitor.c | 18 +++++++++++----- qapi-schema.json | 55 ------------------------------------------------ qmp-commands.hx | 4 ++-- 4 files changed, 18 insertions(+), 69 deletions(-) diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt index 1ba916c9f2..a27789692b 100644 --- a/QMP/qmp-spec.txt +++ b/QMP/qmp-spec.txt @@ -106,14 +106,11 @@ completed because of an error condition. The format is: -{ "error": { "class": json-string, "data": json-object, "desc": json-string }, - "id": json-value } +{ "error": { "class": json-string, "desc": json-string }, "id": json-value } Where, -- The "class" member contains the error class name (eg. "ServiceUnavailable") -- The "data" member contains specific error data and is defined in a - per-command basis, it will be an empty json-object if the error has no data +- The "class" member contains the error class name (eg. "GenericError") - The "desc" member is a human-readable error message. Clients should not attempt to parse this message. - The "id" member contains the transaction identification associated with @@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"} ------------------ C: { "execute": } -S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data": -{}}} +S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } } 3.5 Powerdown event ------------------- diff --git a/monitor.c b/monitor.c index aa5716782a..369459069f 100644 --- a/monitor.c +++ b/monitor.c @@ -353,16 +353,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) QDECREF(json); } +static QDict *build_qmp_error_dict(const QError *err) +{ + QObject *obj; + + obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }", + ErrorClass_lookup[err->err_class], + qerror_human(err)); + + return qobject_to_qdict(obj); +} + static void monitor_protocol_emitter(Monitor *mon, QObject *data) { QDict *qmp; trace_monitor_protocol_emitter(mon); - qmp = qdict_new(); - if (!monitor_has_error(mon)) { /* success response */ + qmp = qdict_new(); if (data) { qobject_incref(data); qdict_put_obj(qmp, "return", data); @@ -372,9 +382,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data) } } else { /* error response */ - qdict_put(mon->error->error, "desc", qerror_human(mon->error)); - qdict_put(qmp, "error", mon->error->error); - QINCREF(mon->error->error); + qmp = build_qmp_error_dict(mon->error); QDECREF(mon->error); mon->error = NULL; } diff --git a/qapi-schema.json b/qapi-schema.json index b513935a39..ec8d91908c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -658,7 +658,6 @@ # Returns information about the current VNC server # # Returns: @VncInfo -# If VNC support is not compiled in, FeatureDisabled # # Since: 0.14.0 ## @@ -1042,9 +1041,6 @@ # virtual address (defaults to CPU 0) # # Returns: Nothing on success -# If @cpu is not a valid VCPU, InvalidParameterValue -# If @filename cannot be opened, OpenFileFailed -# If an I/O error occurs while writing the file, IOError # # Since: 0.14.0 # @@ -1065,8 +1061,6 @@ # @filename: the file to save the memory to as binary data # # Returns: Nothing on success -# If @filename cannot be opened, OpenFileFailed -# If an I/O error occurs while writing the file, IOError # # Since: 0.14.0 # @@ -1108,7 +1102,6 @@ # Injects an Non-Maskable Interrupt into all guest's VCPUs. # # Returns: If successful, nothing -# If the Virtual Machine doesn't support NMI injection, Unsupported # # Since: 0.14.0 # @@ -1159,7 +1152,6 @@ # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound # If @device is not encrypted, DeviceNotEncrypted -# If @password is not valid for this device, InvalidPassword # # Notes: Not all block formats support encryption and some that do are not # able to validate that a password is correct. Disk corruption may @@ -1200,11 +1192,6 @@ # # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound -# If @size is negative, InvalidParameterValue -# If the block device has no medium inserted, DeviceHasNoMedium -# If the block device does not support resize, Unsupported -# If the block device is read-only, DeviceIsReadOnly -# If a long-running operation is using the device, DeviceInUse # # Since: 0.14.0 ## @@ -1266,10 +1253,6 @@ # # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound -# If @device is busy, DeviceInUse will be returned -# If @snapshot-file can't be created, OpenFileFailed -# If @snapshot-file can't be opened, OpenFileFailed -# If @format is invalid, InvalidBlockFormat # # Note: The transaction aborts on the first failure. Therefore, there will # be only one device or snapshot file returned in an error condition, and @@ -1298,8 +1281,6 @@ # # Returns: nothing on success # If @device is not a valid block device, DeviceNotFound -# If @snapshot-file can't be opened, OpenFileFailed -# If @format is invalid, InvalidBlockFormat # # Since 0.14.0 ## @@ -1501,11 +1482,6 @@ # # Returns: Nothing on success # If Spice is not enabled, DeviceNotFound -# If @protocol does not support connected, InvalidParameter -# If @protocol is invalid, InvalidParameter -# If any other error occurs, SetPasswdFailed -# -# Notes: If VNC is not enabled, SetPasswdFailed is returned. # # Since: 0.14.0 ## @@ -1527,8 +1503,6 @@ # # Returns: Nothing on success # If @protocol is `spice' and Spice is not active, DeviceNotFound -# If an error occurs setting password expiration, SetPasswdFailed -# If @protocol is not `spice' or 'vnc', InvalidParameter # # Since: 0.14.0 # @@ -1551,8 +1525,6 @@ # # Returns: Nothing on success # If @device is not a valid block device, DeviceNotFound -# If @device is not removable and @force is false, DeviceNotRemovable -# If @force is false and @device is locked, DeviceLocked # # Notes: Ejecting a device will no media results in success # @@ -1595,7 +1567,6 @@ # # Returns: Nothing on success. # If @device is not a valid block device, DeviceNotFound -# If @format is not a valid block format, InvalidBlockFormat # If the new block device is encrypted, DeviceEncrypted. Note that # if this error is returned, the device has been opened successfully # and an additional call to @block_passwd is required to set the @@ -1631,7 +1602,6 @@ # # Returns: Nothing on success # If @device is not a valid block device, DeviceNotFound -# If the argument combination is invalid, InvalidParameterCombination # # Since: 1.1 ## @@ -1665,11 +1635,7 @@ # @speed: #optional the maximum speed, in bytes per second # # Returns: Nothing on success -# If streaming is already active on this device, DeviceInUse # If @device does not exist, DeviceNotFound -# If image streaming is not supported by this device, NotSupported -# If @base does not exist, BaseNotFound -# If @speed is invalid, InvalidParameter # # Since: 1.1 ## @@ -1691,8 +1657,6 @@ # Defaults to 0. # # Returns: Nothing on success -# If the job type does not support throttling, NotSupported -# If the speed value is invalid, InvalidParameter # If no background operation is active on this device, DeviceNotActive # # Since: 1.1 @@ -1722,7 +1686,6 @@ # # Returns: Nothing on success # If no background operation is active on this device, DeviceNotActive -# If cancellation already in progress, DeviceInUse # # Since: 1.1 ## @@ -1792,8 +1755,6 @@ # format. # # Returns: Nothing on success -# If @filename cannot be opened, OpenFileFailed -# If an I/O error occurs while writing the file, IOError # # Since: 1.1 ## @@ -1808,7 +1769,6 @@ # # Returns: Nothing on success # If @id is not a valid device, DeviceNotFound -# If the device does not support unplug, BusNoHotplug # # Notes: When this command completes, the device may not be removed from the # guest. Hot removal is an operation that requires guest cooperation. @@ -1849,14 +1809,6 @@ # want to dump all guest's memory, please specify the start @begin and @length # # Returns: nothing on success -# If @begin contains an invalid address, InvalidParameter -# If only one of @begin and @length is specified, MissingParameter -# If @protocol stats with "fd:", and the fd cannot be found, FdNotFound -# If @protocol starts with "file:", and the file cannot be -# opened, OpenFileFailed -# If @protocol does not start with "fd:" or "file:", InvalidParameter -# If an I/O error occurs while writing the file, IOError -# If the target does not support this command, Unsupported # # Since: 1.2 ## @@ -1883,10 +1835,6 @@ # # Returns: Nothing on success # If @type is not a valid network backend, DeviceNotFound -# If @id is not a valid identifier, InvalidParameterValue -# if @id already exists, DuplicateId -# If @props contains an invalid parameter for this backend, -# InvalidParameter ## { 'command': 'netdev_add', 'data': {'type': 'str', 'id': 'str', '*props': '**'}, @@ -2206,8 +2154,6 @@ # @fdname: file descriptor name # # Returns: Nothing on success -# If file descriptor was not received, FdNotSupplied -# If @fdname is not valid, InvalidParameterType # # Since: 0.14.0 # @@ -2227,7 +2173,6 @@ # @fdname: file descriptor name # # Returns: Nothing on success -# If @fdname is not found, FdNotFound # # Since: 0.14.0 ## diff --git a/qmp-commands.hx b/qmp-commands.hx index ac466382c0..e07c7b0a9d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -435,8 +435,8 @@ Example: -> { "execute": "inject-nmi" } <- { "return": {} } -Note: inject-nmi is only supported for x86 guest currently, it will - returns "Unsupported" error for non-x86 guest. +Note: inject-nmi fails when the guest doesn't support injecting. + Currently, only x86 guests do. EQMP From 93b91c59dbccde6e4d25661150c1529bd5ee4a06 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 16:30:13 -0300 Subject: [PATCH 30/48] qemu-ga: switch to the new error format on the wire IMPORTANT: this BREAKS qemu-ga compatibility for the error response. Instead of returning something like: { "error": { "class": "InvalidParameterValue", "data": {"name": "mode", "expected": "halt|powerdown|reboot" } } } qemu-ga now returns: { "error": { "class": "GenericError", "desc": "Parameter 'mode' expects halt|powerdown|reboot" } } Notice that this is also a bug fix, as qemu-ga wasn't returning the human message. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- Makefile.objs | 1 + qapi/qmp-core.h | 1 + qapi/qmp-dispatch.c | 10 +++++++++- qemu-ga.c | 4 ++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 5ebbcfa171..8454b536cf 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -211,6 +211,7 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) # qapi qapi-obj-y = qapi/ +qapi-obj-y += qapi-types.o qapi-visit.o common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h index b0f64ba1ee..00446cff9b 100644 --- a/qapi/qmp-core.h +++ b/qapi/qmp-core.h @@ -49,6 +49,7 @@ void qmp_disable_command(const char *name); void qmp_enable_command(const char *name); bool qmp_command_is_enabled(const char *name); char **qmp_get_command_list(void); +QObject *qmp_build_error_object(Error *errp); #endif diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 122c1a29ba..ec613f88b5 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -14,6 +14,7 @@ #include "qemu-objects.h" #include "qapi/qmp-core.h" #include "json-parser.h" +#include "qapi-types.h" #include "error.h" #include "error_int.h" #include "qerror.h" @@ -109,6 +110,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) return ret; } +QObject *qmp_build_error_object(Error *errp) +{ + return qobject_from_jsonf("{ 'class': %s, 'desc': %s }", + ErrorClass_lookup[error_get_class(errp)], + error_get_pretty(errp)); +} + QObject *qmp_dispatch(QObject *request) { Error *err = NULL; @@ -119,7 +127,7 @@ QObject *qmp_dispatch(QObject *request) rsp = qdict_new(); if (err) { - qdict_put_obj(rsp, "error", error_get_qobject(err)); + qdict_put_obj(rsp, "error", qmp_build_error_object(err)); error_free(err); } else if (ret) { qdict_put_obj(rsp, "return", ret); diff --git a/qemu-ga.c b/qemu-ga.c index f1a39ec3a6..39abc50e89 100644 --- a/qemu-ga.c +++ b/qemu-ga.c @@ -515,7 +515,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens) } else { g_warning("failed to parse event: %s", error_get_pretty(err)); } - qdict_put_obj(qdict, "error", error_get_qobject(err)); + qdict_put_obj(qdict, "error", qmp_build_error_object(err)); error_free(err); } else { qdict = qobject_to_qdict(obj); @@ -532,7 +532,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens) qdict = qdict_new(); g_warning("unrecognized payload format"); error_set(&err, QERR_UNSUPPORTED); - qdict_put_obj(qdict, "error", error_get_qobject(err)); + qdict_put_obj(qdict, "error", qmp_build_error_object(err)); error_free(err); } ret = send_response(s, QOBJECT(qdict)); From 7795b166d9d1e2b33d428f5acab6d0d5e617ee91 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 17:59:59 -0300 Subject: [PATCH 31/48] error: drop error_get_qobject()/error_set_qobject() error_get_qobject() is unused since last commit, error_set_qobject() has never been used. Also drops error_int.h. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 20 -------------------- error_int.h | 28 ---------------------------- qapi/qmp-dispatch.c | 1 - qemu-ga.c | 1 - 4 files changed, 50 deletions(-) delete mode 100644 error_int.h diff --git a/error.c b/error.c index b1d5131470..9d7b35f479 100644 --- a/error.c +++ b/error.c @@ -15,7 +15,6 @@ #include "qjson.h" #include "qdict.h" #include "qapi-types.h" -#include "error_int.h" #include "qerror.h" struct Error @@ -91,22 +90,3 @@ void error_propagate(Error **dst_err, Error *local_err) error_free(local_err); } } - -QObject *error_get_qobject(Error *err) -{ - QINCREF(err->obj); - return QOBJECT(err->obj); -} - -void error_set_qobject(Error **errp, QObject *obj) -{ - Error *err; - if (errp == NULL) { - return; - } - err = g_malloc0(sizeof(*err)); - err->obj = qobject_to_qdict(obj); - qobject_incref(obj); - - *errp = err; -} diff --git a/error_int.h b/error_int.h deleted file mode 100644 index 4b00d0836e..0000000000 --- a/error_int.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * QEMU Error Objects - * - * Copyright IBM, Corp. 2011 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU LGPL, version 2. See - * the COPYING.LIB file in the top-level directory. - */ -#ifndef QEMU_ERROR_INT_H -#define QEMU_ERROR_INT_H - -#include "qemu-common.h" -#include "qobject.h" -#include "qdict.h" -#include "error.h" - -/** - * Internal QEMU functions for working with Error. - * - * These are used to convert QErrors to Errors - */ -QObject *error_get_qobject(Error *err); -void error_set_qobject(Error **errp, QObject *obj); - -#endif diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index ec613f88b5..4085994686 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -16,7 +16,6 @@ #include "json-parser.h" #include "qapi-types.h" #include "error.h" -#include "error_int.h" #include "qerror.h" static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp) diff --git a/qemu-ga.c b/qemu-ga.c index 39abc50e89..8f87621ae4 100644 --- a/qemu-ga.c +++ b/qemu-ga.c @@ -28,7 +28,6 @@ #include "module.h" #include "signal.h" #include "qerror.h" -#include "error_int.h" #include "qapi/qmp-core.h" #include "qga/channel.h" #ifdef _WIN32 From df1e608a01eb0d55d6639d97f575dba37a44ac4a Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 17:51:03 -0300 Subject: [PATCH 32/48] error, qerror: pass desc string to error calls This commit changes all QERR_ macros to contain a human message (ie. the desc string found in qerr_table[]) instead of a json dictionary in string format. Before this commit, error_set() and qerror_report() would receive a json dictionary in string format and build a qobject from it. Now, both function receive a human message instead and the qobject is not built anymore. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 3 +- error.h | 10 ++-- qerror.c | 42 +---------------- qerror.h | 141 +++++++++++++++++++++++++++---------------------------- 4 files changed, 77 insertions(+), 119 deletions(-) diff --git a/error.c b/error.c index 9d7b35f479..0e1037333c 100644 --- a/error.c +++ b/error.c @@ -37,9 +37,8 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) err = g_malloc0(sizeof(*err)); va_start(ap, fmt); - err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap)); + err->msg = g_strdup_vprintf(fmt, ap); va_end(ap); - err->msg = qerror_format(fmt, err->obj); err->err_class = err_class; *errp = err; diff --git a/error.h b/error.h index 5336fc58b2..96fc20328f 100644 --- a/error.h +++ b/error.h @@ -17,15 +17,15 @@ #include /** - * A class representing internal errors within QEMU. An error has a string - * typename and optionally a set of named string parameters. + * A class representing internal errors within QEMU. An error has a ErrorClass + * code and a human message. */ typedef struct Error Error; /** - * Set an indirect pointer to an error given a printf-style format parameter. - * Currently, qerror.h defines these error formats. This function is not - * meant to be used outside of QEMU. + * Set an indirect pointer to an error given a ErrorClass value and a + * printf-style human message. This function is not meant to be used outside + * of QEMU. */ void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4); diff --git a/qerror.c b/qerror.c index 0bf8aec947..dda14273d5 100644 --- a/qerror.c +++ b/qerror.c @@ -342,45 +342,6 @@ static QError *qerror_new(void) return qerr; } -static QDict *error_obj_from_fmt_no_fail(const char *fmt, va_list *va) -{ - QObject *obj; - QDict *ret; - - obj = qobject_from_jsonv(fmt, va); - if (!obj) { - fprintf(stderr, "invalid json in error dict '%s'\n", fmt); - abort(); - } - if (qobject_type(obj) != QTYPE_QDICT) { - fprintf(stderr, "error is not a dict '%s'\n", fmt); - abort(); - } - - ret = qobject_to_qdict(obj); - obj = qdict_get(ret, "class"); - if (!obj) { - fprintf(stderr, "missing 'class' key in '%s'\n", fmt); - abort(); - } - if (qobject_type(obj) != QTYPE_QSTRING) { - fprintf(stderr, "'class' key value should be a string in '%s'\n", fmt); - abort(); - } - - obj = qdict_get(ret, "data"); - if (!obj) { - fprintf(stderr, "missing 'data' key in '%s'\n", fmt); - abort(); - } - if (qobject_type(obj) != QTYPE_QDICT) { - fprintf(stderr, "'data' key value should be a dict in '%s'\n", fmt); - abort(); - } - - return ret; -} - /** * qerror_from_info(): Create a new QError from error information * @@ -394,9 +355,8 @@ static QError *qerror_from_info(ErrorClass err_class, const char *fmt, qerr = qerror_new(); loc_save(&qerr->loc); + qerr->err_msg = g_strdup_vprintf(fmt, *va); qerr->err_class = err_class; - qerr->error = error_obj_from_fmt_no_fail(fmt, va); - qerr->err_msg = qerror_format(fmt, qerr->error); return qerr; } diff --git a/qerror.h b/qerror.h index 4f92218d85..057a8f287a 100644 --- a/qerror.h +++ b/qerror.h @@ -45,214 +45,213 @@ char *qerror_format(const char *fmt, QDict *error); * Use scripts/check-qerror.sh to check. */ #define QERR_ADD_CLIENT_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AddClientFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Could not add client" #define QERR_AMBIGUOUS_PATH \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Path '%s' does not uniquely identify an object" #define QERR_BAD_BUS_FOR_DEVICE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' can't go on a %s bus" #define QERR_BASE_NOT_FOUND \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Base '%s' not found" #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by device '%s' does not support feature '%s'" #define QERR_BUFFER_OVERRUN \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BufferOverrun', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "An internal buffer overran" #define QERR_BUS_NO_HOTPLUG \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Bus '%s' does not support hotplugging" #define QERR_BUS_NOT_FOUND \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Bus '%s' not found" #define QERR_COMMAND_DISABLED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "The command %s has been disabled for this instance" #define QERR_COMMAND_NOT_FOUND \ - ERROR_CLASS_COMMAND_NOT_FOUND, "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }" + ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found" #define QERR_DEVICE_ENCRYPTED \ - ERROR_CLASS_DEVICE_ENCRYPTED, "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }" + ERROR_CLASS_DEVICE_ENCRYPTED, "'%s' (%s) is encrypted" #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when using feature '%s' in device '%s'" #define QERR_DEVICE_HAS_NO_MEDIUM \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no medium" #define QERR_DEVICE_INIT_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' could not be initialized" #define QERR_DEVICE_IN_USE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' is in use" #define QERR_DEVICE_IS_READ_ONLY \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' is read only" #define QERR_DEVICE_LOCKED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' is locked" #define QERR_DEVICE_MULTIPLE_BUSSES \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' has multiple child busses" #define QERR_DEVICE_NO_BUS \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no child bus" #define QERR_DEVICE_NO_HOTPLUG \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' does not support hotplugging" #define QERR_DEVICE_NOT_ACTIVE \ - ERROR_CLASS_DEVICE_NOT_ACTIVE, "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }" + ERROR_CLASS_DEVICE_NOT_ACTIVE, "Device '%s' has not been activated" #define QERR_DEVICE_NOT_ENCRYPTED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not encrypted" #define QERR_DEVICE_NOT_FOUND \ - ERROR_CLASS_DEVICE_NOT_FOUND, "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }" + ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found" #define QERR_DEVICE_NOT_REMOVABLE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not removable" #define QERR_DUPLICATE_ID \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Duplicate ID '%s' for %s" #define QERR_FD_NOT_FOUND \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotFound', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "File descriptor named '%s' not found" #define QERR_FD_NOT_SUPPLIED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FdNotSupplied', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "No file descriptor supplied via SCM_RIGHTS" #define QERR_FEATURE_DISABLED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "The feature '%s' is not enabled" #define QERR_INVALID_BLOCK_FORMAT \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Invalid block format '%s'" #define QERR_INVALID_OPTION_GROUP \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }" + ERROR_CLASS_GENERIC_ERROR, "There is no option group '%s'" #define QERR_INVALID_PARAMETER \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'" #define QERR_INVALID_PARAMETER_COMBINATION \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterCombination', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination" #define QERR_INVALID_PARAMETER_TYPE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s" #define QERR_INVALID_PARAMETER_VALUE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s" #define QERR_INVALID_PASSWORD \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'InvalidPassword', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Password incorrect" #define QERR_IO_ERROR \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'IOError', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "An IO error has occurred" #define QERR_JSON_PARSE_ERROR \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParseError', 'data': { 'message': %s } }" + ERROR_CLASS_GENERIC_ERROR, "JSON parse error, %s" #define QERR_JSON_PARSING \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'JSONParsing', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax" #define QERR_KVM_MISSING_CAP \ - ERROR_CLASS_K_V_M_MISSING_CAP, "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }" + ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable" #define QERR_MIGRATION_ACTIVE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationActive', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress" #define QERR_MIGRATION_NOT_SUPPORTED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }" + ERROR_CLASS_GENERIC_ERROR, "State blocked by non-migratable device '%s'" #define QERR_MIGRATION_EXPECTED \ - ERROR_CLASS_MIGRATION_EXPECTED, "{ 'class': 'MigrationExpected', 'data': {} }" + ERROR_CLASS_MIGRATION_EXPECTED, "An incoming migration is expected before this command can be executed" #define QERR_MISSING_PARAMETER \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'MissingParameter', 'data': { 'name': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' is missing" #define QERR_NO_BUS_FOR_DEVICE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }" + ERROR_CLASS_GENERIC_ERROR, "No '%s' bus found for device '%s'" #define QERR_NOT_SUPPORTED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'NotSupported', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Not supported" #define QERR_OPEN_FILE_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Could not open '%s'" #define QERR_PERMISSION_DENIED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PermissionDenied', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation" #define QERR_PROPERTY_NOT_FOUND \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' not found" #define QERR_PROPERTY_VALUE_BAD \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' doesn't take value '%s'" #define QERR_PROPERTY_VALUE_IN_USE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't take value '%s', it's in use" #define QERR_PROPERTY_VALUE_NOT_FOUND \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't find value '%s'" #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \ - "'device': %s, 'property': %s, 'value': %"PRId64" } }" + ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2" #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }" + ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")" #define QERR_QGA_COMMAND_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Guest agent command failed, error was '%s'" #define QERR_QGA_LOGGING_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QgaLoggingFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Guest agent failed to log non-optional log statement" #define QERR_QMP_BAD_INPUT_OBJECT \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Expected '%s' in QMP input" #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }" + ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' expects '%s'" #define QERR_QMP_EXTRA_MEMBER \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }" + ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' is unexpected" #define QERR_RESET_REQUIRED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'ResetRequired', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Resetting the Virtual Machine is required" #define QERR_SET_PASSWD_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SetPasswdFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Could not set password" #define QERR_TOO_MANY_FILES \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'TooManyFiles', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Too many open files" #define QERR_UNDEFINED_ERROR \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UndefinedError', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "An undefined error has occurred" #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }" + ERROR_CLASS_GENERIC_ERROR, "'%s' uses a %s feature which is not supported by this qemu version: %s" #define QERR_UNSUPPORTED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'Unsupported', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported" #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'" #define QERR_VNC_SERVER_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }" + ERROR_CLASS_GENERIC_ERROR, "Could not start VNC server on %s" #define QERR_SOCKET_CONNECT_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockConnectFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket" #define QERR_SOCKET_LISTEN_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockListenFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Failed to set socket to listening mode" #define QERR_SOCKET_BIND_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockBindFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket" #define QERR_SOCKET_CREATE_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "{ 'class': 'SockCreateFailed', 'data': {} }" + ERROR_CLASS_GENERIC_ERROR, "Failed to create socket" #endif /* QERROR_H */ From 3647f5c161dddb5ec22c2d8e0ab27811959e3ada Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 27 Jul 2012 18:11:16 -0300 Subject: [PATCH 33/48] qerror: drop qerror_table and qerror_format() They are unused since last commit. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- qerror.c | 400 ------------------------------------------------------- qerror.h | 7 - 2 files changed, 407 deletions(-) diff --git a/qerror.c b/qerror.c index dda14273d5..ccc52be2a7 100644 --- a/qerror.c +++ b/qerror.c @@ -22,311 +22,6 @@ static const QType qerror_type = { .destroy = qerror_destroy_obj, }; -/** - * The 'desc' parameter is a printf-like string, the format of the format - * string is: - * - * %(KEY) - * - * Where KEY is a QDict key, which has to be passed to qerror_from_info(). - * - * Example: - * - * "foo error on device: %(device) slot: %(slot_nr)" - * - * A single percent sign can be printed if followed by a second one, - * for example: - * - * "running out of foo: %(foo)%%" - * - * Please keep the entries in alphabetical order. - * Use scripts/check-qerror.sh to check. - */ -static const QErrorStringTable qerror_table[] = { - { - QERR_ADD_CLIENT_FAILED, - "Could not add client", - }, - { - QERR_AMBIGUOUS_PATH, - "Path '%(path)' does not uniquely identify an object" - }, - { - QERR_BAD_BUS_FOR_DEVICE, - "Device '%(device)' can't go on a %(bad_bus_type) bus", - }, - { - QERR_BASE_NOT_FOUND, - "Base '%(base)' not found", - }, - { - QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, - "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'", - }, - { - QERR_BUS_NO_HOTPLUG, - "Bus '%(bus)' does not support hotplugging", - }, - { - QERR_BUS_NOT_FOUND, - "Bus '%(bus)' not found", - }, - { - QERR_COMMAND_DISABLED, - "The command %(name) has been disabled for this instance", - }, - { - QERR_COMMAND_NOT_FOUND, - "The command %(name) has not been found", - }, - { - QERR_DEVICE_ENCRYPTED, - "'%(device)' (%(filename)) is encrypted", - }, - { - QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, - "Migration is disabled when using feature '%(feature)' in device '%(device)'", - }, - { - QERR_DEVICE_HAS_NO_MEDIUM, - "Device '%(device)' has no medium", - }, - { - QERR_DEVICE_INIT_FAILED, - "Device '%(device)' could not be initialized", - }, - { - QERR_DEVICE_IN_USE, - "Device '%(device)' is in use", - }, - { - QERR_DEVICE_IS_READ_ONLY, - "Device '%(device)' is read only", - }, - { - QERR_DEVICE_LOCKED, - "Device '%(device)' is locked", - }, - { - QERR_DEVICE_MULTIPLE_BUSSES, - "Device '%(device)' has multiple child busses", - }, - { - QERR_DEVICE_NO_BUS, - "Device '%(device)' has no child bus", - }, - { - QERR_DEVICE_NO_HOTPLUG, - "Device '%(device)' does not support hotplugging", - }, - { - QERR_DEVICE_NOT_ACTIVE, - "Device '%(device)' has not been activated", - }, - { - QERR_DEVICE_NOT_ENCRYPTED, - "Device '%(device)' is not encrypted", - }, - { - QERR_DEVICE_NOT_FOUND, - "Device '%(device)' not found", - }, - { - QERR_DEVICE_NOT_REMOVABLE, - "Device '%(device)' is not removable", - }, - { - QERR_DUPLICATE_ID, - "Duplicate ID '%(id)' for %(object)", - }, - { - QERR_FD_NOT_FOUND, - "File descriptor named '%(name)' not found", - }, - { - QERR_FD_NOT_SUPPLIED, - "No file descriptor supplied via SCM_RIGHTS", - }, - { - QERR_FEATURE_DISABLED, - "The feature '%(name)' is not enabled", - }, - { - QERR_INVALID_BLOCK_FORMAT, - "Invalid block format '%(name)'", - }, - { - QERR_INVALID_OPTION_GROUP, - "There is no option group '%(group)'", - }, - { - QERR_INVALID_PARAMETER, - "Invalid parameter '%(name)'", - }, - { - QERR_INVALID_PARAMETER_COMBINATION, - "Invalid parameter combination", - }, - { - QERR_INVALID_PARAMETER_TYPE, - "Invalid parameter type for '%(name)', expected: %(expected)", - }, - { - QERR_INVALID_PARAMETER_VALUE, - "Parameter '%(name)' expects %(expected)", - }, - { - QERR_INVALID_PASSWORD, - "Password incorrect", - }, - { - QERR_IO_ERROR, - "An IO error has occurred", - }, - { - QERR_JSON_PARSE_ERROR, - "JSON parse error, %(message)", - - }, - { - QERR_JSON_PARSING, - "Invalid JSON syntax", - }, - { - QERR_KVM_MISSING_CAP, - "Using KVM without %(capability), %(feature) unavailable", - }, - { - QERR_MIGRATION_ACTIVE, - "There's a migration process in progress", - }, - { - QERR_MIGRATION_NOT_SUPPORTED, - "State blocked by non-migratable device '%(device)'", - }, - { - QERR_MIGRATION_EXPECTED, - "An incoming migration is expected before this command can be executed", - }, - { - QERR_MISSING_PARAMETER, - "Parameter '%(name)' is missing", - }, - { - QERR_NO_BUS_FOR_DEVICE, - "No '%(bus)' bus found for device '%(device)'", - }, - { - QERR_NOT_SUPPORTED, - "Not supported", - }, - { - QERR_OPEN_FILE_FAILED, - "Could not open '%(filename)'", - }, - { - QERR_PERMISSION_DENIED, - "Insufficient permission to perform this operation", - }, - { - QERR_PROPERTY_NOT_FOUND, - "Property '%(device).%(property)' not found", - }, - { - QERR_PROPERTY_VALUE_BAD, - "Property '%(device).%(property)' doesn't take value '%(value)'", - }, - { - QERR_PROPERTY_VALUE_IN_USE, - "Property '%(device).%(property)' can't take value '%(value)', it's in use", - }, - { - QERR_PROPERTY_VALUE_NOT_FOUND, - "Property '%(device).%(property)' can't find value '%(value)'", - }, - { - QERR_PROPERTY_VALUE_NOT_POWER_OF_2, - "Property '%(device).%(property)' doesn't take " - "value '%(value)', it's not a power of 2", - }, - { - QERR_PROPERTY_VALUE_OUT_OF_RANGE, - "Property '%(device).%(property)' doesn't take " - "value %(value) (minimum: %(min), maximum: %(max))", - }, - { - QERR_QGA_COMMAND_FAILED, - "Guest agent command failed, error was '%(message)'", - }, - { - QERR_QGA_LOGGING_FAILED, - "Guest agent failed to log non-optional log statement", - }, - { - QERR_QMP_BAD_INPUT_OBJECT, - "Expected '%(expected)' in QMP input", - }, - { - QERR_QMP_BAD_INPUT_OBJECT_MEMBER, - "QMP input object member '%(member)' expects '%(expected)'", - }, - { - QERR_QMP_EXTRA_MEMBER, - "QMP input object member '%(member)' is unexpected", - }, - { - QERR_RESET_REQUIRED, - "Resetting the Virtual Machine is required", - }, - { - QERR_SET_PASSWD_FAILED, - "Could not set password", - }, - { - QERR_TOO_MANY_FILES, - "Too many open files", - }, - { - QERR_UNDEFINED_ERROR, - "An undefined error has occurred", - }, - { - QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, - "'%(device)' uses a %(format) feature which is not " - "supported by this qemu version: %(feature)", - }, - { - QERR_UNSUPPORTED, - "this feature or command is not currently supported", - }, - { - QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION, - "Migration is disabled when VirtFS export path '%(path)' " - "is mounted in the guest using mount_tag '%(tag)'", - }, - { - QERR_VNC_SERVER_FAILED, - "Could not start VNC server on %(target)", - }, - { - QERR_SOCKET_CONNECT_FAILED, - "Failed to connect to socket", - }, - { - QERR_SOCKET_LISTEN_FAILED, - "Failed to set socket to listening mode", - }, - { - QERR_SOCKET_BIND_FAILED, - "Failed to bind socket", - }, - { - QERR_SOCKET_CREATE_FAILED, - "Failed to create socket", - }, - {} -}; - /** * qerror_new(): Create a new QError * @@ -361,101 +56,6 @@ static QError *qerror_from_info(ErrorClass err_class, const char *fmt, return qerr; } -static void parse_error(const QErrorStringTable *entry, int c) -{ - fprintf(stderr, "expected '%c' in '%s'", c, entry->desc); - abort(); -} - -static const char *append_field(QDict *error, QString *outstr, - const QErrorStringTable *entry, - const char *start) -{ - QObject *obj; - QDict *qdict; - QString *key_qs; - const char *end, *key; - - if (*start != '%') - parse_error(entry, '%'); - start++; - if (*start != '(') - parse_error(entry, '('); - start++; - - end = strchr(start, ')'); - if (!end) - parse_error(entry, ')'); - - key_qs = qstring_from_substr(start, 0, end - start - 1); - key = qstring_get_str(key_qs); - - qdict = qobject_to_qdict(qdict_get(error, "data")); - obj = qdict_get(qdict, key); - if (!obj) { - abort(); - } - - switch (qobject_type(obj)) { - case QTYPE_QSTRING: - qstring_append(outstr, qdict_get_str(qdict, key)); - break; - case QTYPE_QINT: - qstring_append_int(outstr, qdict_get_int(qdict, key)); - break; - default: - abort(); - } - - QDECREF(key_qs); - return ++end; -} - -static QString *qerror_format_desc(QDict *error, - const QErrorStringTable *entry) -{ - QString *qstring; - const char *p; - - assert(entry != NULL); - - qstring = qstring_new(); - - for (p = entry->desc; *p != '\0';) { - if (*p != '%') { - qstring_append_chr(qstring, *p++); - } else if (*(p + 1) == '%') { - qstring_append_chr(qstring, '%'); - p += 2; - } else { - p = append_field(error, qstring, entry, p); - } - } - - return qstring; -} - -char *qerror_format(const char *fmt, QDict *error) -{ - const QErrorStringTable *entry = NULL; - QString *qstr; - char *ret; - int i; - - for (i = 0; qerror_table[i].error_fmt; i++) { - if (strcmp(qerror_table[i].error_fmt, fmt) == 0) { - entry = &qerror_table[i]; - break; - } - } - - qstr = qerror_format_desc(error, entry); - ret = g_strdup(qstring_get_str(qstr)); - QDECREF(qstr); - - return ret; -} - /** * qerror_human(): Format QError data into human-readable string. */ diff --git a/qerror.h b/qerror.h index 057a8f287a..c5ad29fedd 100644 --- a/qerror.h +++ b/qerror.h @@ -19,12 +19,6 @@ #include "qapi-types.h" #include -typedef struct QErrorStringTable { - ErrorClass err_class; - const char *error_fmt; - const char *desc; -} QErrorStringTable; - typedef struct QError { QObject_HEAD; QDict *error; @@ -37,7 +31,6 @@ QString *qerror_human(const QError *qerror); void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3); void qerror_report_err(Error *err); void assert_no_error(Error *err); -char *qerror_format(const char *fmt, QDict *error); /* * QError class list From 6d3f0dbb304d59759b2faf1e50db94d996f51f8a Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 1 Aug 2012 18:06:44 -0300 Subject: [PATCH 34/48] error, qerror: drop QDict member Used to store error information, but it's unused now. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- error.c | 4 ---- qerror.c | 4 ---- qerror.h | 1 - 3 files changed, 9 deletions(-) diff --git a/error.c b/error.c index 0e1037333c..1f05fc466e 100644 --- a/error.c +++ b/error.c @@ -19,7 +19,6 @@ struct Error { - QDict *obj; char *msg; ErrorClass err_class; }; @@ -51,8 +50,6 @@ Error *error_copy(const Error *err) err_new = g_malloc0(sizeof(*err)); err_new->msg = g_strdup(err->msg); err_new->err_class = err->err_class; - err_new->obj = err->obj; - QINCREF(err_new->obj); return err_new; } @@ -75,7 +72,6 @@ const char *error_get_pretty(Error *err) void error_free(Error *err) { if (err) { - QDECREF(err->obj); g_free(err->msg); g_free(err); } diff --git a/qerror.c b/qerror.c index ccc52be2a7..08185047b4 100644 --- a/qerror.c +++ b/qerror.c @@ -100,7 +100,6 @@ void qerror_report(ErrorClass eclass, const char *fmt, ...) /* Evil... */ struct Error { - QDict *obj; char *msg; ErrorClass err_class; }; @@ -111,8 +110,6 @@ void qerror_report_err(Error *err) qerr = qerror_new(); loc_save(&qerr->loc); - QINCREF(err->obj); - qerr->error = err->obj; qerr->err_msg = g_strdup(err->msg); qerr->err_class = err->err_class; @@ -154,7 +151,6 @@ static void qerror_destroy_obj(QObject *obj) assert(obj != NULL); qerr = qobject_to_qerror(obj); - QDECREF(qerr->error); g_free(qerr->err_msg); g_free(qerr); } diff --git a/qerror.h b/qerror.h index c5ad29fedd..d0a76a4f71 100644 --- a/qerror.h +++ b/qerror.h @@ -21,7 +21,6 @@ typedef struct QError { QObject_HEAD; - QDict *error; Location loc; char *err_msg; ErrorClass err_class; From adb2072ed0fd595b05f6571e985b271a3cfa872d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 6 Aug 2012 11:35:22 -0300 Subject: [PATCH 35/48] docs: writing-qmp-commands.txt: update error section Add information about the new error format and improve the text a bit. Signed-off-by: Luiz Capitulino Reviewed-by: Markus Armbruster --- docs/writing-qmp-commands.txt | 47 ++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt index 0ad51aa22a..8349dec8af 100644 --- a/docs/writing-qmp-commands.txt +++ b/docs/writing-qmp-commands.txt @@ -210,19 +210,17 @@ if you don't see these strings, then something went wrong. === Errors === QMP commands should use the error interface exported by the error.h header -file. The basic function used to set an error is the error_set() one. +file. Basically, errors are set by calling the error_set() function. Let's say we don't accept the string "message" to contain the word "love". If -it does contain it, we want the "hello-world" command to the return the -InvalidParameter error. - -Only one change is required, and it's in the C implementation: +it does contain it, we want the "hello-world" command to return an error: void qmp_hello_world(bool has_message, const char *message, Error **errp) { if (has_message) { if (strstr(message, "love")) { - error_set(errp, QERR_INVALID_PARAMETER, "message"); + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "the word 'love' is not allowed"); return; } printf("%s\n", message); @@ -231,30 +229,40 @@ void qmp_hello_world(bool has_message, const char *message, Error **errp) } } -Let's test it. Build qemu, run it as defined in the "Testing" section, and -then issue the following command: +The first argument to the error_set() function is the Error pointer to pointer, +which is passed to all QMP functions. The second argument is a ErrorClass +value, which should be ERROR_CLASS_GENERIC_ERROR most of the time (more +details about error classes are given below). The third argument is a human +description of the error, this is a free-form printf-like string. -{ "execute": "hello-world", "arguments": { "message": "we love qemu" } } +Let's test the example above. Build qemu, run it as defined in the "Testing" +section, and then issue the following command: + +{ "execute": "hello-world", "arguments": { "message": "all you need is love" } } The QMP server's response should be: { "error": { - "class": "InvalidParameter", - "desc": "Invalid parameter 'message'", - "data": { - "name": "message" - } + "class": "GenericError", + "desc": "the word 'love' is not allowed" } } -Which is the InvalidParameter error. +As a general rule, all QMP errors should use ERROR_CLASS_GENERIC_ERROR. There +are two exceptions to this rule: -When you have to return an error but you're unsure what error to return or -which arguments an error takes, you should look at the qerror.h file. Note -that you might be required to add new errors if needed. + 1. A non-generic ErrorClass value exists* for the failure you want to report + (eg. DeviceNotFound) -FIXME: describe better the error API and how to add new errors. + 2. Management applications have to take special action on the failure you + want to report, hence you have to add a new ErrorClass value so that they + can check for it + +If the failure you want to report doesn't fall in one of the two cases above, +just report ERROR_CLASS_GENERIC_ERROR. + + * All existing ErrorClass values are defined in the qapi-schema.json file === Command Documentation === @@ -275,7 +283,6 @@ here goes "hello-world"'s new entry for the qapi-schema.json file: # @message: #optional string to be printed # # Returns: Nothing on success. -# If @message contains "love", InvalidParameter # # Notes: if @message is not provided, the "Hello, world" string will # be printed instead From 08b76b9fc3f0c25f062216955411aefaefabff89 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 6 Aug 2012 11:35:22 -0300 Subject: [PATCH 36/48] scripts: qapi-commands.py: qmp-commands.h: include qdict.h qmp-commands.h declares several functions that have arguments of type QDict. However, qdict.h is not included. This will cause a build breakage when a file includes qmp-commands.h but doesn't include qdict.h. Signed-off-by: Luiz Capitulino --- scripts/qapi-commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 9eed40e18a..3c4678dbf1 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -342,6 +342,7 @@ def gen_command_decl_prologue(header, guard, prefix=""): #define %(guard)s #include "%(prefix)sqapi-types.h" +#include "qdict.h" #include "error.h" ''', From 1405819637f53ed8021067eb3ea52e32bef2870b Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 8 Aug 2012 17:29:17 -0300 Subject: [PATCH 37/48] qmp: don't emit the RESET event on wakeup from S3 QEMU is basically using reset logic when waking up from S3. This causes the QMP RESET event to be emitted, which is wrong. Also, the runstate checks done in reset are not necessary for S3 wakeup. Fix this by untangling wakeup from reset logic and passing VMRESET_SILENT to qemu_system_reset() to avoid emitting the RESET event. Signed-off-by: Luiz Capitulino Acked-by: Gerd Hoffmann --- vl.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 91076f0e7c..68fa0a060f 100644 --- a/vl.c +++ b/vl.c @@ -1298,6 +1298,7 @@ static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; static int suspend_requested; +static int wakeup_requested; static NotifierList suspend_notifiers = NOTIFIER_LIST_INITIALIZER(suspend_notifiers); static NotifierList wakeup_notifiers = @@ -1352,6 +1353,13 @@ static int qemu_suspend_requested(void) return r; } +static int qemu_wakeup_requested(void) +{ + int r = wakeup_requested; + wakeup_requested = 0; + return r; +} + int qemu_powerdown_requested(void) { int r = powerdown_requested; @@ -1459,7 +1467,7 @@ void qemu_system_wakeup_request(WakeupReason reason) runstate_set(RUN_STATE_RUNNING); monitor_protocol_event(QEVENT_WAKEUP, NULL); notifier_list_notify(&wakeup_notifiers, &reason); - reset_requested = 1; + wakeup_requested = 1; qemu_notify_event(); } @@ -1539,6 +1547,12 @@ static bool main_loop_should_exit(void) runstate_set(RUN_STATE_PAUSED); } } + if (qemu_wakeup_requested()) { + pause_all_vcpus(); + cpu_synchronize_all_states(); + qemu_system_reset(VMRESET_SILENT); + resume_all_vcpus(); + } if (qemu_powerdown_requested()) { monitor_protocol_event(QEVENT_POWERDOWN, NULL); qemu_irq_raise(qemu_system_powerdown); From 17c8660b0b2be17d389e2ffd5681d535cc0d8912 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 9 Aug 2012 11:27:30 -0300 Subject: [PATCH 38/48] qmp: emit the WAKEUP event when the guest is put to run Today, the WAKEUP event is emitted when a wakeup _request_ is made. This could be the system_wakeup command, for example. A better semantic would be to emit the event when the guest is already running, as that's what matters in the end. This commit does that change. In theory, this could break compatibility. In practice, it shouldn't happen though, as clients shouldn't rely on timing characteristics of the events. That is, a client relying that the guest is not running when the event arrives may break if the event arrives after the guest is already running. This commit also adds the missing documentation for the WAKEUP event. Signed-off-by: Luiz Capitulino Acked-by: Gerd Hoffmann --- QMP/qmp-events.txt | 13 +++++++++++++ vl.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 9ba7079589..10f69d1906 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -264,6 +264,19 @@ Example: }} +WAKEUP +------ + +Emitted when the guest has woken up from S3 and is running. + +Data: None. + +Example: + +{ "event": "WATCHDOG", + "timestamp": { "seconds": 1344522075, "microseconds": 745528 } } + + WATCHDOG -------- diff --git a/vl.c b/vl.c index 68fa0a060f..97ab39ff6e 100644 --- a/vl.c +++ b/vl.c @@ -1465,7 +1465,6 @@ void qemu_system_wakeup_request(WakeupReason reason) return; } runstate_set(RUN_STATE_RUNNING); - monitor_protocol_event(QEVENT_WAKEUP, NULL); notifier_list_notify(&wakeup_notifiers, &reason); wakeup_requested = 1; qemu_notify_event(); @@ -1552,6 +1551,7 @@ static bool main_loop_should_exit(void) cpu_synchronize_all_states(); qemu_system_reset(VMRESET_SILENT); resume_all_vcpus(); + monitor_protocol_event(QEVENT_WAKEUP, NULL); } if (qemu_powerdown_requested()) { monitor_protocol_event(QEVENT_POWERDOWN, NULL); From cb8900fe0d0b5ea33fc31a01b1c4fb41dd6368aa Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 9 Aug 2012 11:40:27 -0300 Subject: [PATCH 39/48] qmp: qmp-events.txt: put events in alphabetical order Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake Acked-by: Gerd Hoffmann --- QMP/qmp-events.txt | 266 ++++++++++++++++++++++----------------------- 1 file changed, 130 insertions(+), 136 deletions(-) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 10f69d1906..2389370f1f 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -1,6 +1,23 @@ QEMU Monitor Protocol Events ============================ +BALLOON_CHANGE +-------------- + +Emitted when the guest changes the actual BALLOON level. This +value is equivalent to the 'actual' field return by the +'query-balloon' command + +Data: + +- "actual": actual level of the guest memory balloon in bytes (json-number) + +Example: + +{ "event": "BALLOON_CHANGE", + "data": { "actual": 944766976 }, + "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } + BLOCK_IO_ERROR -------------- @@ -26,6 +43,57 @@ Example: Note: If action is "stop", a STOP event will eventually follow the BLOCK_IO_ERROR event. +BLOCK_JOB_CANCELLED +------------------- + +Emitted when a block job has been cancelled. + +Data: + +- "type": Job type ("stream" for image streaming, json-string) +- "device": Device name (json-string) +- "len": Maximum progress value (json-int) +- "offset": Current progress value (json-int) + On success this is equal to len. + On failure this is less than len. +- "speed": Rate limit, bytes per second (json-int) + +Example: + +{ "event": "BLOCK_JOB_CANCELLED", + "data": { "type": "stream", "device": "virtio-disk0", + "len": 10737418240, "offset": 134217728, + "speed": 0 }, + "timestamp": { "seconds": 1267061043, "microseconds": 959568 } } + +BLOCK_JOB_COMPLETED +------------------- + +Emitted when a block job has completed. + +Data: + +- "type": Job type ("stream" for image streaming, json-string) +- "device": Device name (json-string) +- "len": Maximum progress value (json-int) +- "offset": Current progress value (json-int) + On success this is equal to len. + On failure this is less than len. +- "speed": Rate limit, bytes per second (json-int) +- "error": Error message (json-string, optional) + Only present on failure. This field contains a human-readable + error message. There are no semantics other than that streaming + has failed and clients should not try to interpret the error + string. + +Example: + +{ "event": "BLOCK_JOB_COMPLETED", + "data": { "type": "stream", "device": "virtio-disk0", + "len": 10737418240, "offset": 10737418240, + "speed": 0 }, + "timestamp": { "seconds": 1267061043, "microseconds": 959568 } } + DEVICE_TRAY_MOVED ----------------- @@ -98,6 +166,68 @@ Example: Note: If the command-line option "-no-shutdown" has been specified, a STOP event will eventually follow the SHUTDOWN event. +SPICE_CONNECTED, SPICE_DISCONNECTED +----------------------------------- + +Emitted when a SPICE client connects or disconnects. + +Data: + +- "server": Server information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") +- "client": Client information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + +Example: + +{ "timestamp": {"seconds": 1290688046, "microseconds": 388707}, + "event": "SPICE_CONNECTED", + "data": { + "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"}, + "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"} +}} + +SPICE_INITIALIZED +----------------- + +Emitted after initial handshake and authentication takes place (if any) +and the SPICE channel is up'n'running + +Data: + +- "server": Server information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + - "auth": authentication method (json-string, optional) +- "client": Client information (json-object) + - "host": IP address (json-string) + - "port": port number (json-string) + - "family": address family (json-string, "ipv4" or "ipv6") + - "connection-id": spice connection id. All channels with the same id + belong to the same spice session (json-int) + - "channel-type": channel type. "1" is the main control channel, filter for + this one if you want track spice sessions only (json-int) + - "channel-id": channel id. Usually "0", might be different needed when + multiple channels of the same type exist, such as multiple + display channels in a multihead setup (json-int) + - "tls": whevener the channel is encrypted (json-bool) + +Example: + +{ "timestamp": {"seconds": 1290688046, "microseconds": 417172}, + "event": "SPICE_INITIALIZED", + "data": {"server": {"auth": "spice", "port": "5921", + "family": "ipv4", "host": "127.0.0.1"}, + "client": {"port": "49004", "family": "ipv4", "channel-type": 3, + "connection-id": 1804289383, "host": "127.0.0.1", + "channel-id": 0, "tls": true} +}} + STOP ---- @@ -200,70 +330,6 @@ Example: "host": "127.0.0.1", "sasl_username": "luiz" } }, "timestamp": { "seconds": 1263475302, "microseconds": 150772 } } -SPICE_CONNECTED, SPICE_DISCONNECTED ------------------------------------ - -Emitted when a SPICE client connects or disconnects. - -Data: - -- "server": Server information (json-object) - - "host": IP address (json-string) - - "port": port number (json-string) - - "family": address family (json-string, "ipv4" or "ipv6") -- "client": Client information (json-object) - - "host": IP address (json-string) - - "port": port number (json-string) - - "family": address family (json-string, "ipv4" or "ipv6") - -Example: - -{ "timestamp": {"seconds": 1290688046, "microseconds": 388707}, - "event": "SPICE_CONNECTED", - "data": { - "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"}, - "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"} -}} - - -SPICE_INITIALIZED ------------------ - -Emitted after initial handshake and authentication takes place (if any) -and the SPICE channel is up'n'running - -Data: - -- "server": Server information (json-object) - - "host": IP address (json-string) - - "port": port number (json-string) - - "family": address family (json-string, "ipv4" or "ipv6") - - "auth": authentication method (json-string, optional) -- "client": Client information (json-object) - - "host": IP address (json-string) - - "port": port number (json-string) - - "family": address family (json-string, "ipv4" or "ipv6") - - "connection-id": spice connection id. All channels with the same id - belong to the same spice session (json-int) - - "channel-type": channel type. "1" is the main control channel, filter for - this one if you want track spice sessions only (json-int) - - "channel-id": channel id. Usually "0", might be different needed when - multiple channels of the same type exist, such as multiple - display channels in a multihead setup (json-int) - - "tls": whevener the channel is encrypted (json-bool) - -Example: - -{ "timestamp": {"seconds": 1290688046, "microseconds": 417172}, - "event": "SPICE_INITIALIZED", - "data": {"server": {"auth": "spice", "port": "5921", - "family": "ipv4", "host": "127.0.0.1"}, - "client": {"port": "49004", "family": "ipv4", "channel-type": 3, - "connection-id": 1804289383, "host": "127.0.0.1", - "channel-id": 0, "tls": true} -}} - - WAKEUP ------ @@ -276,7 +342,6 @@ Example: { "event": "WATCHDOG", "timestamp": { "seconds": 1344522075, "microseconds": 745528 } } - WATCHDOG -------- @@ -295,74 +360,3 @@ Example: Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is followed respectively by the RESET, SHUTDOWN, or STOP events. - - -BLOCK_JOB_COMPLETED -------------------- - -Emitted when a block job has completed. - -Data: - -- "type": Job type ("stream" for image streaming, json-string) -- "device": Device name (json-string) -- "len": Maximum progress value (json-int) -- "offset": Current progress value (json-int) - On success this is equal to len. - On failure this is less than len. -- "speed": Rate limit, bytes per second (json-int) -- "error": Error message (json-string, optional) - Only present on failure. This field contains a human-readable - error message. There are no semantics other than that streaming - has failed and clients should not try to interpret the error - string. - -Example: - -{ "event": "BLOCK_JOB_COMPLETED", - "data": { "type": "stream", "device": "virtio-disk0", - "len": 10737418240, "offset": 10737418240, - "speed": 0 }, - "timestamp": { "seconds": 1267061043, "microseconds": 959568 } } - - -BLOCK_JOB_CANCELLED -------------------- - -Emitted when a block job has been cancelled. - -Data: - -- "type": Job type ("stream" for image streaming, json-string) -- "device": Device name (json-string) -- "len": Maximum progress value (json-int) -- "offset": Current progress value (json-int) - On success this is equal to len. - On failure this is less than len. -- "speed": Rate limit, bytes per second (json-int) - -Example: - -{ "event": "BLOCK_JOB_CANCELLED", - "data": { "type": "stream", "device": "virtio-disk0", - "len": 10737418240, "offset": 134217728, - "speed": 0 }, - "timestamp": { "seconds": 1267061043, "microseconds": 959568 } } - - -BALLOON_CHANGE ----------- - -Emitted when the guest changes the actual BALLOON level. This -value is equivalent to the 'actual' field return by the -'query-balloon' command - -Data: - -- "actual": actual level of the guest memory balloon in bytes (json-number) - -Example: - -{ "event": "BALLOON_CHANGE", - "data": { "actual": 944766976 }, - "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } From 67e3cf2664b3fc858a895d1e0e4b8d81c3400823 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 9 Aug 2012 12:02:21 -0300 Subject: [PATCH 40/48] qmp: qmp-events.txt: add missing doc for the SUSPEND event Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake Acked-by: Gerd Hoffmann --- QMP/qmp-events.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 2389370f1f..df190ace7b 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -240,6 +240,18 @@ Example: { "event": "STOP", "timestamp": { "seconds": 1267041730, "microseconds": 281295 } } +SUSPEND +------- + +Emitted when guest enters S3 state. + +Data: None. + +Example: + +{ "event": "SUSPEND", + "timestamp": { "seconds": 1344456160, "microseconds": 309119 } } + VNC_CONNECTED ------------- From 25df49f6eb113081f48fdb3a3dd17bf1c0b25600 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Wed, 8 Aug 2012 17:03:01 -0300 Subject: [PATCH 41/48] qmp: add SUSPEND_DISK event Emitted when the guest makes a request to enter S4 state. There are three possible ways of having this event, as described here: http://lists.gnu.org/archive/html/qemu-devel/2012-07/msg02307.html I've decided to add a new event and make it indepedent of SHUTDOWN. This means that the SHUTDOWN event will eventually follow the SUSPEND_DISK event. I've choosen this way because of two reasons: 1. Having an indepedent event makes it possible to query for its existence by using query-events 2. In the future, we may allow the user to change what QEMU should do as a result of the guest entering S4. So it's a good idea to keep both events separated Signed-off-by: Luiz Capitulino --- QMP/qmp-events.txt | 14 ++++++++++++++ hw/acpi.c | 2 ++ monitor.c | 1 + monitor.h | 1 + 4 files changed, 18 insertions(+) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index df190ace7b..287805825f 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -252,6 +252,20 @@ Example: { "event": "SUSPEND", "timestamp": { "seconds": 1344456160, "microseconds": 309119 } } +SUSPEND_DISK +------------ + +Emitted when the guest makes a request to enter S4 state. + +Data: None. + +Example: + +{ "event": "SUSPEND_DISK", + "timestamp": { "seconds": 1344456160, "microseconds": 309119 } } + +Note: QEMU shuts down when entering S4 state. + VNC_CONNECTED ------------- diff --git a/hw/acpi.c b/hw/acpi.c index effc7ec23e..f7950be267 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -22,6 +22,7 @@ #include "hw.h" #include "pc.h" #include "acpi.h" +#include "monitor.h" struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ @@ -386,6 +387,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4) break; default: if (sus_typ == s4) { /* S4 request */ + monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL); qemu_system_shutdown_request(); } break; diff --git a/monitor.c b/monitor.c index 369459069f..586abae178 100644 --- a/monitor.c +++ b/monitor.c @@ -432,6 +432,7 @@ static const char *monitor_event_names[] = { [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED", [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", [QEVENT_SUSPEND] = "SUSPEND", + [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", [QEVENT_WAKEUP] = "WAKEUP", [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", }; diff --git a/monitor.h b/monitor.h index 5f4de1b3da..4ef9a046f8 100644 --- a/monitor.h +++ b/monitor.h @@ -40,6 +40,7 @@ typedef enum MonitorEvent { QEVENT_BLOCK_JOB_CANCELLED, QEVENT_DEVICE_TRAY_MOVED, QEVENT_SUSPEND, + QEVENT_SUSPEND_DISK, QEVENT_WAKEUP, QEVENT_BALLOON_CHANGE, From 1daa31b9dbec60a7a06690749d73ddeeb35f506d Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:09 -0500 Subject: [PATCH 42/48] qmp: introduce device-list-properties command This can be used in conjunction with qom-list-types to determine the supported set of devices and their parameters. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qapi-schema.json | 28 +++++++++++++++++++++++++++ qmp-commands.hx | 7 +++++++ qmp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index ec8d91908c..927fdea2b2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1724,6 +1724,34 @@ 'data': { '*implements': 'str', '*abstract': 'bool' }, 'returns': [ 'ObjectTypeInfo' ] } +## +# @DevicePropertyInfo: +# +# Information about device properties. +# +# @name: the name of the property +# @type: the typename of the property +# +# Since: 1.2 +## +{ 'type': 'DevicePropertyInfo', + 'data': { 'name': 'str', 'type': 'str' } } + +## +# @device-list-properties: +# +# List properties associated with a device. +# +# @typename: the type name of a device +# +# Returns: a list of DevicePropertyInfo describing a devices properties +# +# Since: 1.2 +## +{ 'command': 'device-list-properties', + 'data': { 'typename': 'str'}, + 'returns': [ 'DevicePropertyInfo' ] } + ## # @migrate # diff --git a/qmp-commands.hx b/qmp-commands.hx index e07c7b0a9d..e9e0410384 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2217,3 +2217,10 @@ EQMP .args_type = "implements:s?,abstract:b?", .mhandler.cmd_new = qmp_marshal_input_qom_list_types, }, + + { + .name = "device-list-properties", + .args_type = "typename:s", + .mhandler.cmd_new = qmp_marshal_input_device_list_properties, + }, + diff --git a/qmp.c b/qmp.c index fee9fb2a9d..254a32fd76 100644 --- a/qmp.c +++ b/qmp.c @@ -417,3 +417,53 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements, return ret; } + +DevicePropertyInfoList *qmp_device_list_properties(const char *typename, + Error **errp) +{ + ObjectClass *klass; + Property *prop; + DevicePropertyInfoList *prop_list = NULL; + + klass = object_class_by_name(typename); + if (klass == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, typename); + return NULL; + } + + klass = object_class_dynamic_cast(klass, TYPE_DEVICE); + if (klass == NULL) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + "name", TYPE_DEVICE); + return NULL; + } + + do { + for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) { + DevicePropertyInfoList *entry; + DevicePropertyInfo *info; + + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->set) { + continue; /* no way to set it, don't show */ + } + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(prop->name); + info->type = g_strdup(prop->info->legacy_name ?: prop->info->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = prop_list; + prop_list = entry; + } + klass = object_class_get_parent(klass); + } while (klass != object_class_by_name(TYPE_DEVICE)); + + return prop_list; +} From 5192082097549c5b3aa7c913c6853d97a68172cb Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:10 -0500 Subject: [PATCH 43/48] qapi: mark QOM commands stable We've had a cycle to tweak. It is time to commit to supporting them. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qapi-schema.json | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 927fdea2b2..1731a92d2d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1377,9 +1377,7 @@ # 4) A link type in the form 'link' where subtype is a qdev # device type name. Link properties form the device model graph. # -# Since: 1.1 -# -# Notes: This type is experimental. Its syntax may change in future releases. +# Since: 1.2 ## { 'type': 'ObjectPropertyInfo', 'data': { 'name': 'str', 'type': 'str' } } @@ -1396,10 +1394,7 @@ # Returns: a list of @ObjectPropertyInfo that describe the properties of the # object. # -# Since: 1.1 -# -# Notes: This command is experimental. It's syntax may change in future -# releases. +# Since: 1.2 ## { 'command': 'qom-list', 'data': { 'path': 'str' }, @@ -1435,9 +1430,7 @@ # returns as #str pathnames. All integer property types (u8, u16, etc) # are returned as #int. # -# Since: 1.1 -# -# Notes: This command is experimental and may change syntax in future releases. +# Since: 1.2 ## { 'command': 'qom-get', 'data': { 'path': 'str', 'property': 'str' }, @@ -1456,9 +1449,7 @@ # @value: a value who's type is appropriate for the property type. See @qom-get # for a description of type mapping. # -# Since: 1.1 -# -# Notes: This command is experimental and may change syntax in future releases. +# Since: 1.2 ## { 'command': 'qom-set', 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' }, @@ -1717,8 +1708,6 @@ # Returns: a list of @ObjectTypeInfo or an empty list if no results are found # # Since: 1.1 -# -# Notes: This command is experimental and may change syntax in future releases. ## { 'command': 'qom-list-types', 'data': { '*implements': 'str', '*abstract': 'bool' }, From 01d3c80d6876c7de6b07bee92b1b2440b48e60c9 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:11 -0500 Subject: [PATCH 44/48] qapi: add query-machines command This provides the same output as -M ? but in a structured way. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qapi-schema.json | 28 ++++++++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ vl.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 1731a92d2d..e51753cdb0 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2194,3 +2194,31 @@ # Since: 0.14.0 ## { 'command': 'closefd', 'data': {'fdname': 'str'} } + +## +# @MachineInfo: +# +# Information describing a machine. +# +# @name: the name of the machine +# +# @alias: #optional an alias for the machine name +# +# @default: #optional whether the machine is default +# +# Since: 1.2.0 +## +{ 'type': 'MachineInfo', + 'data': { 'name': 'str', '*alias': 'str', + '*is-default': 'bool' } } + +## +# @query-machines: +# +# Return a list of supported machines +# +# Returns: a list of MachineInfo +# +# Since: 1.2.0 +## +{ 'command': 'query-machines', 'returns': ['MachineInfo'] } diff --git a/qmp-commands.hx b/qmp-commands.hx index e9e0410384..fd87775461 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2224,3 +2224,9 @@ EQMP .mhandler.cmd_new = qmp_marshal_input_device_list_properties, }, + { + .name = "query-machines", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_machines, + }, + diff --git a/vl.c b/vl.c index 97ab39ff6e..d01256a6a3 100644 --- a/vl.c +++ b/vl.c @@ -1213,6 +1213,37 @@ QEMUMachine *find_default_machine(void) return NULL; } +MachineInfoList *qmp_query_machines(Error **errp) +{ + MachineInfoList *mach_list = NULL; + QEMUMachine *m; + + for (m = first_machine; m; m = m->next) { + MachineInfoList *entry; + MachineInfo *info; + + info = g_malloc0(sizeof(*info)); + if (m->is_default) { + info->has_is_default = true; + info->is_default = true; + } + + if (m->alias) { + info->has_alias = true; + info->alias = g_strdup(m->alias); + } + + info->name = g_strdup(m->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = mach_list; + mach_list = entry; + } + + return mach_list; +} + /***********************************************************/ /* main execution loop */ From 6ee373a0032b8fa6b630c6df9cd6618a7a02902b Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:12 -0500 Subject: [PATCH 45/48] compiler: add macro for GCC weak symbols This lets us provide a default implementation of a symbol which targets can override. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- compiler.h | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler.h b/compiler.h index 736e77075a..f76921e5b0 100644 --- a/compiler.h +++ b/compiler.h @@ -45,6 +45,7 @@ # define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2))) # define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) # endif +#define GCC_WEAK __attribute__((weak)) #else #define GCC_ATTR /**/ #define GCC_FMT_ATTR(n, m) From e4e31c6324af480a22bf4150266b278368eaa336 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:13 -0500 Subject: [PATCH 46/48] qapi: add query-cpu-definitions command (v2) This command attempts to map to the behavior of -cpu ?. Unfortunately, the output of this command differs wildly across targets. To accommodate this, we use a weak symbol to implement a default version of the command that fails with a QERR_NOT_SUPPORTED error code. Targets can then override and implement this command if it makes sense for them. Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- qapi-schema.json | 23 +++++++++++++++++++++++ qmp-commands.hx | 6 ++++++ qmp.c | 6 ++++++ 3 files changed, 35 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index e51753cdb0..9347b6a499 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2222,3 +2222,26 @@ # Since: 1.2.0 ## { 'command': 'query-machines', 'returns': ['MachineInfo'] } + +## +# @CpuDefinitionInfo: +# +# Virtual CPU definition. +# +# @name: the name of the CPU definition +# +# Since: 1.2.0 +## +{ 'type': 'CpuDefinitionInfo', + 'data': { 'name': 'str' } } + +## +# @query-cpu-definitions: +# +# Return a list of supported virtual CPU definitions +# +# Returns: a list of CpuDefInfo +# +# Since: 1.2.0 +## +{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] } diff --git a/qmp-commands.hx b/qmp-commands.hx index fd87775461..521da1055f 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2230,3 +2230,9 @@ EQMP .mhandler.cmd_new = qmp_marshal_input_query_machines, }, + { + .name = "query-cpu-definitions", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_cpu_definitions, + }, + diff --git a/qmp.c b/qmp.c index 254a32fd76..6c1e4e8978 100644 --- a/qmp.c +++ b/qmp.c @@ -467,3 +467,9 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename, return prop_list; } + +CpuDefinitionInfoList GCC_WEAK *qmp_query_cpu_definitions(Error **errp) +{ + error_set(errp, QERR_NOT_SUPPORTED); + return NULL; +} From e3966126d077ef60997f651d8e42b71c623b44a6 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:14 -0500 Subject: [PATCH 47/48] target-i386: add implementation of query-cpu-definitions (v2) Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- target-i386/cpu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 880cfea3f8..6d5d0d6e10 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -28,6 +28,7 @@ #include "qemu-config.h" #include "qapi/qapi-visit-core.h" +#include "qmp-commands.h" #include "hyperv.h" @@ -1125,6 +1126,27 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg) } } +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + x86_def_t *def; + + for (def = x86_defs; def; def = def->next) { + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(def->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = cpu_list; + cpu_list = entry; + } + + return cpu_list; +} + int cpu_x86_register(X86CPU *cpu, const char *cpu_model) { CPUX86State *env = &cpu->env; From 70b7660a4ed0ca3891ee51bda78e10b4c36cd358 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 10 Aug 2012 11:04:15 -0500 Subject: [PATCH 48/48] target-ppc: add implementation of query-cpu-definitions (v2) Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- target-ppc/translate_init.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5742229197..6fe4168dc0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -27,6 +27,7 @@ #include "gdbstub.h" #include #include "kvm_ppc.h" +#include "qmp-commands.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -10345,6 +10346,31 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) } } +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(ppc_defs[i].name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = cpu_list; + cpu_list = entry; + } + + return cpu_list; +} + /* CPUClass::reset() */ static void ppc_cpu_reset(CPUState *s) {