Question

I am trying to change the stdin to a pipe outlet and stdout to another file and using grep. I get the following error:

grep: (standard input): Bad file descriptor

My code is:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>

int main()
{
        pid_t childpid;
        int fds[2];
        int stat;
        int fd = open("temp", O_WRONLY | O_APPEND);
        int old_in = dup(STDIN_FILENO);
        int old_out = dup(STDOUT_FILENO);
        if ((childpid = fork()) != 0)
        {
                wait(&stat);
                close(fds[1]);
                dup2(fds[0], STDIN_FILENO);
                dup2(fd, STDOUT_FILENO);
                system("grep hello");
                dup2(old_in, STDIN_FILENO);
                dup2(old_out, STDOUT_FILENO);
                close(fds[0]);
                close(fd);
        }

        else if (childpid == 0)
        {
                close(fds[0]);
                write(fds[1], "hello how are you", 100);
                close(fds[1]);
                return 0;

        }

        else
        {
                fprintf(stderr, "ERROR:\n");
                exit(1);
        }
        return 0;
}

So basically I am writing a string to the write outlet of a pipe and using the other outlet of the pipe (the read) as stdin for grep, and outputting stdout to another file. I've removed the return from the childpid and also tried using another file as the stdin instead, but still get the same error.

Was it helpful?

Solution

There are multiple problems! Amongst others:

  • You don't call pipe(fds); so you don't have a pipe.

  • Childish code (write(fds[1], "hello how are you", 100);)

    • You should include a newline at the end of the line.
    • You should only write as many characters as there are in the string, and there aren't 100 characters in the string shown.
  • Parental code (the block after if ((childpid = fork()) != 0))

    • You don't need to reinstate the file descriptors after the system because you're about to exit.
    • You could use one of the exec*() functions instead of system().
    • In general, you should not wait for the child to exit; there can be too much data pushed into the pipe for the child to be able to finish before the parent reads anything. In this case, it should be OK, but beware.
    • You should not really execute grep with the extra file descriptors open (old_in and old_out), but they go away when you don't reinstate things after the system() call.
    • You should close fds[0] after you've duplicated it (and before you run grep).

Working code

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void)
{
    pid_t childpid;
    int fds[2];
    int fd = open("temp", O_WRONLY | O_APPEND);
    if (pipe(fds) != 0)
        return 1;
    if ((childpid = fork()) != 0)
    {
        close(fds[1]);
        dup2(fds[0], STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        close(fds[0]);
        close(fd);
        execlp("grep", "grep", "hello", (char *)0);
        fprintf(stderr, "Failed to execute grep\n");
        return 1;
    }
    else if (childpid == 0)
    {
        const char data[] = "hello how are you\nvery well thanks\n";
        close(fds[0]);
        write(fds[1], data, sizeof(data)-1);
        close(fds[1]);
        return 0;
    }
    else
    {
        fprintf(stderr, "ERROR:\n");
        return 1;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top