如何将 ^D / EOT 字符发送到 shell 进程的标准输入?

如何将 ^D / EOT 字符发送到 shell 进程的标准输入?

假设我打开了两个 shell,一个 PID 为 1234,另一个为 5678。

我可以清除屏幕并重置另一个 shell,echo $'\033c' > /proc/1234/fd/0就像reset在终端本身的提示符上键入一样。但是,当我echo $'\04' > /proc/1234/fd/0发送 EOT 字符时,这似乎不起作用。怎样才能达到想要的效果呢?

答案1

首先,一个 tty,即使它看起来是一个文件对象,实际上也是一对管道/队列——一个用于输出,一个用于输入,每个管道/队列的另一端连接到某些硬件设备,或者在伪终端的情况下可供另一个程序使用。当您向链接到 tty 的 fd 写入任何内容时,您正在写入输出队列,即使那是进程的 fd 0 (stdin),并且不会循环回输入队列。

在大多数 Unix 系统上(值得注意的是开放BSD),有一个特殊的 ioctl ( TIOCSTI),它允许您将一个字节插入到 tty 的输入队列中,就好像它是从另一端接收到的一样。TIOCSTI仅当未在调用它的进程的控制 tty 上使用时,才会以 root 身份工作。

$ cc -Wall tiocsti.c -o tiocsti

-- 作为根用户 --

# printf '\04' | ./tiocsti >/proc/5460/fd/0

如果您的进程在伪 tty 中运行,“假”输入的另一种方法是使用调试器连接到持有伪 tty 的主端的进程,并write(2)从那里将您的内容放入其中。

$ gdb -p pid_of_xterm
(gdb) p write(4, "\x04", 1)   # 4 is the fd of the master pty
(gdb) c

两种方法都只是矫枉过正。如果您想控制正在运行的进程,最好将调试器附加到该进程,而不是伪造一些输入;如果你想工具化一个交互式程序,你最好运行它expect;两者都可以在任何 Unix 系统上运行,并且不需要额外的权限。

另请注意,^D/\004只会起作用,EOF就像A)tty 处于规范模式)c_cc[VEOF]特殊字符没有更改为其他字符C)输出队列为空(否则c_cc[VEOF]必须发送两次)。当然,只是从 tty 读取数据的进程将获得 EOF 或那些字节,而不一定是 shell。

tiocsti.c

#include <sys/ioctl.h>
#include <unistd.h>
#include <err.h>

int main(void){
        char c; ssize_t r;
        while((r = read(0, &c, 1)) > 0){
                if(ioctl(1, TIOCSTI, &c)) err(1, "ioctl(TIOCSTI)");
        }
        if(r < 0) err(1, "read");
        return 0;
}

相关内容