防止 POSIX 系统上的文件描述符关闭
有一个库(libvte,终端仿真库)使用一对文件描述符来表示 pty 主/从对。我需要能够从库中“窃取”主文件供我自己使用(以便在极少数情况下实现对 ZMODEM 的支持,当我到网络的唯一链接是通过终端时)。然而,有一个问题。
您可以告诉 libvte 您想要将文件描述符更改为新的文件描述符,但随后它会尝试关闭正在使用的主文件描述符,并开始使用新的文件描述符。这是行不通的,因为当主机关闭时,从机就会消失。最初,我认为可以在 pty master 上使用 dup() ,这样当 libvte 在 PTY master 上执行 close()
时,我仍然会有一个可用的 fd 可以使用。这显然是错误的。
我需要找到一种方法:
- 阻止 libvte 对 fd 的 read() 操作。
- 从 libvte 中窃取 fd,直到我正在使用它(例如,直到我将其连接到的 rz 进程退出)
是否可以在 POSIX 系统上执行这些操作?或者是否有其他方法可以在不修补 libvte 本身的情况下完成同样的事情?我问的原因是该解决方案必须适用于相当多的现有系统。
如果它完全相关,我将通过 Python 与 libvte (和 GTK+ 本身)进行交互。但是,我并不反对用 C 语言编写 Python 扩展,然后可以从 Python 程序调用它,因为您不必在任何系统上拥有特权即可加载 Python 扩展。
如果这一切都不可能,我可能会被迫分叉 libvte 来做我想让它做的事情,并将其与我的程序一起分发,但我不想这样做 --- 我不想被困在维护一个叉!
There is a library (libvte, a terminal emulation library) that uses a pair of file descriptors for a pty master/slave pair. I need to be able to "steal" the master fd from the library for my own use (in order to implement support for ZMODEM for the very rare occasion when the only link I have to the 'net is via a terminal). However, there is a problem.
You can tell libvte that you want to change the file descriptor to a new one, but then it attempts to close the master that it is using, and start using the new one instead. This won't work, because when the master is closed the slave goes away. Originally, I thought that it would be possible to use dup()
on the pty master, such that when libvte did close()
on the PTY master, I'd still have a functioning fd to use. That is apparently wrong.
I need to find a way to either:
- Block libvte's
read()
operations on the fd. - Steal the fd away from libvte until I'm doing using it (e.g., until the
rz
process that I am connecting it to exits)
Is it possible on a POSIX system to do either of these things? Or would there be some other way to accomplish the same thing without patching libvte itself? The reason that I ask is that the solution has to work on a fair number of existing systems.
If it is at all relevant, I'm interfacing with libvte (and GTK+ itself) via Python. However, I'd not be averse to writing a Python extension in C that I could then call from a Python program, because you don't have to be privileged on any system to load a Python extension.
If none of it is possible, I may be forced to fork libvte to do what I want it to do and distribute that with my program, but I don't want to do that --- I do not want to be stuck maintaining a fork!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一种可能的解决方案是编写一个帮助程序进程,该进程打开自己的 pty 主/从对,并在
libvte
和在从属 pty 上运行的实际目标程序之间进行插入:您的帮助程序进程通常只是通过数据,直到看到 ZMODEM 流量。然后,它停止将数据传递到
stdin
/stdout
(最终到达libvte
),而是通过单独的文件描述符将其传递到您的应用程序,或者甚至只是调用 rz 本身。One possible solution would be to write a helper process which opens its own pty master/slave pair, and interposes between
libvte
and the actual target program that runs on the slave pty:Your helper process normally just passes through data, until it sees ZMODEM traffic. It then stops passing data to
stdin
/stdout
(which winds up atlibvte
) and instead either passes it to your application through a separate file descriptor, or even just invokesrz
itself.dup()
的文件描述符不受其他实例的close()
调用的影响;然而,libvte 可能会调用一些其他确实改变其状态的关闭方法。使用strace
进行更详细的调查。除此之外,还有一些事情你可以做,但没有一件是非常漂亮的。一种选择是替换 libvte 下的文件描述符。即:
read()
就在那一刻,向其线程发送一个信号(使用无操作 - not SIGIGN - 处理程序)以中断read()
调用。或者,您可以按照 caf 的建议进行操作,只需从一开始就在其中设置一个代理 pty 即可。
dup()
'd file descriptors are not affected byclose()
calls of other instances; however, it's possible libvte may be calling some other shutdown methods which do change its state. Usestrace
to investigate in more detail.Apart from that, there are a few things you can do, but none of them are very pretty. One option would be to replace the file descriptor from under libvte. That is:
dup()
to get your own copy of the fd, and stash it somewheredup2()
to overwrite libvte's fd with one of your own choosing. This should be a new pty with a configuration similar to that of the one you're stealing, to avoid confusing libvte. Since you'll never write anything to the other end, reads will block (you'll need to do something with any data libvte may write down there!)read()
at that very moment, send a signal to its thread (with a no-op - not SIGIGN - handler) to interrupt theread()
call.dup2()
to put the fd back, then copy any pty state changes libvte may have made to the original descriptor.Alternately, you can do as caf suggests, and simply have a proxy pty in there from the start.