使用pty时污染父终端的子进程



示例

我在cli应用程序ngrok中注意到了这种行为。这只是本例的特殊之处,因为它会污染父进程终端。它的核心功能并不重要。

获取可执行文件:

wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
unzip ngrok-stable-linux-amd64.zip
# There is `ngrok` executable in this dir now

造成问题的代码:

# ngrok_python.py
# It's in the same dir as the ngrok executable
import pty
import subprocess
import shlex
import time
import sys
pty_master, pty_slave = pty.openpty()
ngrok_cmd = "./ngrok http 80" 
# This doesn't happen for others
# ngrok_cmd = "ls -la" 
ngrok = subprocess.Popen(shlex.split(ngrok_cmd), stdin=pty_slave, stdout=pty_slave, stderr=pty_slave)
# It also won't pollute the current terminal when redirected to DEVNULL
# ngrok = subprocess.Popen(shlex.split(ngrok_cmd), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print("The subprocess is attached to the pseudo terminal")
print("Its output should not be printed here")
print("Unless I decide to read from pty_master")
print("Checking a few times if the subprocess is done")
for i in range(3):
time.sleep(1)
if ngrok.poll is not None:
print("Subprocess finished")
sys.exit()
print("Don't want to wait any longer.")
# Running the command
python3 ngrok_python.py

预期行为

  • 唯一的输出将来自打印语句
  • subprocess具有自定义stdout/err/in。它无法访问主终端
  • 由于pty,如果我想读取子流程中发生的事情,我会从pty_master中读取

实际行为

  • 子流程./ngrok http 80的输出消耗终端

奇怪的是,运行注释掉的部分(ngrok_cmd = "ls -la"subprocess with subprocess.DEVNULL(会导致预期的行为。

问题

  1. 如果为孩子提供的stdout/err/in发生了更改,为什么孩子进程知道如何访问家长终端
  2. 如何在python中克服这一点

我不愿意运行从某个随机站点下载的可执行文件,但我愿意打赌ngrok会显式打开并写入/dev/tty,以显示其连接信息。

/dev/tty设备指的是进程的"控制终端",这是进程从其父进程继承的东西之一。重新分配子代的stdinstdoutstderr不影响其控制终端。因此,在这种情况下,子级保留与父级相同的控制终端,当子级打开并写入/dev/tty时,输出直接进入父级的屏幕,而不是通过子级的stdoutstderr或您的伪终端。

为了实现你想要的目标,你需要将孩子与父母的控制终端分离,并将伪终端的从端建立为孩子的控制终端。这涉及到对setsid和/或setpgrp的调用,一些文件描述符的杂耍,可能还有一些其他的回转。如果你在C.工作,所有这些都由login_tty处理

好消息是,Pythonpty模块中有一个方法可以为您完成所有这些工作。该方法是pty.spawn。它在Python 2和3中可用。我链接到了Python3文档,因为它好多了,还包括一个示例程序。pty.spawn基本上表现为forkexecopenptylogin_tty的组合。

如果你重新设计你的程序,使用pty.spawn来启动ngrok,那么我敢肯定你会得到你想要的行为。

相关内容

  • 没有找到相关文章

最新更新