为什么dup()和popen()阻止我的进程从另一个进程调用时退出?

时间:2014-11-27 22:15:41

标签: c ssh posix popen dup

  • 我有一个popen()到另一个以及dup() stdout
  • 的程序
  • 当通过SSH从另一个进程(如PHP示例)调用时,该进程不会退出。

process_test.c

#include <stdio.h>
#include <unistd.h> 

int main() {
  int out;

  out = dup(STDOUT_FILENO);
  // close(out);

  popen("sleep 10\0", "r");
}

使用gcc process_test.c进行编译,使用以下命令运行:

  • ./a.out - &gt;通常退出
  • ruby -e 'system("./a.out");' - &gt;通常退出
  • php -r passthry("./a.out"); - &gt;挂起
  • ssh remotehost ./a.out - &gt;挂起
  • 当我没有dup stdout或关闭dup时,它不会挂起

这是我能找到的最短可重现的代码,它向我展示了一种我想要更好理解的行为。

使用fork / pcntl / etc从多个PHP应用程序/框架中提取它需要花费数小时。修好他们的关系,即我没有写下这个或者说这个;但很显然,由于我将所有东西分开,所以它的整体意识都会丢失。

问题

  • 为什么有些调用挂起(php,ssh)而其他调用挂起(ruby)?
  • 即使我关闭了>之后的fd ,我的程序也会挂起;为什么呢?

1 个答案:

答案 0 :(得分:0)

因为当通过ssh调用程序时,stdoud上的dup是由ssh生成的,所以当ssh尝试结束时它不能,因为stdout还有另一个通道已打开。

我试着给你一个更好的答案: 如果我没记错的话,stdout就是1号频道。制作dup我们还有指向stdout的新频道3。 当ssh尝试关闭通道2 togheter到通道0和2(stdinput和stderr)时,ssh无法自行关闭,因为有另一个资源占用了通道3或更好的stdout。

我希望这一点足够明确 加埃塔诺

如果我按原样运行你的演示,我得到errno = 15,或者它可以是16,如本答案结尾所述。 但是,如果我以不同的方式运行它:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int out;
    int status;

    out = dup(STDOUT_FILENO);
    // close(out);
    FILE *fp = popen("sleep 10\0", "r");
    status = pclose(fp);
    if (status == -1) {
            printf("pclose error: %d", errno);
    }
   close(out);
}

我再也没有得到错误。 要检查bash下的错误,我使用:echo $?

这意味着您必须在退出c程序之前重新发布所有已分配的资源。

我希望这一切。

最好的反馈 加埃塔诺

    #define ENOTBLK     15  /* Block device required */
    #define EBUSY       16  /* Device or resource busy */