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 | 11 ++++-----
tools/virsh-domain.c | 18 ++++++++++----
tools/virsh-host.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 114 insertions(+), 41 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 962594c..c23acda 100644
--- a/tools/console.h
+++ b/tools/console.h
@@ -1,9 +1,9 @@
/*
* console.c: A dumb serial console client
*
- * Copyright (C) 2007, 2010 Red Hat, Inc.
+ * 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,11 +24,8 @@
# define __VIR_CONSOLE_H__
# ifndef WIN32
-
-int vshRunConsole(virDomainPtr dom,
- const char *dev_name,
- const char *escape_seq,
- unsigned int flags);
+# include <termios.h>
+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 1f7aff7..4a500e6 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -30,7 +30,6 @@
#include <poll.h>
#include <signal.h>
#include <sys/time.h>
-#include <termios.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
@@ -1888,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;
@@ -1906,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