[libvirt] [RFC PATCH] virsh: new echo command

Eric Blake eblake at redhat.com
Tue Oct 12 23:39:24 UTC 2010


* tools/virsh.c (cmdEcho): New command.
(commands): Add it.
(vshCmdOptType): Add VSH_OT_ARGV.
(vshCmddefGetData): Special case new opt flag.
(vshCommandOptArgv): New function.
---

Not complete yet, but this shows what I'm thinking of.  Adding the
echo command has two benefits:

1. It will let me add unit tests for the recent virsh command line
improvements - echo back arbitrary strings to make sure quoting is as
desired.  This part works with what I have here, before I ran out of
time to finish this today.

2. Make it easier for a user on the command line to conver an
arbitrary string into something safe for shell evalution and/or XML
usage, by munging the input in a way that it can be reused in the
desired context.  Not yet implemented; hence the RFC.

It exploits the fact that "--" is consumed as the end-of-options,
hence, there is no way for "" to be recognized as a valid option
name, so the only way we can encounter VSH_OT_ARGV is via the
new argv handling, at which point we can handle all remaining
command line arguments.

 tools/virsh.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 89c2e1e..f361658 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -119,11 +119,12 @@ typedef enum {
  * vshCmdOptType - command option type
  */
 typedef enum {
-    VSH_OT_NONE = 0,            /* none */
-    VSH_OT_BOOL,                /* boolean option */
-    VSH_OT_STRING,              /* string option */
-    VSH_OT_INT,                 /* int option */
-    VSH_OT_DATA                 /* string data (as non-option) */
+    VSH_OT_NONE = 0, /* none */
+    VSH_OT_BOOL,     /* boolean option */
+    VSH_OT_STRING,   /* string option */
+    VSH_OT_INT,      /* int option */
+    VSH_OT_DATA,     /* string data (as non-option) */
+    VSH_OT_ARGV      /* remaining arguments, opt->name should be "" */
 } vshCmdOptType;

 /*
@@ -230,6 +231,7 @@ static char *vshCommandOptString(const vshCmd *cmd, const char *name,
 static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name,
                                        int *found);
 static int vshCommandOptBool(const vshCmd *cmd, const char *name);
+static char *vshCommandOptArgv(const vshCmd *cmd, int count);

 #define VSH_BYID     (1 << 1)
 #define VSH_BYUUID   (1 << 2)
@@ -8917,6 +8919,54 @@ cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
 #endif

 /*
+ * "echo" command
+ */
+static const vshCmdInfo info_echo[] = {
+    {"help", N_("echo arguments")},
+    {"desc", N_("Echo back arguments, possibly with quoting.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_echo[] = {
+    {"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
+    {"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
+    {"", VSH_OT_ARGV, 0, N_("arguments to echo")},
+    {NULL, 0, 0, NULL}
+};
+
+/* Exists mainly for debugging virsh, but also handy for adding back
+ * quotes for later evaluation.
+ */
+static int
+cmdEcho (vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd)
+{
+    bool shell = false;
+    bool xml = false;
+    int count = 0;
+    char *arg;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (vshCommandOptBool(cmd, "shell"))
+        shell = true;
+    if (vshCommandOptBool(cmd, "xml"))
+        xml = true;
+
+    while ((arg = vshCommandOptArgv(cmd, count)) != NULL) {
+        /* TODO - use buf */
+        if (xml) {
+            /* TODO - use virBufferEscapeString */
+        }
+        if (shell) {
+            /* TODO - add '' and escape embedded ' */
+        }
+        vshPrint(ctl, "%s%s", count ? " " : "", arg);
+        count++;
+    }
+
+    return TRUE;
+}
+
+/*
  * "edit" command
  */
 static const vshCmdInfo info_edit[] = {
@@ -9545,6 +9595,7 @@ static const vshCmdDef commands[] = {
     {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
     {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
     {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
+    {"echo", cmdEcho, opts_echo, info_echo},
     {"edit", cmdEdit, opts_edit, info_edit},
     {"find-storage-pool-sources", cmdPoolDiscoverSources,
      opts_find_storage_pool_sources, info_find_storage_pool_sources},
@@ -9707,8 +9758,8 @@ vshCmddefGetData(const vshCmdDef * cmd, int data_ct)
     const vshCmdOptDef *opt;

     for (opt = cmd->opts; opt && opt->name; opt++) {
-        if (opt->type == VSH_OT_DATA) {
-            if (data_ct == 0)
+        if (opt->type >= VSH_OT_DATA) {
+            if (data_ct == 0 || opt->type == VSH_OT_ARGV)
                 return opt;
             else
                 data_ct--;
@@ -9970,6 +10021,27 @@ vshCommandOptBool(const vshCmd *cmd, const char *name)
     return vshCommandOpt(cmd, name) ? TRUE : FALSE;
 }

+/*
+ * Returns the COUNT argv argument, or NULL after last argument.
+ *
+ * Requires that a VSH_OT_ARGV option with the name "" be last in the
+ * list of supported options in CMD->def->opts.
+ */
+static char *
+vshCommandOptArgv(const vshCmd *cmd, int count)
+{
+    vshCmdOpt *opt = cmd->opts;
+
+    while (opt) {
+        if (opt->def && opt->def->type == VSH_OT_ARGV) {
+            if (count-- == 0)
+                return opt->data;
+        }
+        opt = opt->next;
+    }
+    return NULL;
+}
+
 /* Determine whether CMD->opts includes an option with name OPTNAME.
    If not, give a diagnostic and return false.
    If so, return true.  */
-- 
1.7.2.3




More information about the libvir-list mailing list