Old virsh command parsing mashes all the args back into a string and
miss the quotes, this patches fix it. It is also needed for introducing
qemu-monitor-command which is very useful.
This patches uses the new vrshCommandParser abstraction and adds
vshCommandArgvParse() for arguments vector, so we don't need
to mash arguments vector into a command sting.
And the usage was changed:
old:
virsh [options] [commands]
new:
virsh [options]... [<command_string>]
virsh [options]... <command> [args...]
So we still support commands like:
# virsh "define D.xml; dumpxml D"
"define D.xml; dumpxml D" was parsed as a commands-string.
and support commands like:
# virsh qemu-monitor-command f13guest "info cpus"
we will not mash them into a string, we use new argv parser for it.
But we don't support the command like:
# virsh "define D.xml; dumpxml" D
"define D.xml; dumpxml" was parsed as a command-name, but we have no such
command-name.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
virsh.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 27321a5..9fd0602 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10165,12 +10165,47 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
typedef struct __vshCommandParser {
int (*getNextArg)(vshControl *, struct __vshCommandParser *, char **);
+ /* vshCommandStringGetArg() */
char *pos;
+ /* vshCommandArgvGetArg() */
+ char **arg_pos;
+ char **arg_end;
} vshCommandParser;
static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);
/* ---------------
+ * Command argv parsing
+ * ---------------
+ */
+
+static int
+vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
+{
+ if (parser->arg_pos == parser->arg_end) {
+ *res = NULL;
+ return VSH_TK_END;
+ }
+
+ *res = vshStrdup(ctl, *parser->arg_pos);
+ parser->arg_pos++;
+ return VSH_TK_ARG;
+}
+
+static int vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
+{
+ vshCommandParser parser;
+
+ if (nargs <= 0)
+ return FALSE;
+
+ parser.arg_pos = argv;
+ parser.arg_end = argv + nargs;
+ parser.getNextArg = vshCommandArgvGetArg;
+ return vshCommandParse(ctl, &parser);
+}
+
+/* ---------------
* Command string parsing
* ---------------
*/
@@ -10939,7 +10974,8 @@ static void
vshUsage(void)
{
const vshCmdDef *cmd;
- fprintf(stdout, _("\n%s [options] [commands]\n\n"
+ fprintf(stdout, _("\n%s [options]... [<command_string>]"
+ "\n%s [options]... <command> [args...]\n\n"
" options:\n"
" -c | --connect <uri> hypervisor connection
URI\n"
" -r | --readonly connect readonly\n"
@@ -10949,7 +10985,7 @@ vshUsage(void)
" -t | --timing print timing information\n"
" -l | --log <file> output logging to
file\n"
" -v | --version program version\n\n"
- " commands (non interactive mode):\n"), progname);
+ " commands (non interactive mode):\n"), progname,
progname);
for (cmd = commands; cmd->name; cmd++)
fprintf(stdout,
@@ -11069,26 +11105,13 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
if (argc > end) {
/* parse command */
- char *cmdstr;
- int sz = 0, ret;
-
ctl->imode = FALSE;
-
- for (i = end; i < argc; i++)
- sz += strlen(argv[i]) + 1; /* +1 is for blank space between items */
-
- cmdstr = vshCalloc(ctl, sz + 1, 1);
-
- for (i = end; i < argc; i++) {
- strncat(cmdstr, argv[i], sz);
- sz -= strlen(argv[i]);
- strncat(cmdstr, " ", sz--);
+ if (argc - end == 1) {
+ vshDebug(ctl, 2, "commands: \"%s\"\n", argv[end]);
+ return vshCommandStringParse(ctl, argv[end]);
+ } else {
+ return vshCommandArgvParse(ctl, argc - end, argv + end);
}
- vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
- ret = vshCommandStringParse(ctl, cmdstr);
-
- VIR_FREE(cmdstr);
- return ret;
}
return TRUE;
}