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

发布于 2024-11-16 16:26:50 字数 759 浏览 2 评论 0原文

有一个库(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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烂柯人 2024-11-23 16:26:50

一种可能的解决方案是编写一个帮助程序进程,该进程打开自己的 pty 主/从对,并在 libvte 和在从属 pty 上运行的实际目标程序之间进行插入:

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

您的帮助程序进程通常只是通过数据,直到看到 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:

+---------------+
| 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. 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.

a√萤火虫的光℡ 2024-11-23 16:26:50

dup() 的文件描述符不受其他实例的 close() 调用的影响;然而,libvte 可能会调用一些其他确实改变其状态的关闭方法。使用 strace 进行更详细的调查。

除此之外,还有一些事情你可以做,但没有一件是非常漂亮的。一种选择是替换 libvte 下的文件描述符。即:

  • 首先,使用 dup() 获取您自己的 fd 副本,并将其存储在某个位置
  • 使用 dup2() 来使用您自己选择的文件覆盖 libvte 的 fd 之一。这应该是一个新的 pty,其配置与您要窃取的 pty 类似,以避免混淆 libvte。由于您永远不会向另一端写入任何内容,因此读取将会阻塞(您需要对 libvte 可能写下的任何数据执行某些操作!)
  • 如果 libvte 可能处于阻塞 read()就在那一刻,向其线程发送一个信号(使用无操作 - not SIGIGN - 处理程序)以中断 read() 调用。
  • 使用在开始时复制的 fd 进行工作
  • 要恢复正常,请使用 dup2() 放回 fd,然后复制 libvte 可能对原始描述符所做的任何 pty 状态更改。

或者,您可以按照 caf 的建议进行操作,只需从一开始就在其中设置一个代理 pty 即可。

dup()'d file descriptors are not affected by close() calls of other instances; however, it's possible libvte may be calling some other shutdown methods which do change its state. Use strace 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:

  • First, use dup() to get your own copy of the fd, and stash it somewhere
  • Use dup2() 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!)
  • 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.
  • Do your work with the fd you duplicated at the start
  • 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.

Alternately, you can do as caf suggests, and simply have a proxy pty in there from the start.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文