All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH v2 05/26] qmp: Clean up how we enforce capability negotiation
Date: Sun, 26 Feb 2017 22:43:23 +0100	[thread overview]
Message-ID: <1488145424-14974-6-git-send-email-armbru@redhat.com> (raw)
In-Reply-To: <1488145424-14974-1-git-send-email-armbru@redhat.com>

To enforce capability negotiation before normal operation,
handle_qmp_command() inspects every command before it's handed off to
qmp_dispatch().  This is a bit of a layering violation, and results in
duplicated code.

Before capability negotiation (!cur_mon->in_command_mode), we fail
commands other than "qmp_capabilities".  This is what enforces
capability negotiation.

Afterwards, we fail command "qmp_capabilities".

Clean this up as follows.

The obvious place to fail a command is the command itself, so move the
"afterwards" check to qmp_qmp_capabilities().

We do the "before" check in every other command, but that would be
bothersome.  Instead, start without all the other commands, by
registering only qmp_qmp_capabilities().  Register the others in
qmp_qmp_capabilities().

Additionally, replace the generic human-readable error message for
CommandNotFound by one that reminds the user to run qmp_capabilities.
Without that, we'd regress commit 2d5a834.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 monitor.c | 70 ++++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 40 insertions(+), 30 deletions(-)

diff --git a/monitor.c b/monitor.c
index 1cc2274..e522b6f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -563,11 +563,6 @@ static void monitor_qapi_event_init(void)
     qmp_event_set_func_emit(monitor_qapi_event_queue);
 }
 
-void qmp_qmp_capabilities(Error **errp)
-{
-    cur_mon->qmp.in_command_mode = true;
-}
-
 static void handle_hmp_command(Monitor *mon, const char *cmdline);
 
 static void monitor_data_init(Monitor *mon)
@@ -995,7 +990,7 @@ static void qmp_unregister_commands_hack(void)
 #endif
 }
 
-void monitor_init_qmp_commands(void)
+static void monitor_init_real_qmp_commands(void)
 {
     qmp_init_marshal();
 
@@ -1009,6 +1004,32 @@ void monitor_init_qmp_commands(void)
     qmp_unregister_commands_hack();
 }
 
+void monitor_init_qmp_commands(void)
+{
+    /*
+     * Start with just qmp_capabilities, to enforce capability
+     * negotiation.  qmp_capabilities will register the other
+     * commands.  See also the error message replacement hack in
+     * handle_qmp_command().
+     */
+    qmp_register_command("qmp_capabilities",
+                         qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+}
+
+void qmp_qmp_capabilities(Error **errp)
+{
+    if (cur_mon->qmp.in_command_mode) {
+        error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+                  "Capabilities negotiation is already complete, command "
+                  "ignored");
+        return;
+    }
+
+    cur_mon->qmp.in_command_mode = true;
+    qmp_unregister_command("qmp_capabilities");
+    monitor_init_real_qmp_commands();
+}
+
 /* set the current CPU defined by the user */
 int monitor_set_cpu(int cpu_index)
 {
@@ -3676,26 +3697,6 @@ static int monitor_can_read(void *opaque)
     return (mon->suspend_cnt == 0) ? 1 : 0;
 }
 
