JosepRivaille JosepRivaille - 6 months ago 80
Linux Question

wc: standard input: Bad file descriptor on fork + pipe + execlp

I know this is a simple exercise but I'm having troubles with it. I'm trying to emulate:

grep arg1 arg2 | wc -l


I'm getting the following error: "wc: standard input: Bad file descriptor when executing". This is my code:

int main(int argc, char *argv[])
{
if (argc != 3) usage();
int pd[2]; //Pipe descriptor
pipe(pd);
int pid = fork();
if (pid < 0) perror("Something failed on trying to create a child process!\n");
else if (pid == 0) { //Child
dup2(pd[1], 0);
close(pd[0]);
close(pd[1]);
execlp("wc", "wc", "-l", (char *)NULL);
} else { //Parent
dup2(pd[0], 1);
close(pd[0]);
close(pd[1]);
execlp("grep", "grep", argv[1], argv[2], (char *)NULL);
}
}


What can be the problem?

Answer

You have:

else if (pid == 0) { //Child
    dup2(pd[1], 0);
    close(pd[0]);
    close(pd[1]);
    execlp("wc", "wc", "-l", (char *)NULL);
}

You need:

else if (pid == 0) { //Child
    dup2(pd[0], 0); 
    close(pd[0]);
    close(pd[1]);
    execlp("wc", "wc", "-l", (char *)NULL);
    fprintf(stderr, "Failed to execute 'wc'\n");
    exit(1);
}

The crucial change is the dup2(); your code copies the write end of the pipe to the child's standard input , which is not a recipe for happiness. The revised code copies the read end of the pipe to the child's standard input. It's easy enough to remember which is which: stdin is file descriptor 0 and pipe descriptor 0 of the pair is the input descriptor (read end of the pipe), while stdout is file descriptor 1 and pipe descriptor 1 of the pair is the output descriptor (write end of the pipe).

You need the converse change in the 'parent' code.

The error arises when wc tries to read from a file descriptor that's only open for writing.

Note that if execlp() — or any other member of the exec*() family of functions — returns, it failed. It is important to deal with that error, usually by reporting a problem on standard error and exiting. It is seldom correct to have no statement after the exec*() operation.

Comments