+#! /bin/sh
+
+set -e
+case $# in
+ 2) ;;
+ *) echo >&2 "usage: $0 {start|stop|restart|status} HOST"; exit 1 ;;
+esac
+op=$1 host=$2
+
+writefile () {
+ file=$1; shift
+ echo "$*" >"$file.new"
+ mv "$file.new" "$file"
+}
+
+runssh () { ssh -T -oControlPath="./$host.ctrl" "$@"; }
+
+stopit () {
+
+ ## Initial shutdown protocol.
+ writefile "$host.state" stopping
+ if [ -f "$host.pid" ]; then kill $(cat "$host.pid") 2>/dev/null || :; fi
+ rm -f "$host.pid"
+
+ ## Shut down an existing connection if there is one.
+ if [ -S "$host.ctrl" ]; then
+ runssh -Oexit "$host" >/dev/null 2>/dev/null || :
+ fi
+
+ ## If there's still a socket, then work out what to do.
+ if [ -e "$host.ctrl" ]; then
+
+ ## If the connection's still running then we have a problem.
+ if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then
+ echo >&2 "$0: failed to kill existing connection to $host"
+ exit 2
+ fi
+
+ ## Remove the stale socket.
+ rm -f "$host.ctrl"
+ fi
+
+ ## Update the state.
+ rm -f "$host.state" "$host.pid"
+}
+
+daemon () {
+
+ ## There doesn't seem to be a better way of getting this. :-(
+ read pid <"$host.daemonpipe"
+ rm -f "$host.daemonpipe"
+
+ ## Set up shop.
+ trap 'rm -f "$host.pid"; stopit' EXIT INT TERM
+ writefile "$host.pid" "$pid"
+
+ ## Initial delay.
+ delay=0
+
+ ## Keep the connection up for as long as we can.
+ while [ -f "$host.pid" ]; do
+
+ ## Maybe back off before trying another connection.
+ case $delay in
+ 0)
+ delay=1
+ ;;
+ *)
+ writefile "$host.state" \
+ "wait until $(date -d+${delay}sec +"%Y-%m-%d %H:%M:%S %z")"
+ sleep $delay
+ delay=$(( 2*$delay ))
+ if [ $delay -gt 120 ]; then delay=120; fi
+ ;;
+ esac
+
+ ## Start a new connection.
+ writefile "$host.state" starting
+ if ! runssh -MNnf "$host" >/dev/null; then continue; fi
+ if ! runssh -Ocheck "$host" >/dev/null 2>&1; then
+ echo "connection to $host apparently stillborn"
+ continue
+ fi
+ writefile "$host.state" connected
+ delay=0
+
+ ## Wait until it gets torn down. The chicanery with a pipe is because
+ ## the ssh process will continue until either it gets disconnected from
+ ## the server or stdin closes -- so we have to arrange that stdin doesn't
+ ## close. Thanks to Richard Kettlewell for the suggestion.
+ rm -f "$host.pipe"; mkfifo -m400 "$host.pipe"
+ runssh -N "$host" >/dev/null <"$host.pipe" || :
+ rm -f "$host.pipe"
+ writefile "$host.state" disconnected
+ done
+}
+
+startit () {
+
+ ## If there's already a connection then we have nothing to do.
+ if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then
+ echo >&2 "$0: already connected to $host"
+ exit 0
+ fi
+
+ ## Start a daemon which makes connections for us. This is remarkably
+ ## tricky.
+ rm -f "$host.daemonpipe"; mkfifo -m600 "$host.daemonpipe"
+ { daemon& echo $! >"$host.daemonpipe"; } 2>&1 | logger -pdaemon.notice&
+}
+
+## Main dispatch.
+case "$op" in
+ start) startit ;;
+ stop) stopit ;;
+ restart) stopit; startit ;;
+ status)
+ if [ -f "$host.state" ]
+ then cat "$host.state"
+ else echo "down"
+ fi
+ ;;
+ *)
+ echo >&2 "usage: $0 {start|stop|restart|status} HOST"
+ exit 1
+ ;;
+esac