-static bool invalid_qmp_mode(const Monitor *mon, const char *cmd,
-                             Error **errp)
-{
-    bool is_cap = g_str_equal(cmd, "qmp_capabilities");
-
-    if (is_cap && mon->qmp.in_command_mode) {
-        error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
-                  "Capabilities negotiation is already complete, command "
-                  "'%s' ignored", cmd);
-        return true;
-    }
-    if (!is_cap && !mon->qmp.in_command_mode) {
-        error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
-                  "Expecting capabilities negotiation with "
-                  "'qmp_capabilities' before command '%s'", cmd);
-        return true;
-    }
-    return false;
-}
-
 /*
  * Input object checking rules
  *
@@ -3781,12 +3782,21 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
     cmd_name = qdict_get_str(qdict, "execute");
     trace_handle_qmp_command(mon, cmd_name);
 
-    if (invalid_qmp_mode(mon, cmd_name, &err)) {
-        goto err_out;
-    }
-
     rsp = qmp_dispatch(req);
 
+    qdict = qdict_get_qdict(qobject_to_qdict(rsp), "error");
+    if (qdict) {
+        if (!mon->qmp.in_command_mode
+            && !g_strcmp0(qdict_get_try_str(qdict, "class"),
+                    QapiErrorClass_lookup[ERROR_CLASS_COMMAND_NOT_FOUND])) {
+            /* Provide a more useful error message */
+            qdict_del(qdict, "desc");
+            qdict_put(qdict, "desc",
+                      qstring_from_str("Expecting capabilities negotiation"
+                                       " with 'qmp_capabilities'"));
+        }
+    }
+
 err_out:
     if (err) {
         qdict = qdict_new();
-- 
2.7.4

  parent reply	other threads:[~2017-02-26 21:43 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-26 21:43 [Qemu-devel] [PATCH v2 00/26] qapi: QMP dispatch and input visitor work Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 01/26] qga: Fix crash on non-dictionary QMP argument Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 02/26] libqtest: Work around a "QMP wants a newline" bug Markus Armbruster
2017-02-27 16:36   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 03/26] qmp-test: New, covering basic QMP protocol Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 04/26] qmp: Dumb down how we run QMP command registration Markus Armbruster
2017-02-26 21:43 ` Markus Armbruster [this message]
2017-02-27 16:39   ` [Qemu-devel] [PATCH v2 05/26] qmp: Clean up how we enforce capability negotiation Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 06/26] qmp: Drop duplicated QMP command object checks Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 07/26] qmp: Eliminate silly QERR_QMP_* macros Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 08/26] qmp: Improve QMP dispatch error messages Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 09/26] qapi: Improve a QObject input visitor error message Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 10/26] qapi: Clean up after commit 3d344c2 Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 11/26] qapi: Make QObject input visitor set *list reliably Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 12/26] qapi: Improve qobject input visitor error reporting Markus Armbruster
2017-02-27 16:45   ` Eric Blake
2017-02-28  8:42     ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 13/26] qapi: Drop string input visitor method optional() Markus Armbruster
2017-02-27 16:46   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 14/26] qapi: Make string input and opts visitor require non-null input Markus Armbruster
2017-02-27 16:58   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 15/26] qom: Make object_property_set_qobject()'s input visitor strict Markus Armbruster
2017-02-27 19:25   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 16/26] test-qobject-input-visitor: Use strict visitor Markus Armbruster
2017-02-27 22:49   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 17/26] qapi: Drop unused non-strict qobject input visitor Markus Armbruster
2017-02-28 14:56   ` Eric Blake
2017-02-28 17:29     ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 18/26] tests-qobject-input-strict: Merge into test-qobject-input-visitor Markus Armbruster
2017-02-28 15:39   ` Eric Blake
2017-02-28 16:57     ` Markus Armbruster
2017-02-28 17:10       ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 19/26] test-string-input-visitor: Tear down existing test automatically Markus Armbruster
2017-02-28 15:44   ` Eric Blake
2017-02-28 16:08     ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 20/26] test-string-input-visitor: Improve list coverage Markus Armbruster
2017-02-28 15:47   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 21/26] tests: Cover partial input visit of list Markus Armbruster
2017-02-28 15:55   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 22/26] test-qobject-input-visitor: Cover missing nested struct member Markus Armbruster
2017-02-28 16:00   ` Eric Blake
2017-02-28 16:52     ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 23/26] qapi: Make input visitors detect unvisited list tails Markus Armbruster
2017-02-28 16:09   ` Eric Blake
2017-02-28 16:55     ` Markus Armbruster
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 24/26] tests: Cover input visit beyond end of list Markus Armbruster
2017-02-28 16:19   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 25/26] qapi: Fix object " Markus Armbruster
2017-02-28 16:20   ` Eric Blake
2017-02-26 21:43 ` [Qemu-devel] [PATCH v2 26/26] qapi: Improve qobject visitor documentation Markus Armbruster
2017-02-28 16:22   ` Eric Blake
2017-02-26 22:23 ` [Qemu-devel] [PATCH v2 00/26] qapi: QMP dispatch and input visitor work no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1488145424-14974-6-git-send-email-armbru@redhat.com \
    --to=armbru@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.