c - 如果未在父级中关闭,则从属 pty 上的最终输出将丢失。为什么?

标签 c unix portability freebsd pty

我编写并维护了一个程序 rlwrap它使用伪终端与子进程通信。 Pseudo-terminals (ptys) 存在于所有 Unix(类)系统中,但它们在不同平台上的行为略有不同。

恰当的例子:在 rlwrap 中,父进程使从 pty 保持打开状态以密切关注子进程的终端设置(在 Linux 和 FreeBSD 上可以使用主进程,但在 Solaris 中不行, 例如)

在 FreeBSD (8.2)(但不是 Linux)上,这会导致子进程的最终输出丢失。例如:

#include <stdio.h>

/* save as test.c and compile with gcc -o test test.c -lutil */

#define BUFSIZE 255

int main(void) {
  int master, slave;
  char buf[BUFSIZE];
  int nread;

  openpty(&master, &slave, NULL, NULL, NULL);

  if (fork()) {       /* parent:                                                      */
    close(slave);     /* leave this out and lose slave's final words ... WHY?         */
    do {
      nread = read(master, buf, BUFSIZE);
      write(STDOUT_FILENO, buf, nread); /* echo child's output to stdout              */
    } while (nread > 0);     
  } else {             /* child:                                                      */
    login_tty(slave);  /* this makes child a session leader and slave a controlling   */
                       /* terminal for it, then dup()s std{in,out,err} to slave       */ 
    printf("Feeling OK :-)\n");
    sleep(1);
    printf("Feeling unwell ... Arghhh!\n"); /* this line may get lost                 */
  }
  return 0;
}

父进程将按预期回显子进程的输出,但是当我省略 close(slave) 时(保持打开状态,就像在 rlwrap 中一样):

  • 在 FreeBSD 上,父级看不到最终输出行,而是读取 EOF。 (如果有的话,我会预料到相反的情况——保持从端打开会防止输出丢失)
  • 另一方面,在 Linux 上,从不看到 EOF,甚至 child 死后也看不到(无论我们是否关闭 slave)

是否在某处记录了此行为?有理由吗?在父进程中不关闭slave可以绕过吗?

我发现让从设备成为控制终端——用一些简单的dup()调用替换login_tty调用——将解决问题。然而,这不是 rlwrap 的解决方案:相当多的命令需要一个控制终端 (/dev/tty) 进行通信,因此 rlwrap 有为他们提供一个。

最佳答案

我认为 Pty 有独特的独立行为。

  1. 如果最后一个数据被写入,系统终止
  2. 如果 child 退出(破管?),系统终止

代码依赖于存在足够长的管道来发送数据,但是退出的子进程可能导致虚拟 channel 在接收到数据之前被删除。

这对于 Pty 来说是独一无二的,对于真正的终端来说是不存在的。

关于c - 如果未在父级中关闭,则从属 pty 上的最终输出将丢失。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23458160/

相关文章:

python - 将输入发送到直接输入(如游戏)

java - 有什么方法可以让依赖 Java7 和 JavaFX2 的程序运行 "portably"?

将 "for"循环转换为 "while"循环

从用户程序控制 TCP header 字段

c - 将 unsigned int(通过负数)分配给有符号 long long 时出现意外值

c++ - 编译 C++ 代码时在 sun 操作系统上出现 "const access error"

mysql - 连接/隧道连接到远程服务器以绕过防火墙

linux - 将 sprintf 替换为带有附加参数的 snprintf

python - 在一个 Bundle 中轻松部署 Python 和应用程序,适用于 Linux

java - 有没有办法让需要文件参数的命令行程序使用标准输入?