Commit | Line | Data |
---|---|---|
b16ea8ba MW |
1 | #! /bin/sh |
2 | ||
3 | set -e | |
4 | case $# in | |
5 | 2) ;; | |
6 | *) echo >&2 "usage: $0 {start|stop|restart|status} HOST"; exit 1 ;; | |
7 | esac | |
8 | op=$1 host=$2 | |
9 | ||
10 | writefile () { | |
11 | file=$1; shift | |
12 | echo "$*" >"$file.new" | |
13 | mv "$file.new" "$file" | |
14 | } | |
15 | ||
16 | runssh () { ssh -T -oControlPath="./$host.ctrl" "$@"; } | |
17 | ||
1dc744ac | 18 | clobber () { |
b16ea8ba MW |
19 | |
20 | ## Shut down an existing connection if there is one. | |
21 | if [ -S "$host.ctrl" ]; then | |
22 | runssh -Oexit "$host" >/dev/null 2>/dev/null || : | |
23 | fi | |
24 | ||
25 | ## If there's still a socket, then work out what to do. | |
26 | if [ -e "$host.ctrl" ]; then | |
27 | ||
28 | ## If the connection's still running then we have a problem. | |
29 | if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then | |
30 | echo >&2 "$0: failed to kill existing connection to $host" | |
31 | exit 2 | |
32 | fi | |
33 | ||
34 | ## Remove the stale socket. | |
35 | rm -f "$host.ctrl" | |
36 | fi | |
1dc744ac MW |
37 | } |
38 | ||
39 | stopit () { | |
40 | ||
41 | ## Initial shutdown protocol. | |
42 | writefile "$host.state" stopping | |
43 | if [ -f "$host.pid" ]; then kill $(cat "$host.pid") 2>/dev/null || :; fi | |
44 | rm -f "$host.pid" | |
45 | ||
46 | ## Clobber the existing connection, if there is one. | |
47 | clobber | |
b16ea8ba MW |
48 | |
49 | ## Update the state. | |
50 | rm -f "$host.state" "$host.pid" | |
51 | } | |
52 | ||
53 | daemon () { | |
54 | ||
55 | ## There doesn't seem to be a better way of getting this. :-( | |
56 | read pid <"$host.daemonpipe" | |
57 | rm -f "$host.daemonpipe" | |
58 | ||
59 | ## Set up shop. | |
60 | trap 'rm -f "$host.pid"; stopit' EXIT INT TERM | |
61 | writefile "$host.pid" "$pid" | |
62 | ||
63 | ## Initial delay. | |
64 | delay=0 | |
65 | ||
66 | ## Keep the connection up for as long as we can. | |
67 | while [ -f "$host.pid" ]; do | |
68 | ||
69 | ## Maybe back off before trying another connection. | |
70 | case $delay in | |
71 | 0) | |
72 | delay=1 | |
73 | ;; | |
74 | *) | |
75 | writefile "$host.state" \ | |
76 | "wait until $(date -d+${delay}sec +"%Y-%m-%d %H:%M:%S %z")" | |
77 | sleep $delay | |
78 | delay=$(( 2*$delay )) | |
79 | if [ $delay -gt 120 ]; then delay=120; fi | |
80 | ;; | |
81 | esac | |
82 | ||
83 | ## Start a new connection. | |
84 | writefile "$host.state" starting | |
85 | if ! runssh -MNnf "$host" >/dev/null; then continue; fi | |
86 | if ! runssh -Ocheck "$host" >/dev/null 2>&1; then | |
87 | echo "connection to $host apparently stillborn" | |
88 | continue | |
89 | fi | |
90 | writefile "$host.state" connected | |
91 | delay=0 | |
92 | ||
93 | ## Wait until it gets torn down. The chicanery with a pipe is because | |
94 | ## the ssh process will continue until either it gets disconnected from | |
95 | ## the server or stdin closes -- so we have to arrange that stdin doesn't | |
96 | ## close. Thanks to Richard Kettlewell for the suggestion. | |
97 | rm -f "$host.pipe"; mkfifo -m400 "$host.pipe" | |
98 | runssh -N "$host" >/dev/null <"$host.pipe" || : | |
99 | rm -f "$host.pipe" | |
100 | writefile "$host.state" disconnected | |
101 | done | |
102 | } | |
103 | ||
104 | startit () { | |
105 | ||
106 | ## If there's already a connection then we have nothing to do. | |
107 | if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then | |
108 | echo >&2 "$0: already connected to $host" | |
109 | exit 0 | |
110 | fi | |
111 | ||
112 | ## Start a daemon which makes connections for us. This is remarkably | |
113 | ## tricky. | |
114 | rm -f "$host.daemonpipe"; mkfifo -m600 "$host.daemonpipe" | |
115 | { daemon& echo $! >"$host.daemonpipe"; } 2>&1 | logger -pdaemon.notice& | |
116 | } | |
117 | ||
118 | ## Main dispatch. | |
119 | case "$op" in | |
120 | start) startit ;; | |
121 | stop) stopit ;; | |
122 | restart) stopit; startit ;; | |
123 | status) | |
124 | if [ -f "$host.state" ] | |
125 | then cat "$host.state" | |
126 | else echo "down" | |
127 | fi | |
128 | ;; | |
129 | *) | |
130 | echo >&2 "usage: $0 {start|stop|restart|status} HOST" | |
131 | exit 1 | |
132 | ;; | |
133 | esac |