【问题标题】:Why a background ssh can take over the tty from Bash?为什么后台 ssh 可以从 Bash 接管 tty?
【发布时间】:2017-06-12 05:59:52
【问题描述】:

(我在 Debian 8 上使用 Bash 4.4.12。bash mailing list 中也提出了问题。)

请参阅以下步骤来重现问题。

来自 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>

STEP 102 启动了作为守护进程运行的多路复用 SSH 连接。 STEP 105 尝试使用多路连接来运行sleep 命令。但是我不能在当前的shell中输入任何东西。如果我终止 ssh ... sleep &amp; 进程,那么 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 读取时停止。

【问题讨论】:

  • 当你尝试 +Z 时会发生什么?
  • 刚试过。什么都不会发生。

标签: bash ssh pty job-control process-group


【解决方案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

去吧tty #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/stderrpts/2 上打开。这是正常的。

STEP 404 的输出(与STEP 303 相比)显示ssh -o ControlMaster=yes 进程也在打开pts/2。我相信这就是多路复用 SSH 的工作原理——新的 ssh ... sleep 进程通过 UNIX 域套接字 (-o ControlPath=/tmp/socket.ssh) 将其打开的文件描述符传递给 ssh -o ControlMaster=yes 进程。所以实际上是ssh -o ControlMaster=yes 进程消耗了来自pts/2 的所有输入。由于ssh -o ControlMaster=yes 进程与bash 进程(和ssh ... sleep)不在同一个进程会话中,因此作业控制机制不适用于它,即使它在后台运行(作为守护进程)并从pts/2.

换一种说法:SIGTTIN 仅发送到作为后台作业运行并尝试从其控制终端读取的进程。这里ssh -o ControlMaster=yes 进程在后台运行,但它不是bash 进程会话 的工作,它根本没有控制终端


更多关于通过 UNIX 域套接字在进程之间传递 FD(来自Wikipedia):

除了发送数据之外,进程还可以使用sendmsg()recvmsg() 系统调用通过Unix 域套接字 连接发送文件描述符。这允许发送进程授予接收进程访问文件描述符的权限,否则接收进程无权访问该文件描述符。

【讨论】:

    猜你喜欢
    • 2011-05-08
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 2021-09-28
    • 2020-06-22
    • 1970-01-01
    • 2020-04-02
    相关资源
    最近更新 更多