virsh: Allow other escape characters for console

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.
This commit is contained in:
Michal Privoznik 2011-11-22 17:08:05 +01:00
parent 0763a26dfe
commit 7a79648532
4 changed files with 61 additions and 15 deletions

View File

@ -44,9 +44,11 @@
# include "threads.h" # include "threads.h"
# include "virterror_internal.h" # include "virterror_internal.h"
/*
/* ie Ctrl-] as per telnet */ * Convert given character to control character.
# define CTRL_CLOSE_BRACKET '\35' * Basically, we assume ASCII, and take lower 6 bits.
*/
# define CONTROL(c) ((c) ^ 0x40)
# define VIR_FROM_THIS VIR_FROM_NONE # define VIR_FROM_THIS VIR_FROM_NONE
@ -69,6 +71,8 @@ struct virConsole {
struct virConsoleBuffer streamToTerminal; struct virConsoleBuffer streamToTerminal;
struct virConsoleBuffer terminalToStream; struct virConsoleBuffer terminalToStream;
char escapeChar;
}; };
static int got_signal = 0; static int got_signal = 0;
@ -219,7 +223,7 @@ virConsoleEventOnStdin(int watch ATTRIBUTE_UNUSED,
virConsoleShutdown(con); virConsoleShutdown(con);
return; return;
} }
if (con->terminalToStream.data[con->terminalToStream.offset] == CTRL_CLOSE_BRACKET) { if (con->terminalToStream.data[con->terminalToStream.offset] == con->escapeChar) {
virConsoleShutdown(con); virConsoleShutdown(con);
return; return;
} }
@ -282,7 +286,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; int ret = -1;
struct termios ttyattr, rawattr; struct termios ttyattr, rawattr;
@ -330,6 +345,7 @@ int vshRunConsole(virDomainPtr dom, const char *dev_name)
goto cleanup; goto cleanup;
} }
con->escapeChar = vshGetEscapeChar(escape_seq);
con->st = virStreamNew(virDomainGetConnect(dom), con->st = virStreamNew(virDomainGetConnect(dom),
VIR_STREAM_NONBLOCK); VIR_STREAM_NONBLOCK);
if (!con->st) if (!con->st)

View File

@ -25,7 +25,9 @@
# ifndef WIN32 # ifndef WIN32
int vshRunConsole(virDomainPtr dom, const char *dev_name); int vshRunConsole(virDomainPtr dom,
const char *dev_name,
const char *escape_seq);
# endif /* !WIN32 */ # endif /* !WIN32 */

View File

