通过ssh替换和打开stdin/stdout

5
我正在开发一个与子进程通信的系统,使用管道连接stdin和stdout。 子进程使用API库来促进这种通信,我需要为该库编写单元测试。 我找到的唯一正确测试这些函数的方法是替换stdin/stdout为管道,以便测试时可以在调用函数时假装成父系统。
/* replace stdin and stdout with pipes */
void setup(void) {
  pipe(in_sub);
  pipe(out_sub);

  dup2(out_sub[1], fileno(stdout));
  dup2( in_sub[0],  fileno(stdin));
  read_from = fdopen(out_sub[0], "rb");
  write_to  = fdopen( in_sub[1], "wb");

  stdout_t = fopen("/dev/tty", "wb");
  stdin_t  = fopen("/dev/tty", "rb");
}

/* reopen stdin and stdout for future test suites */
void teardown(void) {
  fclose(read_from);
  fclose(write_to);

  stdout = stdout_t;
  stdin  = stdin_t;

  close(in_sub[0]);
  close(in_sub[1]);
  close(out_sub[0]);
  close(out_sub[1]);
}

我已经尝试将stdin和stdout保存在temps中,并对它们使用fdopen()(应该可以工作,因为它们是FILE*),但是这并没有导致内容正确地写入管道。当直接从主机的shell上运行此代码时,它可以完美地工作。但是在通过ssh运行时,问题就出现了。单元测试执行得非常完美,但是在此测试套件之后,当我尝试向stdout写入任何内容时,会收到一个broken pipe错误。
有没有什么办法可以避免使用dup2,使得stdin和stdout永远不会关闭,或者如何重新打开stdin和stdout,以便它们在shell和ssh上能够正常工作?
1个回答

3

stdin和stdout只是指向一个结构体(对象)的FILE*,该结构体内部的fd设置为0(和1)。因此,当您执行dup2时,文件0和1将不再起作用。您需要做的是在执行dup2之前从头开始创建一个新的文件对象,这可能是您需要进行的所有修改;

void setup(void) {
  int dupin, dupout;

  dupin = dup(0);  // Create an extra fd to stdin
  dupout = dup(1);  // create an extra fd to stdout

  pipe(in_sub);
  pipe(out_sub);

  dup2(out_sub[1], fileno(stdout));
  dup2( in_sub[0],  fileno(stdin));
  read_from = fdopen(out_sub[0], "rb");
  write_to  = fdopen( in_sub[1], "wb");

  stdout_t = fdopen(dupout, "wb");
  stdin_t  = fdopen(dupin, "rb");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接