Why dup(), again and again?
David Newall
openssh at davidnewall.com
Sat Oct 21 00:11:04 AEDT 2017
Sorry for repeating myself. It's been pointed out that I need a
convincing demonstration. (I feel I already have given that, but here
are all the details, in the one post, including a demonstration.)
I've been using ssh without it duping stdout and stderr, and had no
problems. I think this change should be made to the master source.
WHAT IS THE PROBLEM WITH SSH RIGHT NOW?
It duplicates FILENO_STDOUT and FILENO_STDERR, thus there are two
descriptors for each of these files. When the remote program closes its
stdout or stderr, the remote sshd sends the appropriate message to the
local ssh, which responds by closing the corresponding (duplicate)
descriptor, but it ignores the original descriptor, thus that file
remains open. The result of this is that a program reading from ssh's
stdout (or stderr) has no way of knowing that the remote program has
closed the file.
WHY IS THAT BAD?
For interactive purposes, I suppose it isn't a problem. It's true that
the remote program can send no further ouput (or error output), but
everything proceeds in an otherwise reasonable way. Where it is a
problem is if you want to use ssh in a script. It's significant when a
remote program closes stdout. It means something. It means that no
more output will be produced, the next program in the pipeline will
receive no more input, and should take action for end-of-file. At
present, the next program in the pipeline cannot take action for
end-of-file until ssh exits. The ssh program will not exit until the
remote program exits, but, in a scripted situation, it may well be
waiting for end-of-file on its input, and thus we have a deadlock: the
remote program has closed output and is waiting for input to close; the
local program that is next in the pipeline is waiting for its input to
close, which will never occur, and thus has no way to signal that it has
finished its job. The program providing input has no way of knowing
that the remote program has closed output and thus has no way of knowing
that it should close its input.
WHAT IMPACT IS THERE FROM NOT DUPLICATING THESE DESCRIPTORS?
As far as I can tell, only that ssh's accurately mirrors the remote
program's output. That already happens for all data written to output.
Closing ssh's output (all descriptors) merely completes the picture.
Ssh does not, of itself, use stdout; it has no reason to keep stdout
open. As far as I can tell, the change I am proposing has no
deleterious effect.
PROVE IT!
This is what should happen:
$ sh -c 'exec cat >&- 2>&-; sleep 5' | { read something && echo
$something || echo eof; }
eof
[then 5 second pause]
This is what happens using ssh:
$ ssh localhost 'exec >&- 2>&-; sleep 5' | { read something && echo
$something || echo eof; }
[5 second pause]
eof
Try for yourself!
WHAT IS THE EXACT CHANGE?
This patch allows a program reading ssh's output to see an EOF from
the remote session. Good for scripting.
Author: David NewallPatch-Name: scriptable-ssh.patch --- diff -u a/ssh.c b/ssh.c --- a/ssh.c
+++ b/ssh.c @@ -1837,11 +1837,11 @@ } else { in = dup(STDIN_FILENO); } -
out = dup(STDOUT_FILENO); - err = dup(STDERR_FILENO); + out =
STDOUT_FILENO; + err = STDERR_FILENO; - if (in < 0 || out < 0 || err <
0) - fatal("dup() in/out/err failed"); + if (in < 0) + fatal("dup() in
failed"); /* enable nonblocking unless tty */ if (!isatty(in))
WHAT CAN I DO TO HELP STEWARD THIS CHANGE INTO THE MASTER SOURCE?
What do I need to do?
David
More information about the openssh-unix-dev
mailing list