当我重定向输出时,fork和wait进程不能与mke2fs一起使用

时间:2013-12-17 12:21:52

标签: c linux fork dup2

我需要派生一个进程,在缓冲区中重定向输出(stdout和stderr)。我的代码似乎适用于大多数二进制文件,但不是全部。例如,我可以用很长的“ls”运行我的代码,比如ls -R / proc /,它运行得很好。当我运行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的输出不是经典的。该进程似乎在计算期间更新输出,而不是打印输出并向前移动提示。这是一种进步条。不确定我的解释是否真的很清楚。

谢谢, EVA。

1 个答案:

答案 0 :(得分:2)

在从管道读取stdout / stderr之前,您无法等待程序完成(使用waitpid执行的操作)。当程序写入管道并且它已满时,它将一直处于休眠状态,直到您从管道读取以在其中留出空间为止。因此,程序会等到管道中有更多空间才能继续并退出,而您在从管道读取空间之前等待程序退出。

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