From: Mark Wooding Date: Sun, 19 Dec 2010 03:14:17 +0000 (+0000) Subject: hacks/ssh: Add new hack for setting up background SSH master connections. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/profile/commitdiff_plain/4d7d040beb835fa5ea0015d0e1202f61fa79c0c1 hacks/ssh: Add new hack for setting up background SSH master connections. I don't really know why SSH doesn't do this by default; but it damned well ought to. --- diff --git a/hacks/ssh b/hacks/ssh new file mode 100755 index 0000000..a11c777 --- /dev/null +++ b/hacks/ssh @@ -0,0 +1,172 @@ +#! /bin/bash +### +### SSH wrapper to spawn separate SSH master connections on demand +### +### (c) 2010 Mark Wooding +### + +###----- Licensing notice --------------------------------------------------- +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. +### +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software Foundation, +### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +###-------------------------------------------------------------------------- +### Configuration. + +: ${REAL_SSH=/usr/bin/ssh} + +###-------------------------------------------------------------------------- +### Parse the command line and dredge out information. + +## This is a reasonable approximation to SSH's command-line argument parser. +unset host login +mode=m +declare -a opts masteropts +while :; do + case "$1,$#" in + + ## Nothing left. We're done. + ,0) + break + ;; + + ## A command line option group. Parse it and work out what's going on. + -*) + opt=$1 + opts=("${opts[@]}" "$opt") + while :; do + + ## Strip off the first character, because it's the one we dealt with + ## last time. + opt=${opt#?} + o=$opt + + ## Phase 1: identify the option and whether it needs an argument. + unset arg + case "$o" in + + ## Empty group. We're done. + "") + break + ;; + + ## Options with arguments. + [bcDeFiLlmOopRSw]*) + case "$#,$o" in + + ## You're going to lose because there's no argument. But we'll + ## let SSH deal with that. + 1,?) + arg= + ;; + + ## There's an argument cuddled on to the end of the option. It + ## will have been committed to the `opts' array as part of the + ## option group. + *,??*) + arg=${opt#?} + opt= + ;; + + ## Nope. There's an argument in the next word. Grab it and + ## commit it. + *) + arg="$2" + opts=("${opts[@]}" "$arg") + shift + ;; + esac + ;; + + ## Anything else. Let it go even if it's not valid: SSH will moan + ## if it wants. Note that `--' is ignored by SSH, but this isn't + ## documented; in particular, `--' is /not/ a POSIX end-of-options + ## marker, so we don't try to handle it specially here either. + *) + ;; + esac + + ## Phase two. Figure out whether what this means for us. + case "$mode,$o" in + + ## `-O foo' and `-S foo' mean that the caller wants to take + ## control of the multiplexing process. + ?,[MOS]*) + mode=p + ;; + + ## Catch the login name if there is one. Make sure the master + ## knows it. + ?,l*) + masteropts=("${masteropts[@]}" "-l$arg") + login=$arg + ;; + + ## These options are interesting to the master connection. + m,[aADLlRSwxXv]*) + masteropts=("${masteropts[@]}" "-${o:0:1}$arg") + ;; + + ## SSH options on the command line merit special attention. Pass + ## them onto the master, if necessary. + ?,o*) + masteropts=("${masteropts[@]}" "${opt:0:1}$arg") + case "$mode,$arg" in + + ## User wants to control the process. Let him. + ?,ControlMaster=* | ?,ControlPath=*) + mode=p + ;; + + esac + ;; + esac + done + ;; + + ## A bare word. Maybe it's the hostname, or the start of the command. + *) + case ${host-t} in + t) host=$1 ;; + *) break ;; + esac + ;; + esac + shift +done + +###-------------------------------------------------------------------------- +### Now to actually do the job. + +## If there's no host, pass straight through. We can't do anything useful +## anyway. +case ${host+t} in + t) ;; + *) mode=p ;; +esac + +## Actually do something useful. +case "$mode" in + p) + exec "$REAL_SSH" "${opts[@]}" ${host+"$host"} "$@" + ;; + m) + if ! "$REAL_SSH" -Ocheck ${login+"$login@"}"$host" >/dev/null 2>&1; then + "$REAL_SSH" -MNf "${masteropts[@]}" "$host" + fi + exec "$REAL_SSH" ${opts[@]} "$host" "$@" + ;; +esac + +###----- That's all, folks -------------------------------------------------- diff --git a/setup b/setup index 76b95db..5e55c9b 100755 --- a/setup +++ b/setup @@ -248,6 +248,19 @@ for s in $scripts; do done echo " all done." +hacks=" + ssh:ssh" +echo "Installing hacks..." +for h in $hacks; do + d=${h%%:*} h=${h#*:} + ft=$HOME$sub/bin/hacks/$d + mkdir -p $ft + ln -s $here/hacks/$h $ft/$h.new + mv $ft/$h.new $ft/$h + echo " $d:$h" +done +echo " all done." + ###-------------------------------------------------------------------------- ### Set up the Emacs config.