如果未在父级中关闭,则slave pty上的最终输出将丢失.为什么?

Han*_*Lub 30 c unix portability freebsd pty

我编写并维护了一个程序rlwrap,它使用伪终端与子进程通信. 在所有Unix(类似)系统中都可以找到伪终端(ptys),但它们在不同平台上的表现略有不同.

例证:在rlwrap,父进程保持slave pty打开以密切关注子进程的终端设置(在Linux和FreeBSD上可以使用master,例如在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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 在FreeBSD上,父节点没有看到最终的输出行,而是读取了EOF.(如果有的话,我会预料到相反的情况 - 保持奴隶端打开会阻止输出丢失)
  • 另一方面,在Linux上,EOF 从未见过,即使孩子死亡之后也是如此(无论我们是否关闭了奴隶)

这种行为是否记录在某处?有没有理由呢?我可以在不关闭父进程中的奴隶的情况下绕过它吗?

我发现不让奴隶成为一个控制终端 - 用login_tty一些简单的dup()电话取代电话 - 将解决问题.rlwrap然而,这不是解决方案:相当多的命令需要控制终端(/dev/tty)来与之通信,因此rlwrap必须为它们提供一个.

Rol*_*ith 0

在 FreeBSD 10-STABLE 上我确实得到了两条输出线。

(您可以替换openptyand fork,基本上也forkpty可以解决问题。)login_tty

在 FreeBSD 8.0 中,旧的pty(4)驱动程序被替换为pts(4). 新的pty(4)行为与旧的不同。来自手册;

与以前的实现不同,当 PTY 变得不使用时,主设备节点和从设备节点将被销毁。在不存在的主设备上调用 stat(2) 将导致创建新的主设备节点。主设备只能通过打开和关闭来破坏。

8.0-RELEASE 和 10.0-RELEASE 之间很可能存在重大变化

您可能还想查看FreeBSD ports 树中应用的补丁。