chiark / gitweb /
dot/mailrc: Some minor tweaks for use with GNU Mailutils.
[profile] / 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}
28
29###--------------------------------------------------------------------------
30### Parse the command line and dredge out information.
31
32## This is a reasonable approximation to SSH's command-line argument parser.
33unset host login
34mode=m
35declare -a opts masteropts
36while :; do
37 case "$1,$#" in
38
39 ## Nothing left. We're done.
40 ,0)
41 break
42 ;;
43
44 ## A command line option group. Parse it and work out what's going on.
45 -*)
46 opt=$1
47 opts=("${opts[@]}" "$opt")
48 while :; do
49
50 ## Strip off the first character, because it's the one we dealt with
51 ## last time.
52 opt=${opt#?}
53 o=$opt
54
55 ## Phase 1: identify the option and whether it needs an argument.
56 unset arg
57 case "$o" in
58
59 ## Empty group. We're done.
60 "")
61 break
62 ;;
63
64 ## Options with arguments.
65 [bcDeFiLlmOopRSw]*)
66 case "$#,$o" in
67
68 ## You're going to lose because there's no argument. But we'll
69 ## let SSH deal with that.
70 1,?)
71 arg=
72 ;;
73
74 ## There's an argument cuddled on to the end of the option. It
75 ## will have been committed to the `opts' array as part of the
76 ## option group.
77 *,??*)
78 arg=${opt#?}
79 opt=
80 ;;
81
82 ## Nope. There's an argument in the next word. Grab it and
83 ## commit it.
84 *)
85 arg="$2"
86 opts=("${opts[@]}" "$arg")
87 shift
88 ;;
89 esac
90 ;;
91
92 ## Anything else. Let it go even if it's not valid: SSH will moan
93 ## if it wants. Note that `--' is ignored by SSH, but this isn't
94 ## documented; in particular, `--' is /not/ a POSIX end-of-options
95 ## marker, so we don't try to handle it specially here either.
96 *)
97 ;;
98 esac
99
100 ## Phase two. Figure out whether what this means for us.
101 case "$mode,$o" in
102
103 ## `-O foo' and `-S foo' mean that the caller wants to take
104 ## control of the multiplexing process.
105 ?,[MOS]*)
106 mode=p
107 ;;
108
109 ## Catch the login name if there is one. Make sure the master
110 ## knows it.
111 ?,l*)
112 masteropts=("${masteropts[@]}" "-l$arg")
113 login=$arg
114 ;;
115
116 ## These options are interesting to the master connection.
117 m,[aADLlRSwxXv]*)
118 masteropts=("${masteropts[@]}" "-${o:0:1}$arg")
119 ;;
120
121 ## SSH options on the command line merit special attention. Pass
122 ## them onto the master, if necessary.
123 ?,o*)
124 masteropts=("${masteropts[@]}" "${opt:0:1}$arg")
125 case "$mode,$arg" in
126
127 ## User wants to control the process. Let him.
128 ?,ControlMaster=* | ?,ControlPath=*)
129 mode=p
130 ;;
131
132 esac
133 ;;
134 esac
135 done
136 ;;
137
138 ## A bare word. Maybe it's the hostname, or the start of the command.
139 *)
140 case ${host-t} in
141 t) host=$1 ;;
142 *) break ;;
143 esac
144 ;;
145 esac
146 shift
147done
148
149###--------------------------------------------------------------------------
150### Now to actually do the job.
151
152## If there's no host, pass straight through. We can't do anything useful
153## anyway.
154case ${host+t} in
155 t) ;;
156 *) mode=p ;;
157esac
158
159## Actually do something useful.
160case "$mode" in
161 p)
162 exec "$REAL_SSH" "${opts[@]}" ${host+"$host"} "$@"
163 ;;
164 m)
165 if ! "$REAL_SSH" -Ocheck ${login+"$login@"}"$host" >/dev/null 2>&1; then
166 "$REAL_SSH" -MNf "${masteropts[@]}" "$host"
167 fi
168 exec "$REAL_SSH" ${opts[@]} "$host" "$@"
169 ;;
170esac
171
172###----- That's all, folks --------------------------------------------------