[libvirt] [PATCH] virsh: Allow other escape characters for console

Michal Privoznik mprivozn at redhat.com
Tue Nov 22 16:18:00 UTC 2011


Currently virsh supports only ^] as escape character for console.
However, some users might want to use something else. This patch
creates such ability by specifying '-e' switch on virsh command
line.
---
Okay, this patch is meant as RFC mainly but if it got enough ACKs
I will not hesitate to push it. My biggest concern is the way
of telling virsh customized sequence. I am not big fan of new switch,
however we lack virsh.conf in $conf_dir. Maybe it is the right time
for creating it.
Another approach is to pass the sequence as parameter directly to
'console' command.

What's your opinion?

 tools/console.c |   28 +++++++++++++++++++++++-----
 tools/console.h |    4 +++-
 tools/virsh.c   |   20 ++++++++++++++++----
 tools/virsh.pod |    5 +++++
 4 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/tools/console.c b/tools/console.c
index 0f85bc7..db2e17e 100644
--- a/tools/console.c
+++ b/tools/console.c
@@ -43,9 +43,13 @@
 # include "memory.h"
 # include "virterror_internal.h"
 
-
-/* ie  Ctrl-]  as per telnet */
-# define CTRL_CLOSE_BRACKET '\35'
+/*
+ * Convert given character to control character.
+ * Basically, we take lower 5 bits unless given
+ * character is DEL (represented by '?'). Then
+ * we return 127
+ */
+# define CONTROL(c) ((c) == '?' ? ((c) | 0x40) : ((c) & 0x1f))
 
 # define VIR_FROM_THIS VIR_FROM_NONE
 
@@ -66,6 +70,8 @@ struct virConsole {
 
     struct virConsoleBuffer streamToTerminal;
     struct virConsoleBuffer terminalToStream;
+
+    char escapeChar;
 };
 
 static int got_signal = 0;
@@ -215,7 +221,7 @@ virConsoleEventOnStdin(int watch ATTRIBUTE_UNUSED,
             virConsoleShutdown(con);
             return;
         }
-        if (con->terminalToStream.data[con->terminalToStream.offset] == CTRL_CLOSE_BRACKET) {
+        if (con->terminalToStream.data[con->terminalToStream.offset] == con->escapeChar) {
             virConsoleShutdown(con);
             return;
         }
@@ -278,7 +284,18 @@ virConsoleEventOnStdout(int watch ATTRIBUTE_UNUSED,
 }
 
 
-int vshRunConsole(virDomainPtr dom, const char *dev_name)
+static char
+vshGetEscapeChar(const char *s)
+{
+    if (*s == '^')
+        return CONTROL(s[1]);
+
+    return *s;
+}
+
+int vshRunConsole(virDomainPtr dom,
+                  const char *dev_name,
+                  const char *escape_seq)
 {
     int ret = -1;
     struct termios ttyattr, rawattr;
@@ -326,6 +343,7 @@ int vshRunConsole(virDomainPtr dom, const char *dev_name)
         goto cleanup;
     }
 
+    con->escapeChar = vshGetEscapeChar(escape_seq);
     con->st = virStreamNew(virDomainGetConnect(dom),
                            VIR_STREAM_NONBLOCK);
     if (!con->st)
diff --git a/tools/console.h b/tools/console.h
index 9b05ff1..8cca08f 100644
--- a/tools/console.h
+++ b/tools/console.h
@@ -25,7 +25,9 @@
 
 # ifndef WIN32
 
-int vshRunConsole(virDomainPtr dom, const char *dev_name);
+int vshRunConsole(virDomainPtr dom,
+                  const char *dev_name,
+                  const char *escape_seq);
 
 # endif /* !WIN32 */
 
diff --git a/tools/virsh.c b/tools/virsh.c
index 89fb4e7..1b84980 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -75,6 +75,9 @@ static char *progname;
         ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
           ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
 
+/* Default escape char Ctrl-] as per telnet */
+#define CTRL_CLOSE_BRACKET "^]"
+
 /**
  * The log configuration
  */
@@ -249,6 +252,7 @@ typedef struct __vshControl {
                                    virDomainGetState is not supported */
     bool useSnapshotOld;        /* cannot use virDomainSnapshotGetParent or
                                    virDomainSnapshotNumChildren */
+    const char *escapeChar;     /* Escape character for domain console */
 } __vshControl;
 
 typedef struct vshCmdGrp {
@@ -796,8 +800,8 @@ cmdRunConsole(vshControl *ctl, virDomainPtr dom, const char *name)
     }
 
     vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
-    vshPrintExtra(ctl, "%s", _("Escape character is ^]\n"));
-    if (vshRunConsole(dom, name) == 0)
+    vshPrintExtra(ctl, _("Escape character is %s\n"), ctl->escapeChar);
+    if (vshRunConsole(dom, name, ctl->escapeChar) == 0)
         ret = true;
 
  cleanup:
@@ -16817,6 +16821,7 @@ vshDeinit(vshControl *ctl)
     vshReadlineDeinit(ctl);
     vshCloseLogFile(ctl);
     VIR_FREE(ctl->name);
+    VIR_FREE(ctl->escapeChar);
     if (ctl->conn) {
         int ret;
         if ((ret = virConnectClose(ctl->conn)) != 0) {
@@ -16848,7 +16853,8 @@ vshUsage(void)
                       "    -t | --timing           print timing information\n"
                       "    -l | --log <file>       output logging to file\n"
                       "    -v | --version[=short]  program version\n"
-                      "    -V | --version=long     version and full options\n\n"
+                      "    -V | --version=long     version and full options\n"
+                      "    -e | --escape <char>    set escape sequence for console\n\n"
                       "  commands (non interactive mode):\n\n"), progname, progname);
 
     for (grp = cmdGroups; grp->name; grp++) {
@@ -17009,13 +17015,14 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
         {"connect", required_argument, NULL, 'c'},
         {"readonly", no_argument, NULL, 'r'},
         {"log", required_argument, NULL, 'l'},
+        {"escape", required_argument, NULL, 'e'},
         {NULL, 0, NULL, 0}
     };
 
     /* Standard (non-command) options. The leading + ensures that no
      * argument reordering takes place, so that command options are
      * not confused with top-level virsh options. */
-    while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:", opt, NULL)) != -1) {
+    while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) {
         switch (arg) {
         case 'd':
             if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
@@ -17050,6 +17057,9 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
         case 'l':
             ctl->logfile = vshStrdup(ctl, optarg);
             break;
+        case 'e':
+            ctl->escapeChar = vshStrdup(ctl, optarg);
+            break;
         default:
             vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
             exit(EXIT_FAILURE);
@@ -17091,6 +17101,8 @@ main(int argc, char **argv)
     ctl->imode = true;          /* default is interactive mode */
     ctl->log_fd = -1;           /* Initialize log file descriptor */
     ctl->debug = VSH_DEBUG_DEFAULT;
+    ctl->escapeChar = vshStrdup(ctl, CTRL_CLOSE_BRACKET);
+
 
     if (!setlocale(LC_ALL, "")) {
         perror("setlocale");
diff --git a/tools/virsh.pod b/tools/virsh.pod
index db872dd..08b761d 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -92,6 +92,11 @@ option of the B<connect> command.
 
 Output elapsed time information for each command.
 
+=item B<-e>, B<--escape> I<string>
+
+Set alternative escape sequence for I<console> command. By default,
+telnet's ^] is used.
+
 =back
 
 =head1 NOTES
-- 
1.7.3.4




More information about the libvir-list mailing list