This ugly thing is a shell script to detect availability of
the -q option for 'nc': debian and suse based distros need this
flag to ensure the remote nc will exit on EOF, so it will go away
when we close the tunnel. If it doesn't go away, a useless 'nc'
process is left sitting on the remote host.
Fedora's 'nc' doesn't have this option, so we can't blindly pass -q.
More info here:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=564034
We also detect the -U option, since some nc versions don't support it, which
has caused quite some user confusion. Connecting to a box and using the
incorrect nc:
virsh --connect qemu+ssh://root@debhost/system?netcat=/bin/nc.traditional
error: server closed connection: /bin/nc.traditional: invalid option -- U
nc -h for help
openbsd nc is required
error: failed to connect to the hypervisor
Test with Fedora 12, RHEL 5.4, and Debian Lenny
---
src/remote/remote_driver.c | 52 ++++++++++++++++++++++++++++++++++++++------
1 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 7f92fd0..c3258d3 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -732,8 +732,49 @@ doRemoteOpen (virConnectPtr conn,
}
case trans_ssh: {
- int j, nr_args = 6;
+ int j, nr_args = 0;
+ char *nc_command;
+
+ const char *nc_bin = netcat ? netcat : "nc";
+ const char *sock_path = (sockname ? sockname :
+ (flags & VIR_CONNECT_RO
+ ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
+ : LIBVIRTD_PRIV_UNIX_SOCKET));
+
+ /*
+ * Build 'nc' command run on the remote host
+ *
+ * This ugly thing is a shell script to detect availability of
+ * the -q option for 'nc': debian and suse based distros need this
+ * flag to ensure the remote nc will exit on EOF, so it will go away
+ * when we close the tunnel. If it doesn't go away, a useless 'nc'
+ * process is left sitting on the remote host.
+ *
+ * Fedora's 'nc' doesn't have this option, and apparently
defaults
+ * to the desired behavior.
+ */
+ const char *nc_detect_template = (
+ "NCOUT=$(%s -U 2>&1);"
+ "echo \"$NCOUT\" | grep -q 'invalid option';"
+ "if [ $? -eq 0 ] ; then"
+ " echo \"$NCOUT\" >&2;"
+ " echo openbsd 'nc' is required >&2;"
+ " exit 1;"
+ "fi;"
+ ""
+ "%s -q 2>&1 | grep -q 'requires an argument';"
+ "if [ $? -eq 0 ] ; then"
+ " CMD='-q 0';"
+ "else"
+ " CMD='';"
+ "fi;"
+ "%s $CMD -U %s;");
+
+ if (virAsprintf(&nc_command, nc_detect_template,
+ nc_bin, nc_bin, nc_bin, sock_path) < 0)
+ goto out_of_memory;
+ nr_args += 4; /* ssh $hostname $netcat_command NULL*/
if (username) nr_args += 2; /* For -l username */
if (no_tty) nr_args += 5; /* For -T -o BatchMode=yes -e none */
if (port) nr_args += 2; /* For -p port */
@@ -765,12 +806,9 @@ doRemoteOpen (virConnectPtr conn,
cmd_argv[j++] = strdup ("none");
}
cmd_argv[j++] = strdup (priv->hostname);
- cmd_argv[j++] = strdup (netcat ? netcat : "nc");
- cmd_argv[j++] = strdup ("-U");
- cmd_argv[j++] = strdup (sockname ? sockname :
- (flags & VIR_CONNECT_RO
- ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
- : LIBVIRTD_PRIV_UNIX_SOCKET));
+
+ cmd_argv[j++] = nc_command;
+
cmd_argv[j++] = 0;
assert (j == nr_args);
for (j = 0; j < (nr_args-1); j++)
--
1.6.5.2