chiark / gitweb /
el/dot-emacs.el (mdw-fontify-rust): Fix integer literal syntax.
[profile] / bin / hacks / ssh
CommitLineData
4d7d040b
MW
1#! /bin/bash
2###
3### SSH wrapper to spawn separate SSH master connections on demand
4###
5### (c) 2010 Mark Wooding
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This program is free software; you can redistribute it and/or modify
11### it under the terms of the GNU General Public License as published by
12### the Free Software Foundation; either version 2 of the License, or
13### (at your option) any later version.
14###
15### This program is distributed in the hope that it will be useful,
16### but WITHOUT ANY WARRANTY; without even the implied warranty of
17### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18### GNU General Public License for more details.
19###
20### You should have received a copy of the GNU General Public License
21### along with this program; if not, write to the Free Software Foundation,
22### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24###--------------------------------------------------------------------------
25### Configuration.
26
27: ${REAL_SSH=/usr/bin/ssh}
e41b452f
MW
28: ${SSH_HOME=$(unset HOME; bash -c 'echo ~/.ssh')}
29: ${SSH_LOGDIR=$SSH_HOME/log-$(hostname)}
4d7d040b
MW
30
31###--------------------------------------------------------------------------
32### Parse the command line and dredge out information.
33
34## This is a reasonable approximation to SSH's command-line argument parser.
35unset host login
36mode=m
37declare -a opts masteropts
38while :; do
39 case "$1,$#" in
40
41 ## Nothing left. We're done.
42 ,0)
43 break
44 ;;
45
46 ## A command line option group. Parse it and work out what's going on.
47 -*)
48 opt=$1
49 opts=("${opts[@]}" "$opt")
50 while :; do
51
52 ## Strip off the first character, because it's the one we dealt with
53 ## last time.
54 opt=${opt#?}
55 o=$opt
56
57 ## Phase 1: identify the option and whether it needs an argument.
58 unset arg
59 case "$o" in
60
61 ## Empty group. We're done.
62 "")
63 break
64 ;;
65
66 ## Options with arguments.
67 [bcDeFiLlmOopRSw]*)
68 case "$#,$o" in
69
70 ## You're going to lose because there's no argument. But we'll
71 ## let SSH deal with that.
72 1,?)
73 arg=
74 ;;
75
76 ## There's an argument cuddled on to the end of the option. It
77 ## will have been committed to the `opts' array as part of the
78 ## option group.
79 *,??*)
80 arg=${opt#?}
81 opt=
82 ;;
83
84 ## Nope. There's an argument in the next word. Grab it and
85 ## commit it.
86 *)
87 arg="$2"
88 opts=("${opts[@]}" "$arg")
89 shift
90 ;;
91 esac
92 ;;
93
94 ## Anything else. Let it go even if it's not valid: SSH will moan
95 ## if it wants. Note that `--' is ignored by SSH, but this isn't
96 ## documented; in particular, `--' is /not/ a POSIX end-of-options
97 ## marker, so we don't try to handle it specially here either.
98 *)
99 ;;
100 esac
101
102 ## Phase two. Figure out whether what this means for us.
103 case "$mode,$o" in
104
105 ## `-O foo' and `-S foo' mean that the caller wants to take
106 ## control of the multiplexing process.
107 ?,[MOS]*)
108 mode=p
109 ;;
110
111 ## Catch the login name if there is one. Make sure the master
112 ## knows it.
113 ?,l*)
114 masteropts=("${masteropts[@]}" "-l$arg")
115 login=$arg
116 ;;
117
e41b452f
MW
118 ## Catch the port number. We want this for building the logfile
119 ## name.
120 ?,p*)
121 masteropts=("${masteropts[@]}" "-p$arg")
122 port=$arg
123 ;;
124
4d7d040b 125 ## These options are interesting to the master connection.
ef864444 126 m,[aADLlRSwxXv46]*)
4d7d040b
MW
127 masteropts=("${masteropts[@]}" "-${o:0:1}$arg")
128 ;;
129
130 ## SSH options on the command line merit special attention. Pass
131 ## them onto the master, if necessary.
132 ?,o*)
133 masteropts=("${masteropts[@]}" "${opt:0:1}$arg")
134 case "$mode,$arg" in
135
136 ## User wants to control the process. Let him.
137 ?,ControlMaster=* | ?,ControlPath=*)
138 mode=p
139 ;;
140
141 esac
142 ;;
143 esac
144 done
145 ;;
146
147 ## A bare word. Maybe it's the hostname, or the start of the command.
148 *)
af844120 149 case ${host-t}${host+nil} in
4d7d040b
MW
150 t) host=$1 ;;
151 *) break ;;
152 esac
153 ;;
154 esac
155 shift
156done
157
158###--------------------------------------------------------------------------
159### Now to actually do the job.
160
161## If there's no host, pass straight through. We can't do anything useful
162## anyway.
163case ${host+t} in
164 t) ;;
165 *) mode=p ;;
166esac
167
168## Actually do something useful.
169case "$mode" in
170 p)
171 exec "$REAL_SSH" "${opts[@]}" ${host+"$host"} "$@"
172 ;;
173 m)
e41b452f
MW
174 mkdir -p -m700 "$SSH_LOGDIR"
175 logfile=$SSH_LOGDIR/${login+"$login@"}"$host"${port+":$port"}.log
cfed2fe1
MW
176 if ! "$REAL_SSH" -Ocheck \
177 ${port+-p$port} ${login+"$login@"}"$host" \
afda7f51
MW
178 >/dev/null 2>&1
179 then
e41b452f
MW
180 "$REAL_SSH" -MNf "${masteropts[@]}" "$host" \
181 </dev/null >/dev/null 2>$logfile
4d7d040b
MW
182 fi
183 exec "$REAL_SSH" ${opts[@]} "$host" "$@"
184 ;;
185esac
186
187###----- That's all, folks --------------------------------------------------