Почему фоновый ssh ​​может взять tty у Bash?

(Я использую Bash 4.4.12 в Debian 8. Вопрос также задавался в списке рассылки bash.)

Смотрите следующие шаги, чтобы воспроизвести проблему.

Из tty # 1 (pts/2):

[STEP 101] # tty
/dev/pts/2
[STEP 102] # ssh -o ControlMaster=yes -o ControlPath=/tmp/socket.ssh -N -f 127.0.0.1
[STEP 103] # ps -C ssh u
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root       1390  0.0  0.0  36440   656 ?        Ss   11:33   0:00 ssh -o ControlMaster=yes -o ControlPath=/tmp/so
[STEP 104] #
[STEP 105] # ssh -o ControlMaster=no -o ControlPath=/tmp/socket.ssh \
             127.0.0.1 sleep 3600 &
[1] 1396
[STEP 106] #    <-- Here I cannot input anything except <CTRL-C>

ШАГ 102 запустил мультиплексное соединение SSH, работающее как демон. ШАГ 105 пытается использовать мультиплексное соединение для запуска sleep команда. Но тогда я не могу ничего ввести в текущую оболочку. Если я убью ssh ... sleep & обработайте, тогда Bash сможет принять мой ввод снова. Похоже, что все входные данные потребляются ssh процесс.

Перейти к tty # 2 (pts/3):

[STEP 201] # tty
/dev/pts/3
[STEP 202] # ps t pts/2 j
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
   723   1353   1353   1353 pts/2      1353 Ss+      0   0:00 bash
  1353   1396   1396   1353 pts/2      1353 S        0   0:00 ssh -o ControlMaster=no -o ControlPath=/tmp/socket.ssh 127.0.0.1 sleep 3600
[STEP 203] # ps s 1396
  UID    PID  PENDING  BLOCKED  IGNORED    CAUGHT STAT TTY    TIME COMMAND
    0   1396 00000000 00000000 00001000 188004003 S    pts/2  0:00 ssh -o ControlMaster=no -o ControlPath=/tmp/socket.ssh 127.0.0.1 sleep 3600
[STEP 204] #

Я расшифровал сиг-маски:

PENDING (00000000):
BLOCKED (00000000):
IGNORED (00001000):
  13 PIPE
CAUGHT (188004003):
   1 HUP
   2 INT
  15 TERM
  28 WINCH
  32
  33

Здесь мы видим, что процесс SSH не ловит SIGTTIN сигнал. Вот что меня смущает, потому что фоновое задание (группа процессов) должно получить SIGTTIN и будет остановлен, когда он попытается прочитать из tty.

1 ответ

Решение

Я думаю, я понял, что происходит. Позвольте мне объяснить это.

Из tty # 1 (pts/2):

[STEP 300] # tty
/dev/pts/2
[STEP 301] # ssh -o ControlMaster=yes -o ControlPath=/tmp/socket.ssh -N -f 127.0.0.1 < /dev/null >& /dev/null
[STEP 302] # ps -C ssh j
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    1  4052  4052  4052 ?           -1 Ss       0   0:00 ssh -o ControlMaster=yes -o ControlPath=/tmp/socket.ssh -N -f 127.0.0.1
[STEP 303] # ls -l /proc/4052/fd/
total 0
lr-x------ 1 root root 64 2017-06-12 22:59 0 -> /dev/null
l-wx------ 1 root root 64 2017-06-12 22:59 1 -> /dev/null
l-wx------ 1 root root 64 2017-06-12 22:59 2 -> /dev/null
lrwx------ 1 root root 64 2017-06-12 22:59 3 -> socket:[370151]
lrwx------ 1 root root 64 2017-06-12 22:59 4 -> socket:[370201]
[STEP 304] # ssh -o ControlMaster=no -o ControlPath=/tmp/socket.ssh 127.0.0.1 sleep 3600 &
[1] 4062
[STEP 305] #    <-- Cannot input anything

Иди иди на номер 2 (pts/3):

[STEP 401] # tty
/dev/pts/3
[STEP 402] # ps t pts/2 j
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
  579  3552  3552  3552 pts/2     3552 Ss+      0   0:00 bash
 3552  4062  4062  3552 pts/2     3552 S        0   0:00 ssh -o ControlMaster=no -o ControlPath=/tmp/socket.ssh 127.0.0.1 sleep 3600
[STEP 403] # ls -l /proc/4062/fd/    # The `ssh ... sleep' process
total 0
lrwx------ 1 root root 64 2017-06-12 23:00 0 -> /dev/pts/2
lrwx------ 1 root root 64 2017-06-12 23:00 1 -> /dev/pts/2
lrwx------ 1 root root 64 2017-06-12 23:00 2 -> /dev/pts/2
lrwx------ 1 root root 64 2017-06-12 23:00 3 -> socket:[370349]
[STEP 404] # ls -l /proc/4052/fd/    # The `ssh -o ControlMaster=yes' process
total 0
lr-x------ 1 root root 64 2017-06-12 22:59 0 -> /dev/null
l-wx------ 1 root root 64 2017-06-12 22:59 1 -> /dev/null
l-wx------ 1 root root 64 2017-06-12 22:59 2 -> /dev/null
lrwx------ 1 root root 64 2017-06-12 22:59 3 -> socket:[370151]
lrwx------ 1 root root 64 2017-06-12 22:59 4 -> socket:[370201]
lrwx------ 1 root root 64 2017-06-12 23:02 5 -> socket:[370350]
lrwx------ 1 root root 64 2017-06-12 23:02 6 -> /dev/pts/2
lrwx------ 1 root root 64 2017-06-12 23:02 7 -> /dev/pts/2
lrwx------ 1 root root 64 2017-06-12 23:02 8 -> /dev/pts/2
[STEP 405] #

ВыводSTEP 403 показывает, что ssh ... sleep процесс ' stdin/stdout/stderr открыт pts/2, Это нормально.

Но вывод STEP 404(по сравнению с STEP 303) показывает, что ssh -o ControlMaster=yes процесс также открывается pts/2, Я считаю, что так работает мультиплексный SSH - новый ssh ... sleep процесс передает свои открытые файловые дескрипторы ssh -o ControlMaster=yes обрабатывать через сокет домена UNIX (-o ControlPath=/tmp/socket.ssh). Так что на самом деле ssh -o ControlMaster=yes Процесс, который потребляет весь вклад от pts/2, И так как ssh -o ControlMaster=yes процесс не находится в том же сеансе процесса, что и bash процесс (и ssh ... sleep) поэтому механизм управления заданиями не применяется к нему, даже если он работает в фоновом режиме (как демон) и читает из pts/2,

Поместите это по-другому: SIGTTIN отправляется только процессу, который выполняется как фоновое задание и пытается прочитать с его управляющего терминала. Здесь ssh -o ControlMaster=yes Процесс работает в фоновом режиме, но это не работа bash сеанс процесса, и он не имеет управляющего терминала вообще.


Немного больше о передаче FD между процессами через доменные сокеты UNIX (из Википедии):

В дополнение к отправке данных процессы могут отправлять файловые дескрипторы через соединение с сокетом домена Unix, используя sendmsg() а также recvmsg() системные вызовы. Это позволяет отправляющим процессам предоставлять принимающему процессу доступ к дескриптору файла, к которому у принимающего процесса в противном случае нет доступа.

Другие вопросы по тегам