Как предотвратить вложенный сеанс tmux в новой оболочке входа в систему? - PullRequest
0 голосов
/ 18 января 2019

Почти все решения ( 1 , 2 ) для установки tmux при запуске оболочки зависят от некоторых переменных среды, таких как $TMUX, $TERM и т. Д. Но когда мы запускаем Оболочка для входа, например, su -, все переменные очищены, кроме $TERM. Таким образом, мы можем положиться на $TERM, чтобы избежать запуска вложенных сессий. Допустим, по умолчанию $TERM равен xterm, и мы установили screen в .tmux.conf, чтобы определить, что мы находимся в сеансе TMUX. Это прекрасно работает для локального входа.

Теперь две машины A и B используют одно и то же правило для управления вложенными сеансами, и мы находимся в сеансе tmux на машине A. Когда мы выполняем удаленный вход (через ssh) из A в B, сеанс tmux не запускается B, потому что $TERM уже установлен на screen.

Итак, нет ли способа узнать, что мы уже находимся в сеансе tmux, не завися от переменных окружения?

PS:

Я публикую обходной путь как ответ, который я использую для достижения вышеупомянутого поведения. Но более точный и лучший метод, такой как этот, может работать с использованием команд tmux.

1 Ответ

0 голосов
/ 18 января 2019

Это решение работает, выясняя, подключен ли текущий терминал к серверу tmux, работающему на той же машине. Чтобы выяснить связь, мы будем использовать псевдотерминальную пару и статистику ввода / вывода взломать.
Однако может произойти сбой, если файлы /proc fs или /dev не доступны для чтения / записи пользователем. Например, если tmux-сервер был запущен пользователем root, пользователь без полномочий root не сможет его найти.
Кроме того, мы можем получить ложные срабатывания, если сервер tmux получает данные из какого-либо другого источника, в то время как мы пытаемся записать в него нули.

Поместите это в конец .bashrc или другого файла запуска оболочки, который вы хотите:

# ~/.bashrc

# don't waste time if $TMUX environemnt variable is set
[ -z $TMUX ] || return

# don't start a tmux session if current shell is not connected to a terminal
pts=$(tty) || return

# find out processes connected to master pseudoterminal
for ptm in $(fuser /dev/ptmx 2>/dev/null)
do
    # ignore process if it's not a tmux server
    grep -q tmux /proc/$ptm/comm || continue
    # number of bytes already read by tmux server
    rchar_old=$(awk '/rchar/ {print $2}' /proc/$ptm/io)
    # write out 1000 bytes to current slave pseudoterminal terminal
    dd bs=1 count=1000 if=/dev/zero of=$pts &>/dev/null
    # read number of bytes again and find difference
    diff=$(( $(awk '/rchar/ {print $2}' /proc/$ptm/io) - rchar_old ))
    # if it equals 1000, current terminal is connected to tmux server
    # however diff comes greater than 1000 most of the times
    [ $diff -ge 1000 ] && return
done

# start or attach to a tmux session
echo 'Press any key to interrupt tmux session.'
read -st1 key && return

# connect to a detached session if exists for current user
session=($(tmux list-sessions 2>/dev/null | sed -n '/(attached)/!s/:.*r//p'))
[ -z $session ] || exec tmux a -t ${session[0]}

# start a new session after all
exec tmux
...