0
  • 我有一个程序,popen()另一个程序也是dup()标准输出
  • 当从另一个进程(如 PHP 示例)通过 SSH 调用时,该进程不会退出。

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-> 正常退出
  • ruby -e 'system("./a.out");'-> 正常退出
  • php -r passthry("./a.out");-> 挂起
  • ssh remotehost ./a.out-> 挂起
  • 当我不dupstdout 或关闭 dup 时,它不会挂起

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

使用 fork/pcntl/etc 从多个 PHP 应用程序/框架中提取它需要几个小时。来衡量他们的关系,即我没有写这个或编造这个;但很明显,由于我把所有东西都拆开,它的整体感觉就消失了。

问题

  • 为什么有些调用会挂起 (php, ssh) 而其他的不会 (ruby) ?
  • 即使我在弹出关闭 fd ,我的程序也会挂起;为什么?
4

1 回答 1

0

Because when calling the program via ssh a dup on stdoud is made by ssh, so when ssh try to end it cannot because the stdout has also another channel opened.

I try to give you a better answer: stdout is the channel number 1 if i remember correctly. Making the dup we have also the new channel 3 that is pointing to stdout. When ssh try to close the channel 2 togheter to channel 0 and 2 (stdinput and stderr) ssh cannot close itself because there is another resource that occupies the channel 3 or better the stdout.

I hope that's enough clear gaetano

If I run your demo as it is and I get errno = 15 or it could be 16 as described at the end of this answer. But, if I run it in different way:

#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);
}

I don't get any more the error. To check the error under bash I use: echo $?

That means you have to realease all allocated resources before to exit the c program.

I hope that's all.

Best reagards gaetano

    #define ENOTBLK     15  /* Block device required */
    #define EBUSY       16  /* Device or resource busy */
于 2014-11-27T22:23:33.927 回答