With open2(), the stderr from the child process would just be printed directly making it impossible for the call site of the tunnel to filter the output.
This is in preparation to add a 'pct mtunnel' command. When forking a tunnel to a node which does not support that command yet, the whole 'pct' usage documentation would be printed to the migration log and the call site would only see 'can't open tunnel - no reply' as an error. By capturing the stderr output too, the call site can detect that the failure happens because the target node is too old and avoid dumping the whole usage information. Signed-off-by: Fiona Ebner <[email protected]> --- New in v2. src/PVE/Tunnel.pm | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/PVE/Tunnel.pm b/src/PVE/Tunnel.pm index 25e03b6..148a8e2 100644 --- a/src/PVE/Tunnel.pm +++ b/src/PVE/Tunnel.pm @@ -5,7 +5,7 @@ use warnings; use IO::File; use IO::Pipe; -use IPC::Open2; +use IPC::Open3 qw(open3); use JSON qw(encode_json decode_json); use POSIX qw( WNOHANG ); use Storable qw(dclone); @@ -66,12 +66,19 @@ sub read_tunnel { $timeout = 60 if !defined($timeout); my $reader = $tunnel->{reader}; + my $reader_stderr = $tunnel->{reader_stderr}; my $output; eval { PVE::Tools::run_with_timeout($timeout, sub { $output = <$reader>; }); }; - die "reading from tunnel failed: $@\n" if $@; + my $err = $@; + + while (my $line = <$reader_stderr>) { # $reader_stderr is set up as non-blocking + $tunnel->{log}->('warn', $line); + } + + die "reading from tunnel failed: $err\n" if $err; chomp $output if defined($output); @@ -145,13 +152,16 @@ sub fork_ssh_tunnel { my $full_cmd = [@$rem_ssh, '-o ExitOnForwardFailure=yes', @localtunnelinfo, @$cmd]; my $reader = IO::File->new(); + my $reader_stderr = IO::File->new(); my $writer = IO::File->new(); my $orig_pid = $$; my $cpid; - eval { $cpid = open2($reader, $writer, @$full_cmd); }; + eval { $cpid = open3($writer, $reader, $reader_stderr, @$full_cmd); }; + # Only read_tunnel() uses $reader_stderr and it never wants to wait. + $reader_stderr->blocking(0); my $err = $@; @@ -167,6 +177,7 @@ sub fork_ssh_tunnel { my $tunnel = { writer => $writer, reader => $reader, + reader_stderr => $reader_stderr, pid => $cpid, rem_ssh => $rem_ssh, log => $log, -- 2.47.3
