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 | ||
f93e3eb3 MW |
66 | ## Not waiting on a pipe yet. |
67 | kidcat=nil | |
68 | ||
b16ea8ba MW |
69 | ## Keep the connection up for as long as we can. |
70 | while [ -f "$host.pid" ]; do | |
71 | ||
72 | ## Maybe back off before trying another connection. | |
73 | case $delay in | |
74 | 0) | |
75 | delay=1 | |
76 | ;; | |
77 | *) | |
78 | writefile "$host.state" \ | |
79 | "wait until $(date -d+${delay}sec +"%Y-%m-%d %H:%M:%S %z")" | |
80 | sleep $delay | |
81 | delay=$(( 2*$delay )) | |
82 | if [ $delay -gt 120 ]; then delay=120; fi | |
83 | ;; | |
84 | esac | |
85 | ||
f93e3eb3 MW |
86 | ## Prepare a pipe so that we can wait for SSH to finish. This is a |
87 | ## rotten hack. | |
88 | case $kidcat in | |
89 | nil) ;; | |
90 | *) kill $kidcat >/dev/null 2>&1 || :; kidcat=nil ;; | |
91 | esac | |
92 | rm -f "$host.pipe"; mkfifo -m600 "$host.pipe" | |
93 | cat $host.pipe >/dev/null& kidcat=$! | |
94 | ||
b16ea8ba MW |
95 | ## Start a new connection. |
96 | writefile "$host.state" starting | |
f93e3eb3 | 97 | if ! runssh -MNnf "$host" >"$host.pipe"; then continue; fi |
b16ea8ba MW |
98 | if ! runssh -Ocheck "$host" >/dev/null 2>&1; then |
99 | echo "connection to $host apparently stillborn" | |
100 | continue | |
101 | fi | |
102 | writefile "$host.state" connected | |
103 | delay=0 | |
104 | ||
f93e3eb3 MW |
105 | ## Wait until it gets torn down. |
106 | wait $kidcat >/dev/null 2>&1 || : | |
b16ea8ba | 107 | rm -f "$host.pipe" |
f93e3eb3 | 108 | clobber |
b16ea8ba MW |
109 | writefile "$host.state" disconnected |
110 | done | |
111 | } | |
112 | ||
113 | startit () { | |
114 | ||
115 | ## If there's already a connection then we have nothing to do. | |
116 | if runssh -Ocheck "$host" >/dev/null 2>/dev/null; then | |
117 | echo >&2 "$0: already connected to $host" | |
118 | exit 0 | |
119 | fi | |
120 | ||
121 | ## Start a daemon which makes connections for us. This is remarkably | |
122 | ## tricky. | |
123 | rm -f "$host.daemonpipe"; mkfifo -m600 "$host.daemonpipe" | |
124 | { daemon& echo $! >"$host.daemonpipe"; } 2>&1 | logger -pdaemon.notice& | |
125 | } | |
126 | ||
127 | ## Main dispatch. | |
128 | case "$op" in | |
129 | start) startit ;; | |
130 | stop) stopit ;; | |
131 | restart) stopit; startit ;; | |
132 | status) | |
133 | if [ -f "$host.state" ] | |
134 | then cat "$host.state" | |
135 | else echo "down" | |
136 | fi | |
137 | ;; | |
138 | *) | |
139 | echo >&2 "usage: $0 {start|stop|restart|status} HOST" | |
140 | exit 1 | |
141 | ;; | |
142 | esac |