This patch adds a "remote netcat" functionality using for example: virsh tcp-console --host localhost --port 1234 --ipv4 --- tools/console.c | 66 ++++++++++++++++++++++++++++------------------------ tools/console.h | 9 ++----- tools/virsh-domain.c | 17 +++++++++++--- tools/virsh-host.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 40 deletions(-) diff --git a/tools/console.c b/tools/console.c index 40de8eb..e4e4fd7 100644 --- a/tools/console.c +++ b/tools/console.c @@ -325,38 +325,46 @@ vshMakeStdinRaw(struct termios *ttyattr, bool report_errors) return 0; } -int vshRunConsole(virDomainPtr dom, - const char *dev_name, - const char *escape_seq, - unsigned int flags) +int +vshRunConsole(virStreamPtr st, + const char *escape_seq, + bool raw) { int ret = -1; struct termios ttyattr; - void (*old_sigquit)(int); - void (*old_sigterm)(int); - void (*old_sigint)(int); - void (*old_sighup)(int); - void (*old_sigpipe)(int); + void (*old_sigquit)(int) = NULL; + void (*old_sigterm)(int) = NULL; + void (*old_sigint)(int) = NULL; + void (*old_sighup)(int) = NULL; + void (*old_sigpipe)(int) = NULL; virConsolePtr con = NULL; + if (!st) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid stream")); + return -1; + } + /* Put STDIN into raw mode so that stuff typed does not echo to the screen (the TTY reads will result in it being echoed back already), and also ensure Ctrl-C, etc is blocked, and misc other bits */ - if (vshMakeStdinRaw(&ttyattr, true) < 0) + if (raw && vshMakeStdinRaw(&ttyattr, true) < 0) goto resettty; /* Trap all common signals so that we can safely restore the original terminal settings on STDIN before the process exits - people don't like being left with a messed up terminal ! */ - old_sigquit = signal(SIGQUIT, do_signal); - old_sigterm = signal(SIGTERM, do_signal); - old_sigint = signal(SIGINT, do_signal); - old_sighup = signal(SIGHUP, do_signal); - old_sigpipe = signal(SIGPIPE, do_signal); - got_signal = 0; + if (raw) { + old_sigquit = signal(SIGQUIT, do_signal); + old_sigterm = signal(SIGTERM, do_signal); + old_sigint = signal(SIGINT, do_signal); + old_sighup = signal(SIGHUP, do_signal); + old_sigpipe = signal(SIGPIPE, do_signal); + got_signal = 0; + } if (VIR_ALLOC(con) < 0) { virReportOOMError(); @@ -364,13 +372,8 @@ int vshRunConsole(virDomainPtr dom, } con->escapeChar = vshGetEscapeChar(escape_seq); - con->st = virStreamNew(virDomainGetConnect(dom), - VIR_STREAM_NONBLOCK); - if (!con->st) - goto cleanup; - - if (virDomainOpenConsole(dom, dev_name, con->st, flags) < 0) - goto cleanup; + virStreamRef(st); + con->st = st; if (virCondInit(&con->cond) < 0 || virMutexInit(&con->lock) < 0) goto cleanup; @@ -411,17 +414,20 @@ int vshRunConsole(virDomainPtr dom, VIR_FREE(con); } - /* Restore original signal handlers */ - signal(SIGPIPE, old_sigpipe); - signal(SIGHUP, old_sighup); - signal(SIGINT, old_sigint); - signal(SIGTERM, old_sigterm); - signal(SIGQUIT, old_sigquit); + if (raw) { + /* Restore original signal handlers */ + signal(SIGPIPE, old_sigpipe); + signal(SIGHUP, old_sighup); + signal(SIGINT, old_sigint); + signal(SIGTERM, old_sigterm); + signal(SIGQUIT, old_sigquit); + } resettty: /* Put STDIN back into the (sane?) state we found it in before starting */ - tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); + if (raw) + tcsetattr(STDIN_FILENO, TCSAFLUSH, &ttyattr); return ret; } diff --git a/tools/console.h b/tools/console.h index 46255b8..c23acda 100644 --- a/tools/console.h +++ b/tools/console.h @@ -3,7 +3,7 @@ * * Copyright (C) 2007, 2010, 2012 Red Hat, Inc. * - * This library is free software; you can redistribute it and/or + * This library is free software you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. @@ -24,13 +24,8 @@ # define __VIR_CONSOLE_H__ # ifndef WIN32 - # include <termios.h> - -int vshRunConsole(virDomainPtr dom, - const char *dev_name, - const char *escape_seq, - unsigned int flags); +int vshRunConsole(virStreamPtr st, const char *escape_seq, bool raw); int vshMakeStdinRaw(struct termios *ttyattr, bool report_errors); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 96e62fc..4a500e6 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1887,10 +1887,12 @@ static const vshCmdOptDef opts_console[] = { }; static bool -cmdRunConsole(vshControl *ctl, virDomainPtr dom, +cmdRunConsole(vshControl *ctl, + virDomainPtr dom, const char *name, unsigned int flags) { + virStreamPtr st = NULL; bool ret = false; int state; @@ -1905,17 +1907,26 @@ cmdRunConsole(vshControl *ctl, virDomainPtr dom, } if (!isatty(STDIN_FILENO)) { - vshError(ctl, "%s", _("Cannot run interactive console without a controlling TTY")); + vshError(ctl, "%s", _("Cannot run interactive console " + "without a controlling TTY")); goto cleanup; } + if (!(st = virStreamNew(virDomainGetConnect(dom), VIR_STREAM_NONBLOCK))) + goto cleanup; + + if (virDomainOpenConsole(dom, name, st, flags) < 0) + goto cleanup; + vshPrintExtra(ctl, _("Connected to domain %s\n"), virDomainGetName(dom)); vshPrintExtra(ctl, _("Escape character is %s\n"), ctl->escapeChar); fflush(stdout); - if (vshRunConsole(dom, name, ctl->escapeChar, flags) == 0) + if (vshRunConsole(st, ctl->escapeChar, true) == 0) ret = true; cleanup: + if (st) + virStreamFree(st); return ret; } diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 3d13e01..bf2a48f 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -31,6 +31,7 @@ #include <libxml/xpath.h> #include <libxml/xmlsave.h> +#include "console.h" #include "internal.h" #include "buf.h" #include "memory.h" @@ -1073,6 +1074,64 @@ error: goto cleanup; } +static const vshCmdInfo info_node_tcp_console[] = { + {"help", N_("Connect to a TCP port on the host using a console")}, + {"desc", N_("Connect to a TCP port on the host using a console")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_tcp_console[] = { + {"port", VSH_OT_DATA, VSH_OFLAG_REQ, N_("port to connect to")}, + {"host", VSH_OT_STRING, VSH_OFLAG_NONE, N_("hostname to connect to")}, + {"ipv4", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("use IPv4")}, + {"ipv6", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("use IPv6")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeTCPConsole(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + const char *host; + const char *port; + unsigned int flags = 0; + virStreamPtr st = NULL; + + if (vshCommandOptString(cmd, "host", &host) < 0) { + vshError(ctl, "%s", _("Invalid hostname")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "port", &port) < 0) { + vshError(ctl, "%s", _("Invalid port")); + goto cleanup; + } + + if (vshCommandOptBool(cmd, "ipv4")) + flags |= VIR_NODE_TUNNEL_TCP_IPV4; + + if (vshCommandOptBool(cmd, "ipv6")) + flags |= VIR_NODE_TUNNEL_TCP_IPV6; + + if (!(st = virStreamNew(ctl->conn, VIR_STREAM_NONBLOCK))) + goto cleanup; + + if (virNodeTunnelTCP(ctl->conn, st, host, port, flags) < 0) + goto cleanup; + + vshPrintExtra(ctl, _("Connected to host '%s' port '%s'\n"), host, port); + vshPrintExtra(ctl, _("Escape character is %s\n"), ctl->escapeChar); + fflush(stdout); + if (vshRunConsole(st, ctl->escapeChar, false) == 0) + ret = true; + +cleanup: + if (st) + virStreamFree(st); + + return ret; +} + const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, @@ -1094,5 +1153,6 @@ const vshCmdDef hostAndHypervisorCmds[] = { {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, {"uri", cmdURI, NULL, info_uri, 0}, {"version", cmdVersion, opts_version, info_version, 0}, + {"node-tcp-console", cmdNodeTCPConsole, opts_node_tcp_console, info_node_tcp_console, 0}, {NULL, NULL, NULL, NULL, 0} }; -- 1.8.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list