python - 使用 Ubuntu 和 pty 不合适的 ioctl
问题描述
我正在开发一个用 python 编写的终端多路复用器。在基于 Ubuntu 的发行版上,我看到了错误:
bash: cannot set terminal process group (9862): Inappropriate ioctl for device
bash: no job control in this shell
tmp@tmp-VirtualBox:
在 openSuSE 和 Fedora 上,我没有看到 ioctl 错误,并且作业控制工作正常。
示例问题:
#!/usr/bin/python3
import subprocess
import sys
import pty
import os
master, slave = pty.openpty()
bashCMD = "bash".split()
p = subprocess.Popen(bashCMD, preexec_fn=os.setsid, stdin=slave, stdout=slave, stderr=slave, universal_newlines=True, shell=True)
while p.poll() is None:
data = os.read(master, 1026)
print(str(data))
解决方案
好的,pty.fork() 适用于所有平台。
但它不允许我们像 pty.openpty() slave 那样写入 TTY
为了解决这个问题,我使用了 mmap
#write tty device info to memory the child and parent process can read
slaveFd, tmpfile = tempfile.mkstemp()
os.write(slaveFd, b'\x00' * mmap.PAGESIZE)
os.lseek(slaveFd, 0, os.SEEK_SET)
def getSlaves():
raw = getSlavesRaw()
returnData = []
for lessRaw in raw.strip('/').split('/'):
returnData.append("/dev/pts/" + str(lessRaw))
return returnData
def getSlavesRaw():
os.lseek(slaveFd, 0, os.SEEK_SET)
buf = mmap.mmap(slaveFd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_READ)
msg = str(buf.readline())
msg = ':'.join(msg.split(':')[:-1]).split("'")[-1]
return(msg)
def addSlave(PID):
offset = getSlavesRaw()
offset = len(offset)
os.lseek(slaveFd, offset, os.SEEK_SET)
buf = mmap.mmap(slaveFd, mmap.PAGESIZE, mmap.MAP_SHARED, mmap.PROT_WRITE)
TTY = subprocess.check_output(['ps', 'hotty', str(PID)]).strip().decode()
TTY = TTY.split("pts")[-1] + ":" # cut off pts and add a : for spacing
for index in range(offset, offset + len(TTY)):
buf[index] = ord(TTY[index - offset])
#Thanks! https://stackoverflow.com/a/52157066/5282272
# fork this script such that a child process writes to a pty that is
# controlled or "spied on" by the parent process
(child_pid, newMasterHandle) = pty.fork()
masters.append(newMasterHandle)
# A new child process has been spawned and is continuing from here.
# The original parent process is also continuing from here.
# They have "forked".
if child_pid == 0:
debug("This is the child process fork, pid %s" % os.getpid())
addSlave(os.getpid())
bashProcessList.append(subprocess.run("bash"))
else:
debug("This is the parent process fork, pid %s" % os.getpid())
debug(getSlaves())
while True:
try:
data = os.read(masters[myScreen], 1026)
except Exception:
#time.sleep(.2)
continue
yield data
推荐阅读
- python - 如何在Excel中返回未知列长度的非空顶行列值?
- jquery - 如何实现基于规则选择一年中一周的日期选择器?
- javascript - Bokeh CustomJS 问题与解构实例
- python - sklearn.manifold 导入 MDS 没有名为“numpy.random.bit_generator”的模块
- c# - 具有多个视图相同 ViewModel 的棱镜导航
- ruby-on-rails - Had to re-write a DB Query for Rails 6 due to Squeel gem: Error: undefined method `call' for #
- authentication - 未注册类型“Microsoft.AspNetCore.Identity.UserManager`1[ABC_App.Repository.Models.ApplicationUser]”的服务
- web - 为请求输入创建网站(包括保存文件)
- reactjs - 来自一个客户端的多个 Socket.IO 实例
- linux - 读取大型 gb 文件并收到错误“client_loop:发送断开连接:管道损坏”