简体   繁体   English

防止POSIX系统上的文件描述符关闭

[英]Prevent a file descriptor's closure on POSIX systems

There is a library (libvte, a terminal emulation library) that uses a pair of file descriptors for a pty master/slave pair. 有一个库(libvte,一个终端仿真库),它使用一对文件描述符作为pty主/从对。 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). 我需要能够从库中“窃取”主fd以供我自己使用(为了在非常罕见的情况下实现对ZMODEM的支持,因为我对'net的唯一链接是通过终端)。 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. 您可以告诉libvte您要将文件描述符更改为新文件描述符,但它会尝试关闭它正在使用的主文件,然后开始使用新文件描述符。 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. 最初,我认为可以在pty主服务器上使用dup() ,这样当libvte在PTY主服务器上执行close()时,我仍然可以使用正常运行的fd。 That is apparently wrong. 这显然是错误的。

I need to find a way to either: 我需要找到一种方法:

  • Block libvte's read() operations on the fd. 阻止libvte对fd的read()操作。
  • Steal the fd away from libvte until I'm doing using it (eg, until the rz process that I am connecting it to exits) 将fd从libvte中偷走,直到我正在使用它(例如,直到rz进程,我将它连接到退出)

Is it possible on a POSIX system to do either of these things? 在POSIX系统上可以做这些事情中的任何一个吗? Or would there be some other way to accomplish the same thing without patching libvte itself? 或者,如果不修补libvte本身,还会有其他方法来完成同样的事情吗? 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. 如果它完全相关,我通过Python与libvte(和GTK +本身)连接。 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. 但是,我不反对在C中编写Python扩展,然后我可以从Python程序调用,因为您不必在任何系统上获得加载Python扩展的特权。

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! 如果没有可能,我可能会被迫分叉libvte来做我想做的事情并用我的程序分发,但我不想那样做 - 我不想被卡住维持一个叉子!

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: 一种可能的解决方案是编写一个辅助进程,它打开自己的pty主/从对,并插入libvte和在slave pty上运行的实际目标程序:

+---------------+
| libvte        |
|               |
|    pty master=|-----\
+---------------+     |
                      |
+---------------+     |
| helper proxy  |     |
|               |     |
|  stdin/stdout=|-----/
|               |
|    pty master=|-----\
+---------------+     |
                      |
+---------------+     |
| target        |     |
|               |     |
|  stdin/stdout=|-----/
+---------------+

Your helper process normally just passes through data, until it sees ZMODEM traffic. 您的帮助程序通常只会传递数据,直到它看到ZMODEM流量。 It then stops passing data to stdin / stdout (which winds up at libvte ) and instead either passes it to your application through a separate file descriptor, or even just invokes rz itself. 然后它停止将数据传递给stdin / stdout (在libvte ),而是通过单独的文件描述符将其传递给应用程序,甚至只调用rz本身。

dup() 'd file descriptors are not affected by close() calls of other instances; dup() 'd文件描述符不受其他实例的close()调用的影响; however, it's possible libvte may be calling some other shutdown methods which do change its state. 但是,libvte可能会调用其他一些确实改变其状态的关闭方法。 Use strace to investigate in more detail. 使用strace进行更详细的调查。

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. 一种选择是从libvte下替换文件描述符。 That is: 那是:

  • First, use dup() to get your own copy of the fd, and stash it somewhere 首先,使用dup()获取自己的fd副本,并将其存放在某处
  • Use dup2() to overwrite libvte's fd with one of your own choosing. 使用dup2()用你自己选择的一个覆盖libvte的fd。 This should be a new pty with a configuration similar to that of the one you're stealing, to avoid confusing libvte. 这应该是一个新的pty,配置类似于你偷窃的配置,以避免混淆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!) 因为你永远不会把任何东西写到另一端,所以读取会阻塞(你需要对libvte可能写下的任何数据做些什么!)
  • If libvte may be in a blocking read() at that very moment, send a signal to its thread (with a no-op - not SIGIGN - handler) to interrupt the read() call. 如果libvte当时可能处于阻塞read()中,则向其线程发送信号(使用no-op - 而不是 SIGIGN - 处理程序)来中断read()调用。
  • Do your work with the fd you duplicated at the start 在开始时使用您复制的fd进行工作
  • To return to normal, use dup2() to put the fd back, then copy any pty state changes libvte may have made to the original descriptor. 要恢复正常,请使用dup2()将fd放回,然后复制libvte可能对原始描述符所做的任何pty状态更改。

Alternately, you can do as caf suggests, and simply have a proxy pty in there from the start. 或者,您可以像caf建议的那样做,并且从一开始就只需要一个代理pty。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM