1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#!/bin/bash
# Copyright (C) 2020-2022 Sean Whitton
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
# Launcher for connections to remote persistent shell sessions, via mosh or a
# mechanism for manual, but convenient, user-triggered reconnects.
#
# Advantage of the latter over autossh is avoidance of surprise dialogs asking
# to authorise the use of SSH keys. And thus works better than autossh with
# short ServerAliveInterval and low ServerAliveCountMax ssh client config,
# which are desirable for interactive sessions.
# Hosts I want to mosh to.
# Be conservative: it's not just that mosh is available on that machine and
# it's not a highly security-sensitive machine, but also that, e.g., the host
# reboots not much more often than the workstation that'll be connecting, to
# minimise zombie clients.
mosh_hosts=(athena.silentflame.com melete.silentflame.com)
getopt=$(getopt -s bash -o "" \
-l 'container-cmd:,container-name:' -n ssh-and-tmux -- "$@")
eval "set - $getopt"
while true; do
case "$1" in
'--container-cmd') container_cmd=$2; shift 2; continue ;;
'--container-name') container_name=$2; shift 2; continue ;;
'--') shift; break ;;
esac
done
host="$1"
session="${2:-default}"
if printf '%s\0' "${mosh_hosts[@]}" \
| grep -Fxqz "$host"; then use_mosh=true; else use_mosh=false; fi
if [ -n "$container_name" ]; then
home="\\\$HOME"
display_host="$container_name"
else
home="\$HOME"
display_host="$host"
fi
# Go via a login shell such that if there is no root tmux daemon yet, it ends
# up with a PATH as though the first tmux session were launched from an
# interactive login shell. This affects launching programs directly from tmux
# (e.g. my C-\ e binding) for *all* sessions.
#
# mosh does execvp directly so for simplicity we assume remote SHELL is bash.
cmd=$(printf "tmux new-session -A -c %s -s $session" $home)
if $use_mosh; then
cmd=(bash -l -c "$cmd")
else
cmd=(\$SHELL -l -c "\"$cmd\"")
fi
[ -n "$container_name" ] \
&& cmd=($(printf "$container_cmd" "$container_name") -- "${cmd[@]}")
if $use_mosh; then
exec mosh "$host" -- "${cmd[@]}"
else
# The idea behind quitting on d, C-c or C-d was so that the user can type
# C-d C-d to kill the remote shell and then kill this script, C-\ d d to
# detach tmux and then kill this script, or similar.
#
# We now die when ssh exits zero, so this feature may be obsolete.
echo -ne "\033]0;tmux $session on $display_host\007"
prompt="Press any key to retry tmux [1m$session[0m"
prompt+=" on [1m$display_host[0m;
d/C-d/C-c to give up .. "
while true; do
ssh -t "$host" "${cmd[*]}" && exit
clear
read -n 1 -r -s -p "$prompt" ch
clear
[ "$ch" = $'\04' -o "$ch" = d ] && echo && exit
done
fi
|