强制使用`exec`创建的程序执行无缓冲的I / O.

时间:2013-12-13 16:43:45

标签: c io exec fork pipe

我正在尝试使用pipeforkexec与C中的外部程序进行互动。我想强制外部程序执行无缓冲的I / O.到目前为止,这是我的代码中的相关代码段:

...
pid = fork();
if (pid == (pid_t) 0)
{
    /* child process */

    /* make pipe connections to standard streams */             
    dup2(wpipe[0], STDIN_FILENO);
    dup2(rpipe[1], STDOUT_FILENO);

    /* close pipe endings */
    close(wpipe[0]); close(rpipe[0]);
    close(wpipe[1]); close(rpipe[1]);

    /* unbuffered I/O */
    setvbuf(stdin, NULL, _IONBF, BUFSIZ);
    setvbuf(stdout, NULL, _IONBF, BUFSIZ); 

    if (execl("path/to/some_binary", "path/to/some_binary", (char *) NULL) == -1)
    {
        fprintf(stderr, "exec failed\n");
        return EXIT_FAILURE;
    }   
    return EXIT_SUCCESS;
}
...

这不起作用,因为流不会在exec次调用中存活。因此,使用setvbuf强制无缓冲的I / O不起作用,因为程序映像(some_binary)创建了自己的stdin和stdout流,并且不使用我调用的流{{1} } 上。

在我的代码中添加setvbuf次调用后重新构建some_binary时,该程序可以正常工作。但是如果你对传递给setvbuf的二进制文件没有任何控制权,怎么办?如何使用例如execcat之类的unix命令?

2 个答案:

答案 0 :(得分:1)

在一般情况下你不能做你想要的事情(在任意可执行文件的execve(2)之后没有缓冲...)

缓冲由代码完成(例如,通过与libc相关的一些<stdio.h>代码完成。代码由程序execve - ed。

定义

您可能会在setvbuf(stdin, NULL, _IONBF, BUFSIZ);之后(但在execve ....之前)使用可能会调用main LD_PRELOAD tricks。但这只适用于动态链接的可执行文件。

也许在constructor - ed共享对象的某些初始化函数中使用一些LD_PRELOAD function attribute可能会有时执行此操作。或者在该共享对象中重新定义printffopen,....

附加物

您评论说:

  

使用两个管道与子流程进行双向通信。

然后你的方法是错误的。父进程应监视两个管道,可能使用多路复用调用poll(2),然后(根据多路复用的结果)决定读取或写入子进程。实际上,你需要一些event loop:你自己实现一个简单的事件循环 (例如poll [迭代地多次调用] 循环)或使用一些现有的(请参阅libeventlibev,或某些工具包提供的那个,如GTKQt等。 。)

您也可以与select(2)复用,但由于C10K problem

,我建议poll

阅读Advanced Linux Programming ...

,您不会浪费时间

另请参阅this answer您的下一个相关问题。

答案 1 :(得分:0)

您可能会尝试暂停任务,然后修改其图像。你可以通过gdb或/ proc文件系统来完成。 特别是,您可以访问通过/ proc文件系统创建的任务的所有fds。

更新:

如果缓冲由glibc完成,只需覆盖glibc中的相关函数,定义自己的函数,将其编译成共享库并加载程序。