[libvirt] [PATCH v3 2/3] virt-shell: Support command history for individual clients

Erik Skultety eskultet at redhat.com
Thu Aug 13 11:39:03 UTC 2015


By splitting generic parts from virsh we will need to preserve each client's
history, yet we use hardcoded names and paths. This patch fixes this
problem.
---
 src/libvirt_private.syms |  1 +
 src/util/virstring.c     | 32 +++++++++++++++++++++++++++++
 src/util/virstring.h     |  1 +
 tools/virsh.c            | 14 ++++++-------
 tools/vsh.c              | 52 +++++++++++++++++++++++++++++-------------------
 tools/vsh.h              |  5 ++++-
 6 files changed, 76 insertions(+), 29 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 45f42f5..e2140e4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2187,6 +2187,7 @@ virStringSplit;
 virStringSplitCount;
 virStringStripControlChars;
 virStringStripIPv6Brackets;
+virStringToUpper;
 virStrncpy;
 virStrndup;
 virStrToDouble;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 5794f96..4f0afe9 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -1020,3 +1020,35 @@ virStringStripControlChars(char *str)
     }
     str[j] = '\0';
 }
+
+/**
+ * virStringToUpper:
+ * @str: string to capitalize
+ * @dst: where to store the new capitalized string
+ *
+ * Capitalize the string with replacement of all '-' characters for '_'
+ * characters. Caller frees the result.
+ *
+ * Returns 0 if src is NULL, 1 if capitalization was successfull, -1 on failure.
+ */
+int
+virStringToUpper(char **dst, const char *src)
+{
+    char *cap = NULL;
+    size_t i;
+
+    if (!src)
+        return 0;
+
+    if (VIR_ALLOC_N(cap, strlen(src) + 1) < 0)
+        return -1;
+
+    for (i = 0; src[i]; i++) {
+        cap[i] = c_toupper(src[i]);
+        if (cap[i] == '-')
+            cap[i] = '_';
+    }
+
+    *dst = cap;
+    return 1;
+}
diff --git a/src/util/virstring.h b/src/util/virstring.h
index e6dcb32..9848fb6 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -258,6 +258,7 @@ size_t virStringListLength(char **strings);
 
 int virStringSortCompare(const void *a, const void *b);
 int virStringSortRevCompare(const void *a, const void *b);
+int virStringToUpper(char **dst, const char *src);
 
 ssize_t virStringSearch(const char *str,
                         const char *regexp,
diff --git a/tools/virsh.c b/tools/virsh.c
index 9f9e1d3..2d198cd 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -33,7 +33,6 @@
 #include <errno.h>
 #include <getopt.h>
 #include <sys/time.h>
-#include "c-ctype.h"
 #include <fcntl.h>
 #include <locale.h>
 #include <time.h>
@@ -169,7 +168,7 @@ virshReconnect(vshControl *ctl)
                                   "disconnect from the hypervisor"));
     }
 
-    priv->conn = virshConnect(ctl, ctl->name, priv->readonly);
+    priv->conn = virshConnect(ctl, ctl->connname, priv->readonly);
 
     if (!priv->conn) {
         if (disconnected)
@@ -629,7 +628,7 @@ virshInit(vshControl *ctl)
                                                 NULL)) < 0)
         return false;
 
