summaryrefslogtreecommitdiff
path: root/bin/ssh-and-tmux
blob: 79c1766dc928838db892b7d44feaeb51ee6a3cb4 (plain)
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
#!/usr/bin/env 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 <https://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)

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 $session"
    prompt+=" on $display_host;
    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