Program stuck on Pipe (exec ls grep sort)

3.8k views Asked by At

I'm trying to make a program that executes the following commands connecting the output of one to the input of the next using pipes and taking two arguments DIR (directory) and ARG (filetype, example: jpg).

ls DIR -laR | grep ARG | sort

Here's the code:

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("Invalid arguments. <dir> <arg>\n");
        exit(1);
    }

    int pipe_fd1[2];
    int pipe_fd2[2];
    pid_t ls_pid, grep_pid;
    int status;

    pipe(pipe_fd1);
    pipe(pipe_fd2);

    ls_pid = fork();
    if (ls_pid == 0) { //first child ls DIR -laR
        dup2(pipe_fd1[1], STDOUT_FILENO);
        close(pipe_fd1[0]);

        execlp("ls", "ls", argv[1], "-laR", NULL);

    } else if (ls_pid > 0) {
        grep_pid = fork();
        if (grep_pid == 0) { //second child grep ARG
            dup2(pipe_fd1[0], STDIN_FILENO);
            dup2(pipe_fd2[1], STDOUT_FILENO);       
            close(pipe_fd1[1]);
            close(pipe_fd2[0]);

            waitpid(ls_pid, &status, 0);    
            execlp("grep", "grep", argv[2], NULL);

        } else if (grep_pid > 0) { //parent sort
            dup2(pipe_fd2[0], STDIN_FILENO);
            close(pipe_fd2[1]);

            waitpid(grep_pid, &status, 0);
            execlp("sort", "sort", NULL);
        }

    }

    return 0;
}

It seems to be stuck? Not sure why?

1

There are 1 answers

2
Filipe Gonçalves On BEST ANSWER

You never close pipe_fd1 on the parent, so grep and sort doen't know when to stop reading input: because the pipe read and write ends are never closed on the parent, the reader blocks waiting for more input that will never arrive. You need to close it.

Also, you don't need waitpid(): the way pipes work ensures that input flows linearly and in order throughout the pipe.

Here's the working version with these issues addressed:

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

int main(int argc, char *argv[]) {

    if (argc != 3) {
        printf("Invalid arguments. <dir> <arg>\n");
        exit(1);
    }

    int pipe_fd1[2];
    int pipe_fd2[2];
    pid_t ls_pid, grep_pid;

    pipe(pipe_fd1);

    ls_pid = fork();
    if (ls_pid == 0) { //first child ls DIR -laR
        dup2(pipe_fd1[1], STDOUT_FILENO);
        close(pipe_fd1[0]);
        execlp("ls", "ls", argv[1], "-laR", NULL);

    } else if (ls_pid > 0) {
        dup2(pipe_fd1[0], STDIN_FILENO);
        close(pipe_fd1[1]);

        pipe(pipe_fd2);
        grep_pid = fork();

        if (grep_pid == 0) { //second child grep ARG
            dup2(pipe_fd2[1], STDOUT_FILENO);
            close(pipe_fd2[0]);  
            execlp("grep", "grep", argv[2], NULL);

        } else if (grep_pid > 0) { //parent sort
            dup2(pipe_fd2[0], STDIN_FILENO);
            close(pipe_fd2[1]);
            execlp("sort", "sort", NULL);
        }

    }

    return 0;
}