From: Markus Armbruster <armbru@redhat.com>
To: Bandan Das <bsd@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
qemu-devel@nongnu.org, Luiz Capitulino <lcapitulino@redhat.com>
Subject: Re: [Qemu-devel] [PATCH] monitor: suggest running "help" for command errors
Date: Thu, 14 May 2015 13:27:55 +0200 [thread overview]
Message-ID: <874mnf7610.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <jpgr3qk9oei.fsf_-_@redhat.com> (Bandan Das's message of "Wed, 13 May 2015 17:08:05 -0400")
Bandan Das <bsd@redhat.com> writes:
> When a command fails due to incorrect syntax or input,
> suggest using the "help" command to get more information
> about the command. This is only applicable for HMP.
>
> Before:
> (qemu) drive_add usb_flash_drive
> drive_add: string expected
> After:
> (qemu) drive_add usb_flash_drive
> drive_add: string expected
> Try "help drive_add" for more information
>
> Signed-off-by: Bandan Das <bsd@redhat.com>
> ---
> monitor.c | 28 +++++++++++++++++++---------
> 1 file changed, 19 insertions(+), 9 deletions(-)
>
> diff --git a/monitor.c b/monitor.c
> index b2561e1..46e8880 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -939,7 +939,7 @@ static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
> return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
> }
>
> -static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
> +static int user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
> const QDict *params)
> {
> int ret;
> @@ -954,6 +954,8 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
> monitor_resume(mon);
> g_free(cb_data);
> }
> +
> + return ret;
> }
>
user_async_cmd_handler() is unreachable since commit 3b5704b. I got
code cleaning that up in my tree. Don't worry about it.
> static void hmp_info_help(Monitor *mon, const QDict *qdict)
> @@ -3698,7 +3700,8 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
> const char *cmdline,
> int start,
> mon_cmd_t *table,
> - QDict *qdict)
> + QDict *qdict,
> + int *failed)
> {
> const char *p, *typestr;
> int c;
> @@ -3734,7 +3737,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
> return cmd;
> }
> return monitor_parse_command(mon, cmdline, p - cmdline,
> - cmd->sub_table, qdict);
> + cmd->sub_table, qdict, failed);
> }
>
> /* parse the parameters */
> @@ -4084,8 +4087,9 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
> return cmd;
>
> fail:
> + *failed = 1;
> g_free(key);
> - return NULL;
> + return cmd;
> }
>
>From the function's contract:
* If @cmdline is blank, return NULL.
* If it can't be parsed, report to @mon, and return NULL.
* Else, insert command arguments into @qdict, and return the command.
Your patch splits the "it can't be parsed" case into "command not found"
and "arguments can't be parsed", but neglects to update the contract.
Needs fixing. Perhaps like this:
* If @cmdline is blank, return NULL.
* If @cmdline doesn't start with a valid command name, report to @mon,
* and return NULL.
* Else, if the command's arguments can't be parsed, report to @mon,
* store 1 through @failed, and return the command.
* Else, insert command arguments into @qdict, and return the command.
The contract wasn't exactly pretty before, and I'm afraid it's
positively ugly now.
The common cause for such ugliness is doing too much in one function.
I'd try splitting into a command part and an argument part, so that
cmd = monitor_parse_command(mon, cmdline, start, table, qdict);
if (!cmd) {
// bail out
}
becomes something like
cmd = monitor_parse_command(mon, cmdline, start, table, &args);
if (!cmd) {
// bail out
}
qdict = monitor_parse_arguments(mon, cmd, args)
if (!qdict) {
// bail out
}
While I encourage you to do this, I won't reject your patch just because
you don't.
> void monitor_set_error(Monitor *mon, QError *qerror)
> @@ -4114,20 +4118,22 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
> {
> QDict *qdict;
> const mon_cmd_t *cmd;
> + int failed = 0;
>
> qdict = qdict_new();
>
> - cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table, qdict);
> - if (!cmd)
> + cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table,
> + qdict, &failed);
> + if (!cmd || failed) {
> goto out;
> + }
cmd implies !failed, therefore !cmd || failed == !cmd here. Why not
simply stick to if (!cmd)?
>
> if (handler_is_async(cmd)) {
> - user_async_cmd_handler(mon, cmd, qdict);
> + failed = user_async_cmd_handler(mon, cmd, qdict);
As discussed above: unreachable, but don't worry about it.
> } else if (handler_is_qobject(cmd)) {
This is the "new" HMP command interface. It's used only with drive_del,
device_add, client_migrate_info, pcie_aer_inject_error. The cleanup
work I mentioned above will get rid of it. Again, don't worry.
> QObject *data = NULL;
>
> - /* XXX: ignores the error code */
> - cmd->mhandler.cmd_new(mon, qdict, &data);
> + failed = cmd->mhandler.cmd_new(mon, qdict, &data);
> assert(!monitor_has_error(mon));
> if (data) {
> cmd->user_print(mon, data);
qobject_decref(data);
}
} else {
This is the traditional HMP command interface. Almost all commands use
it, and after my pending cleanup, it'll be the *only* HMP command
interface.
It lacks means to communicate command failure.
cmd->mhandler.cmd(mon, qdict);
}
Since you can't set failed in the common case, I recommend not to bother
setting it in the unreachable and the uncommon case, either.
> @@ -4138,6 +4144,10 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
> }
>
> out:
> + if (failed && cmd) {
Recommend (cmd && failed).
> + monitor_printf(mon, "Try \"help %s\" for more information\n",
> + cmd->name);
> + }
> QDECREF(qdict);
> }
Cases:
1. @cmdline is blank
cmd == NULL && !failed
We don't print command help. Good.
2. @cmdline isn't blank, command not found
cmd == NULL && !failed
We don't print command help. We already printed the error. Good.
3. command found, arguments can't be parsed
cmd != NULL && failed
We print command help. We printed the parse error already. Good.
4. command found, arguments parsed, command failed
cmd != NULL, but failed can be anything
We may or may not print command help. The command should've printed
an error already. Best we can do as long as the traditional HMP
command handler doesn't return status.
5. command found, arguments parsed, command succeeded
We don't print command help. Good.
Works.
next prev parent reply other threads:[~2015-05-14 11:28 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-12 21:37 [Qemu-devel] [PATCH] monitor: print help for command errors Bandan Das
2015-05-13 7:10 ` Markus Armbruster
2015-05-13 20:49 ` Bandan Das
2015-05-13 21:08 ` [Qemu-devel] [PATCH] monitor: suggest running "help" " Bandan Das
2015-05-14 11:27 ` Markus Armbruster [this message]
2015-05-15 4:37 ` Bandan Das
2015-05-15 11:29 ` Markus Armbruster
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=874mnf7610.fsf@blackfin.pond.sub.org \
--to=armbru@redhat.com \
--cc=bsd@redhat.com \
--cc=lcapitulino@redhat.com \
--cc=pbonzini@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.