关于如何包装Execvp调用的困惑

时间:2016-02-22 21:53:20

标签: c process io

我无法获得使用execvp调用的程序的完整输出。在这里,我基本上尝试使用可以过滤输入和输出的程序来包装任何程序:

#define BUF_SIZ 8192
int main(int argc, char **argv) {
    int outp[2]; // r, w
    int inp[2];
    pid_t pid;
    char buf[BUF_SIZ];
    fd_set fds;
    struct timeval tv;

    tv.tv_sec = 0;
    tv.tv_usec = 300000;
    if (pipe(outp) < 0 || pipe(inp) < 0) return 1;
    if ((pid = fork()) < 0) return 2;
    else if (pid) {
        close(outp[1]);
        close(inp[0]);
        dup2(outp[0], STDIN_FILENO);
        dup2(inp[1], STDOUT_FILENO);
        execvp(*(argv + 1), argv + 1);
    } else {
        while (1) {
            FD_ZERO(&fds);
            FD_SET(STDIN_FILENO, &fds);
            FD_SET(inp[0], &fds);
            if (select(inp[0] + 1, &fds, NULL, NULL, &tv) < 0) exit(3);
            if (FD_ISSET(STDIN_FILENO, &fds))
                write(outp[1], buf, read(STDIN_FILENO, buf, BUF_SIZ));
            if (FD_ISSET(inp[0], &fds))
                write(STDOUT_FILENO, buf, read(inp[0], buf, BUF_SIZ));
        }
    }

    return 0;
}

如果我使用该程序调用shell sh,我会得到以下输出(我没有收到提示):

$ ./shell sh    
echo "test"
test
^C

如果我尝试运行Python;我没有收到任何输出:

$ ./shell python
print "test"
^C

为什么我没有收到(大多数)输出?

1 个答案:

答案 0 :(得分:3)

问题是,shell和python解释器的stdin不是终端。在这种情况下,两个程序的行为都有所不同:

  • shell不会发出提示
  • Python希望首先从stdin(直到EOF)读取其完整脚本

例如,要使python脚本工作,你必须从你的 stdin中捕获EOF(读取返回0),在这种情况下,关闭你的python进程的stdin。然后,您可以通过按终端上的CTRL + D来调用EOF。

if (select(inp[0] + 1, &fds, NULL, NULL, &tv) < 0) exit(3);
if (FD_ISSET(STDIN_FILENO, &fds)) {
    int st = read(STDIN_FILENO, buf, BUF_SIZ));
    if (st > 0)
        write(outp[1], buf, st);
    else {
        close(outp[1]);
    ...

如果您想拥有一个交互式终端,您必须打开一个新的伪终端,forkpty(3)将为您完成大部分工作。