2013-12-17 71 views
0

我需要fork一个进程,将输出(stdout和stderr)重定向到缓冲区。我的代码似乎适用于大多数二进制文件,但不是全部。例如,我可以使用ls -R/proc /这样一个非常长的“ls”来运行我的代码,并且它工作得很完美。当我运行mke2fs进程时,我的代码不再工作。当我重定向输出时,fork和wait处理不能用于mke2fs

如果我在fork中运行mke2fs并等待它,它就能正常工作。现在,如果我添加重定向的东西,我的程序永远不会完成运行。

我写了一个小主,以测试这个特定的麻烦:

#include <sys/wait.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 


int main() 
{ 
    pid_t pid; 
    int status = -42; 
    int pipefd_out[2]; 
    int pipefd_err[2]; 
    char buf_stderr[1024]; 
    char buf_stdout[1024]; 
    int count; 
    int ret; 

    pipe(pipefd_out); 
    pipe(pipefd_err); 

    memset (buf_stdout, 0, 1024); 
    memset (buf_stderr, 0, 1024); 

    pid = fork(); 

    if (pid == -1) 
    { 
    fprintf (stderr, "Error when forking process : /usr/sbin/mke2fs\n"); 
    return 1; 
    } 

    if (pid == 0) 
    { 
    close(pipefd_out[0]); 
    close(pipefd_err[0]); 

    dup2(pipefd_out[1], 1); 
    dup2(pipefd_err[1], 2); 

    close(pipefd_out[1]); 
    close(pipefd_err[1]); 

    char **args; 

    args = malloc (sizeof (1024)); 
    args[0] = strdup("/usr/sbin/mke2fs"); 
    args[1] = strdup("/dev/sda4"); 
    args[2] = strdup("-t"); 
    args[3] = strdup("ext4"); 
    args[4] = NULL; 

    execvp ("/usr/sbin/mke2fs", args); 

    /* 
    args = malloc (sizeof (1024)); 
    args[0] = strdup("/bin/ls"); 
    args[1] = strdup("-R"); 
    args[2] = strdup("/proc/irq"); 
    args[3] = NULL; 

    execvp ("/bin/ls", args); 
    */ 
    perror ("execv"); 
    fprintf (stderr, "Error when execvp process /usr/sbin/mke2fs\n"); 
    return 1; 
    } 
    close(pipefd_out[1]); 
    close(pipefd_err[1]); 

    if (waitpid(pid, &status, 0) == -1) 
    { 
    fprintf (stderr, "Error when waiting pid : %d\n", pid); 
    return 1; 
    } 

    do 
    { 
    count = read(pipefd_out[0], buf_stdout, sizeof(buf_stdout)); 
    } 
    while (count != 0); 
    do 
    { 
    count = read(pipefd_err[0], buf_stderr, sizeof(buf_stderr)); 
    } 
    while (count != 0); 

    ret = WEXITSTATUS(status); 

    FILE* file = NULL; 
    file = fopen("/root/TUTU", "w"); 

    if (file != NULL) 
    { 
    fwrite(buf_stdout, 1, sizeof(buf_stdout), file); 
    fwrite(buf_stderr, 1, sizeof(buf_stdout), file); 
    fclose(file); 
    } 

    return 0; 
} 

如果我运行ps的,我可以看到我的孩子进程在运行:

# ps | grep sda4 
    936 root  2696 S {mke2fs} /dev/sda4 -t ext4 

我无法理解为什么我有这种奇怪的行为。不知道它的相关,但mke2fs的输出是不经典的。这个过程似乎在计算过程中更新输出,而不是打印输出并提示提示。这是一种进度条。不知道我的解释是否真的很清楚。

谢谢, 伊娃。

回答

2

在从管道读取标准输出/标准错误之前,您不能等待程序完成(使用waitpid做什么)。当程序写入管道时,它会一直睡眠,直到从管道读取数据为止。所以程序会等待管道中有更多空间,然后才能继续并退出,而在等待程序退出之前,请先阅读管道以腾出空间。

在这种情况下,最简单的解决方案是将waitpid移动到读完管道后。应该没问题,因为你执行的程序会在退出时关闭管道。

+1

由于父级尝试读取所有孩子的标准输出,然后读取其所有标准错误,所以仍然存在潜在的死锁。如果stderr管道在程序完成之前填满,则在母公司仍在尝试读取标准输出时,将阻止写入标准错误。 “捕获标准输出和标准错误”不是一件简单的工作。 –

+0

@Wumpus Q. Wumbley:的确,我得到这个问题是因为我读stdout然后stderr。我想我可能会尝试使用pthread在同一时间读取它们。 – ArthurLambert