pipe() - 程序导致EIO

时间:2014-06-01 19:54:05

标签: c unix pipe ioerror

我们有一个家庭作业问题,我们必须编写一个带有两个参数的程序,将它们作为shell命令执行,将第一个程序的stdout输入到第二个程序的stdin中。

这是我的solution这个家庭作业问题。同样的文件转载如下。

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

#define SHELL   "/bin/sh"

extern int  main(int, char*[]);
static int  readingend(int, int, const char*);
static int  writingend(int, int, const char*);
static int  usr1handler();

extern int
main(int argc, char *argv[])
{
    int pipefd[2], status;
    pid_t rpid, wpid;

    if (argc != 3) {
        fprintf(stderr, "Invalid argument count\n");
        return (EXIT_FAILURE);
    }

    if (pipe(pipefd)) {
        perror("Cannot make a pipe");
        return (EXIT_FAILURE);
    }

    signal(SIGUSR1, (void(*)(int))usr1handler);

    if ((rpid = fork()) < 0) {
        perror("Cannot fork");
        return (EXIT_FAILURE);
    }

    if (rpid == 0)
        return (readingend(pipefd[0], pipefd[1], argv[2]));


    if ((wpid = fork()) < 0) {
        perror("Cannot fork");
        kill(rpid, SIGKILL);
        return (EXIT_FAILURE);
    }

    if (wpid == 0)
        return (writingend(pipefd[0], pipefd[1], argv[1]));

    close(pipefd[0]);
    close(pipefd[1]);

    waitpid(rpid, &status, 0);
    return (status);
}

static int
readingend(int rfd, int wfd, const char *cmd)
{
    close(wfd);
    dup2(rfd, STDIN_FILENO);

    /* execl() only returns on error */
    execl(SHELL, SHELL, "-c", cmd, NULL);
    fprintf(stderr, "Cannot execute %s: ", cmd);
    perror(NULL);

    /* clean up */
    kill(getppid(), SIGUSR1);
    return (EXIT_FAILURE);
}

static int
writingend(int rfd, int wfd, const char *cmd)
{
    close(rfd);
    dup2(wfd, STDOUT_FILENO);

    execl(SHELL, SHELL, "-c", cmd, NULL);
    fprintf(stderr, "Cannot execute %s: ", cmd);
    perror(NULL);

    /* clean up */
    kill(getppid(), SIGUSR1);
    return (EXIT_FAILURE);
}

static int
usr1handler()
{
    /* child already printed diagnostic */
    exit(EXIT_FAILURE);
}

问题在于,在某些调用中,第一个进程在从stdin读取时收到EIO。这似乎只发生在一些shell上:它发生在ksh93bash但不发生在bosh。这样的错误看起来像这样:

$ LANG=C ./mypipe cat true
$ cat: -: Input/output error

有人可以告诉我为什么会出现这种错误吗?我该怎么办才能让错误再次发生?显然必须有一种方法,因为在普通shell中执行cat | true会产生所需的结果,而不会产生任何虚假的EIO

1 个答案:

答案 0 :(得分:0)

发生此问题是因为true立即终止,导致mypipe终止,导致cat孤立。如果发生这种情况,read()可能会失败:

  

EIO

     

该进程是尝试从其控制终端读取的后台进程的成员,该进程忽略或阻止SIGTTIN信号,或者进程组是孤立的。出于实现定义的原因,也可能会生成此错误。

可以通过等待这两个进程来阻止此问题:

extern int
main(int argc, char *argv[])
{
    int status, estatus;

    /* ... */


    /* wait for both processes to terminate */
    if (wait(&status) == rpid) {
        estatus = status;
        wait(&status);
    } else {
        wait(&status);
        estatus = status;
    }

    return (estatus);
}