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?

2

2 Answers

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.

3

As I can see, you trying to replicate the terminal command of "wc -l | grep something something".

The problem is that you are not providing input to wc. wc -l command requires an input for which it should count its lines. Try something like:

execlp("wc", "wc", "-l", "somefile.txt", (char *)NULL);
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Marcus Vance

Marcus Vance

Cybersecurity & Digital Privacy Researcher

Marcus Vance is a cybersecurity auditor and technology writer dedicated to educating the public about online safety, data privacy regulations, enterprise security, and emerging cyber threats.

Share this article
Twitter Facebook Pinterest