Terminating remote ssh-started programs

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
I have a Linux program which does the following:

For each of a set of hosts,
    Create a pipe.
    Fork a child.
    In the child,
        Dup the write end of the pipe to stdout.
        Exec an ssh command to this host, giving it a particular
        time-consuming remote command.
    In the parent,
        Retain the read end of the pipe.

Use select() in a loop to collect output from each child ssh process,
multiplexing it line-by-line to stdout of the main program, prepending each
line with the name of the host that generated it.  Exit when all children
have exited.

This works well enough.  The problem is when I interrupt the main program
by pressing control-C (which also terminates all of the ssh child processes,
as they're in the same process group).  I want all of the remote commands to
be terminated as well, but under the existing scheme, they don't.  I suppose
I was hoping that some fatal signal would be delivered automatically, as
often happens when one is dealing with local processes, but it doesn't work
in this case.  The remote sshd processes end, but their children keep
chugging right along.

I've examined the source for our installed version of OpenSSH (3.6.1p2), but
I can't find any option or provision for sshd to deliver a signal to its
child when it exits due to EOF from the client.

The best solution I've been able to come up with is to modify the remote
command such that it notices when its standard input stream closes, and to
terminate when that happens.  Fortunately for me, the program was already
one that polls various file descriptors with select(2) in its main loop, so
it was trivial to add 0 to the set of descriptors.  However, this feels like
a hack; the program otherwise ignores stdin, so I used to close it, but now
I have to keep it open, discarding any data that arrives prior to EOF.
Also, I might not have had as easy a time of it if the remote program were
not I/O event-driven, and I'm interested in knowing a good general solution.
Something like Expect would obviously work, but I'd prefer something more

Can anyone suggest a cleaner way to get the behavior I'm after?

Thanks in advance.

Sean McAfee -- etzwane@schwag.org

Re: Terminating remote ssh-started programs

Quoted text here. Click to load it

See http://bugzilla.mindrot.org/show_bug.cgi?id=396

Quoted text here. Click to load it
Quoted text here. Click to load it

Use "ssh -t" to allocate a pty for your subprocess so it will get a
SIGHUP when the pty closes.

Darren Tucker (dtucker at zip.com.au)
GPG key 8FF4FA69 / D9A3 86E9 7EEE AF4B B2D4  37C9 C982 80C7 8FF4 FA69
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.

Re: Terminating remote ssh-started programs

Quoted text here. Click to load it

Thanks for the tip, but that approach causes its own problems.  It forces
the ssh client into interactive mode, causing it to interfere with my
terminal settings.  If I have more than a couple of client ssh processes, my
terminal wedges completely.  I can avoid that by either closing stdin or
redirecting it from /dev/null in the child before exec-ing ssh, but that
causes ssh to print an error message when tcgetattr fails.

I could probably avoid all of this by attaching ssh to a pseudo-tty or
something, but I think the far simpler solution is to fall back on the
"remote program exits when its stdin closes" strategy I mentioned before.

Sean McAfee -- etwane@schwag.org

Site Timeline