@ -76,6 +76,9 @@ static char *progname;
((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \ ((((int) ((T)->tv_sec - (U)->tv_sec)) * 1000000.0 + \
((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0) ((int) ((T)->tv_usec - (U)->tv_usec))) / 1000.0)
/* Default escape char Ctrl-] as per telnet */
#define CTRL_CLOSE_BRACKET "^]"
/** /**
* The log configuration * The log configuration
*/ */
@ -254,6 +257,9 @@ typedef struct __vshControl {
virMutex lock; virMutex lock;
bool eventLoopStarted; bool eventLoopStarted;
bool quit; bool quit;
const char *escapeChar; /* String representation of
console escape character */
} __vshControl; } __vshControl;
typedef struct vshCmdGrp { typedef struct vshCmdGrp {
@ -801,8 +807,8 @@ cmdRunConsole(vshControl *ctl, virDomainPtr dom, const char *name)
} }
vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom)); vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom));
vshPrintExtra(ctl, "%s", _("Escape character is ^]\n")); vshPrintExtra(ctl, _("Escape character is %s\n"), ctl->escapeChar);
if (vshRunConsole(dom, name) == 0) if (vshRunConsole(dom, name, ctl->escapeChar) == 0)
ret = true; ret = true;
cleanup: cleanup:
@ -17544,15 +17550,17 @@ vshUsage(void)
fprintf(stdout, _("\n%s [options]... [<command_string>]" fprintf(stdout, _("\n%s [options]... [<command_string>]"
"\n%s [options]... <command> [args...]\n\n" "\n%s [options]... <command> [args...]\n\n"
" options:\n" " options:\n"
" -c | --connect <uri> hypervisor connection URI\n" " -c | --connect=URI hypervisor connection URI\n"
" -r | --readonly connect readonly\n" " -r | --readonly connect readonly\n"
" -d | --debug <num> debug level [0-4]\n" " -d | --debug=NUM debug level [0-4]\n"
" -h | --help this help\n" " -h | --help this help\n"
" -q | --quiet quiet mode\n" " -q | --quiet quiet mode\n"
" -t | --timing print timing information\n" " -t | --timing print timing information\n"
" -l | --log <file> output logging to file\n" " -l | --log=FILE output logging to file\n"
" -v | --version[=short] program version\n" " -v short version\n"
" -V | --version=long version and full options\n\n" " -V long version\n"
" --version[=TYPE] version, TYPE is short or long (default short)\n"
" -e | --escape <char> set escape sequence for console\n\n"
" commands (non interactive mode):\n\n"), progname, progname); " commands (non interactive mode):\n\n"), progname, progname);
for (grp = cmdGroups; grp->name; grp++) { for (grp = cmdGroups; grp->name; grp++) {
@ -17703,7 +17711,7 @@ static bool
vshParseArgv(vshControl *ctl, int argc, char **argv) vshParseArgv(vshControl *ctl, int argc, char **argv)
{ {
bool help = false; bool help = false;
int arg; int arg, len;
struct option opt[] = { struct option opt[] = {
{"debug", required_argument, NULL, 'd'}, {"debug", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
@ -17713,13 +17721,14 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
{"connect", required_argument, NULL, 'c'}, {"connect", required_argument, NULL, 'c'},
{"readonly", no_argument, NULL, 'r'}, {"readonly", no_argument, NULL, 'r'},
{"log", required_argument, NULL, 'l'}, {"log", required_argument, NULL, 'l'},
{"escape", required_argument, NULL, 'e'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
/* Standard (non-command) options. The leading + ensures that no /* Standard (non-command) options. The leading + ensures that no
* argument reordering takes place, so that command options are * argument reordering takes place, so that command options are
* not confused with top-level virsh options. */ * 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) { switch (arg) {
case 'd': case 'd':
if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) {
@ -17754,6 +17763,18 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
case 'l': case 'l':
ctl->logfile = vshStrdup(ctl, optarg); ctl->logfile = vshStrdup(ctl, optarg);
break; break;
case 'e':
len = strlen(optarg);
if ((len == 2 && *optarg == '^') ||
(len == 1 && *optarg != '^')) {
ctl->escapeChar = optarg;
} else {
vshError(ctl, _("Invalid string '%s' for escape sequence"),
optarg);
exit(EXIT_FAILURE);
}
break;
default: default:
vshError(ctl, _("unsupported option '-%c'. See --help."), arg); vshError(ctl, _("unsupported option '-%c'. See --help."), arg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -17795,6 +17816,8 @@ main(int argc, char **argv)
ctl->imode = true; /* default is interactive mode */ ctl->imode = true; /* default is interactive mode */
ctl->log_fd = -1; /* Initialize log file descriptor */ ctl->log_fd = -1; /* Initialize log file descriptor */
ctl->debug = VSH_DEBUG_DEFAULT; ctl->debug = VSH_DEBUG_DEFAULT;
ctl->escapeChar = CTRL_CLOSE_BRACKET;
if (!setlocale(LC_ALL, "")) { if (!setlocale(LC_ALL, "")) {
perror("setlocale"); perror("setlocale");

View File

@ -92,6 +92,11 @@ option of the B<connect> command.
Output elapsed time information for each 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 B<^]> is used.
=back =back
=head1 NOTES =head1 NOTES