# Copyright (c) 2016 Uwe Werler # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. _sock="SSH" _sess="SSH" _tabw="15" # width of the tabs created # run tmux with some defaults like utf-8 support and at an separate socket _tmux="tmux -2 -u -L ${_sock}" # set the variable "%#{pane_id}" in tmux environment to the hostname _setenv="${_tmux} setenv -t ${_sess}" usage(){ echo \ " usage: /bin/sh $0 -cgsu [args] -c : start server and connect xterm or attach term to detached session -c args: start server and run ssh with args or start ssh and attach xterm -r refresh all \"tabs\" with vals from active panes -s %num value: set value to var %num -u %num: unset var %num where %num is the pane ID. For usage from within shell create an alias like this: alias ssh=\"sh ~/.tmux/SSH.sh -c\" For usage from within cwm put this in Your ~/.cwmrc: command term \'ksh -c \". ~/.tmux/SSH.sh -c \$1\"\' bind CM-Return xterm #...and if autogroup preferred autogroup 1 \"${_sess},XTerm\" If xdotool is installed it focusses automatically to the xterm running this tmux session or reattaches a xterm if the session is detached. " exit 1 } _checkname(){ # parse the output from ssh -G for _l; do case $_l in hostname) # make stupid check if hostname is an IP _ip=${2##+([0-9]).+([0-9]).+([0-9]).+([0-9])} _ip=${_ip##+([0-9a-f]):+([0-9a-f]):+([0-9a-f]):*([0-9a-f:]):+([0-9a-f])} if [[ -z ${_ip} ]]; then _host=$(dig +short -x $2) [[ -n "$_host" ]] && _host=${_host%%.*} || _host=$2 else _host=${2%%.*} fi break ;; esac shift done } _runxdotool(){ # with xdotool installed, activate the window or reattach to a detached # session if type xdotool >/dev/null; then _winid="xdotool search --classname ${_sess}" [[ -z $(${_winid}) ]] && { xterm -title ${_sess} -name ${_sess} -e \ $_tmux attach -t ${_sess} & sleep 0.5; } 2>/dev/null xdotool search --classname ${_sess} windowactivate fi } _setwin(){ # get all environment variables and store them for _var in $($_tmux show-env -t ${_sess}); do case $_var in %+([0-9a-f])*) _index=${_var%%=*} # make a list of existing variables INDEX="${INDEX} ${_index}" _index=${_index##%} _value=${_var##*=} # make an array with values VALS[$_index]=${_value} ;; esac done $_tmux list-windows -F "#{window_id} #{pane_id} #{@HOST}" -t ${_sess} | { _localhost=$(hostname -s) while read _winid _paneid _val; do _host=${VALS[${_paneid##%}]} [[ -z ${_host} ]] && _host=${_localhost} [[ ${_val} == ${_host} ]] || \ $_tmux setw -q -t ${_winid} "@HOST" "$(printf %-${_tabw}.${_tabw}s ${_host})" done } for _pane in $($_tmux list-panes -s -t ${_sess} -F '#D'); do # make a list of all panes in session CURPANES="${CURPANES} X${_pane}X" done # compare environment with current panes and delete unused variables for _pane in ${INDEX}; do [[ ${CURPANES} == *X${_pane}X* ]] || \ $_setenv -ur ${_pane} done # workaround as long as tmux crashes by setting "renumber-windows on" and hook # "after-join-pane" or "after-move-pain" at the same time $_tmux move-window -r -t ${_sess} $_tmux refresh-client -S 2>/dev/null } _ssh() { # remove string when invoked via cwm [[ $1 == "[ssh]" ]] && shift if [[ -n $1 ]]; then # force a tty e.g. when running a command at the remote side like tmux ;) _cmd="ssh -t $@" # let ssh parse the command line so we are sane # avoid override the hostname via main config _checkname $(unalias ssh; ssh -F /dev/null -G $@) fi [[ $($_tmux list-session -F "#S" 2>/dev/null) == *${_sess}* ]] && _s=${_sess} # check if called from inside our tabbed tmux to avoid a new window if [[ $TMUX == *${_sock}* && ${_s} == ${_sess} ]]; then trap "$_setenv -ur $TMUX_PANE; sh $0 -r" INT EXIT $_setenv $TMUX_PANE ${_host} _setwin $_cmd exit elif [[ ${_s} == ${_sess} ]]; then [[ -z ${_cmd} ]] && _runxdotool && exit _paneid=$($_tmux new-window -P -t ${_sess} -F '#D' ${_cmd}) $_setenv ${_paneid} ${_host} _setwin _runxdotool else _paneid=$($_tmux -f ~/.tmux/SSH.conf new-session -P -d -F '#D' -s ${_sess} ${_cmd}) [[ -n ${_paneid} ]] || exit 1 [[ -n ${_host} ]] && $_setenv ${_paneid} ${_host} _setwin xterm -title ${_sess} -name ${_sess} -e \ $_tmux attach -t ${_sess} 2>/dev/null & fi } getopts ":s:u:cr" _opt shift $((OPTIND-1)) case "$_opt" in c) _ssh $OPTARG $@ ;; r) _setwin exit 0 ;; s) [[ $OPTARG != %+([0-9]) ]] && usage $_setenv $OPTARG $@ ;; u) [[ $OPTARG != %+([0-9]) ]] && usage $_setenv -ur $OPTARG ;; *) usage ;; esac #vim: set ai:ts=2:et:sw=2