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