-    if (ctl->name) {
+    if (ctl->connname) {
         virshReconnect(ctl);
         /* Connecting to a named connection must succeed, but we delay
          * connecting to the default connection until we need it
@@ -661,7 +660,7 @@ virshDeinit(vshControl *ctl)
     virshControlPtr priv = ctl->privData;
 
     vshDeinit(ctl);
-    VIR_FREE(ctl->name);
+    VIR_FREE(ctl->connname);
     if (priv->conn) {
         int ret;
         virConnectUnregisterCloseCallback(priv->conn, virshCatchDisconnect);
@@ -937,8 +936,8 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
     while ((arg = getopt_long(argc, argv, "+:c:d:e:hk:K:l:qrtvV", opt, &longindex)) != -1) {
         switch (arg) {
         case 'c':
-            VIR_FREE(ctl->name);
-            ctl->name = vshStrdup(ctl, optarg);
+            VIR_FREE(ctl->connname);
+            ctl->connname = vshStrdup(ctl, optarg);
             break;
         case 'd':
             if (virStrToLong_i(optarg, NULL, 10, &debug) < 0) {
@@ -1137,6 +1136,7 @@ main(int argc, char **argv)
 
     memset(ctl, 0, sizeof(vshControl));
     memset(&virshCtl, 0, sizeof(virshControl));
+    ctl->name = "virsh";        /* hardcoded name of the binary */
     ctl->imode = true;          /* default is interactive mode */
     ctl->log_fd = -1;           /* Initialize log file descriptor */
     ctl->debug = VSH_DEBUG_DEFAULT;
@@ -1193,7 +1193,7 @@ main(int argc, char **argv)
     virFileActivateDirOverride(argv[0]);
 
     if ((defaultConn = virGetEnvBlockSUID("VIRSH_DEFAULT_CONNECT_URI")))
-        ctl->name = vshStrdup(ctl, defaultConn);
+        ctl->connname = vshStrdup(ctl, defaultConn);
 
     if (vshInit(ctl, cmdGroups, NULL) < 0)
         exit(EXIT_FAILURE);
diff --git a/tools/vsh.c b/tools/vsh.c
index 62f57ca..043d0fb 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -2543,36 +2543,46 @@ vshReadlineCompletion(const char *text, int start,
     return matches;
 }
 
-# define VIRTSHELL_HISTSIZE_MAX 500000
+# define HISTSIZE_MAX 500000
 
 static int
 vshReadlineInit(vshControl *ctl)
 {
     char *userdir = NULL;
+    char *name_capitalized = NULL;
     int max_history = 500;
-    const char *histsize_str;
+    int ret = -1;
+    const char *histsize_str = NULL;
+    const char *histsize_env = NULL;
+    const char *strings[] = {
+        name_capitalized,
+        "HISTSIZE",
+        NULL
+    };
 
     /* Allow conditional parsing of the ~/.inputrc file.
      * Work around ancient readline 4.1 (hello Mac OS X),
      * which declared it as 'char *' instead of 'const char *'.
      */
-    rl_readline_name = (char *) "virtshell";
+    rl_readline_name = ctl->name;
 
     /* Tell the completer that we want a crack first. */
     rl_attempted_completion_function = vshReadlineCompletion;
 
+    if (virStringToUpper(&name_capitalized, ctl->name) < 0 ||
+        !(histsize_env = virStringJoin(strings, "_")))
+        goto cleanup;
+
     /* Limit the total size of the history buffer */
-    if ((histsize_str = virGetEnvBlockSUID("VIRTSHELL_HISTSIZE"))) {
+    if ((histsize_str = virGetEnvBlockSUID(histsize_env))) {
         if (virStrToLong_i(histsize_str, NULL, 10, &max_history) < 0) {
-            vshError(ctl, "%s", _("Bad $VIRTSHELL_HISTSIZE value."));
-            VIR_FREE(userdir);
-            return -1;
-        } else if (max_history > VIRTSHELL_HISTSIZE_MAX || max_history < 0) {
-            vshError(ctl, _("$VIRTSHELL_HISTSIZE value should be between 0 "
+            vshError(ctl, _("Bad $%s value."), histsize_env);
+            goto cleanup;
+        } else if (max_history > HISTSIZE_MAX || max_history < 0) {
+            vshError(ctl, _("$%s value should be between 0 "
                             "and %d"),
-                     VIRTSHELL_HISTSIZE_MAX);
-            VIR_FREE(userdir);
-            return -1;
+                     histsize_env, HISTSIZE_MAX);
+            goto cleanup;
         }
     }
     stifle_history(max_history);
@@ -2584,26 +2594,26 @@ vshReadlineInit(vshControl *ctl)
 
     if (userdir == NULL) {
         vshError(ctl, "%s", _("Could not determine home directory"));
-        return -1;
+        goto cleanup;
     }
 
-    if (virAsprintf(&ctl->historydir, "%s/virtshell", userdir) < 0) {
+    if (virAsprintf(&ctl->historydir, "%s/%s", userdir, ctl->name) < 0) {
         vshError(ctl, "%s", _("Out of memory"));
-        VIR_FREE(userdir);
-        return -1;
+        goto cleanup;
     }
 
     if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
         vshError(ctl, "%s", _("Out of memory"));
-        VIR_FREE(userdir);
-        return -1;
+        goto cleanup;
     }
 
-    VIR_FREE(userdir);
-
     read_history(ctl->historyfile);
+    ret = 0;
 
-    return 0;
+ cleanup:
+    VIR_FREE(userdir);
+    VIR_FREE(name_capitalized);
+    return ret;
 }
 
 static void
diff --git a/tools/vsh.h b/tools/vsh.h
index ecf52e9..19862d0 100644
--- a/tools/vsh.h
+++ b/tools/vsh.h
@@ -194,7 +194,10 @@ struct _vshCmd {
  * vshControl
  */
 struct _vshControl {
-    char *name;                 /* connection name */
+    const char *name;           /* hardcoded name of the binary that cannot
+                                 * be changed without recompilation compared
+                                 * to program name */
+    char *connname;             /* connection name */
     char *progname;             /* program name */
     vshCmd *cmd;                /* the current command */
     char *cmdstr;               /* string with command */
-- 
2.4.3




More information about the libvir-list mailing list