Skip to content
Advertisement

C fork and pipe multiple process

I’m trying to implement this command cat /etc/passwd | grep 1000 | cut -d: -f1 in C using system calls fork and pipe.
When I use only two commands cmd1 | cmd2 so 1 fork it works fine but when I’m using more than 2 process the problem occurs
Here is my code, I think the problem is in the grand parent block

Update :
I closed some unclosed file descriptors

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


int main(){
    int fd[2], fd2[2];
    pid_t pid, pid2;
    char str[100];

    if(pipe(fd) != 0){
        fprintf(stderr, "Error pipe.n");
        return 1;
    }
    if(pipe(fd2) != 0){
        fprintf(stderr, "Error pipe.n");
        return 1;
    }

    do{
        pid = fork();
    }while(pid == -1 && errno == EAGAIN);

    if(pid == -1){
        perror("fork()");
        exit(1);
    }

    if(pid == 0){
        pid2 = fork();
        if(pid2 == 0){
            // fprintf(stderr, "1 - Grand Childn");
            close(fd[0]);
            dup2(fd[1], 1);
            close(fd[1]);
            execlp("cat", "cat", "/etc/passwd", NULL);
            perror("cat error");
        }else{
            wait(&pid2);
            // fprintf(stderr, "2 - Childn");
            close(fd[1]);
            dup2(fd[0], 0);
            close(fd[0]);

            up2(fd2[1], 1);
            close(fd2[1]);

            execlp("grep", "grep", "1000", NULL);
            perror("grep failed");
        }
        return 1;
    }else{
        wait(&pid);
        // fprintf(stderr, "3 - Parentn");
        close(fd[0]);
        dup2(fd2[0], 0);
        close(fd2[0]);
        execlp("cut", "cut", "-d:", "-f1", NULL);
        perror("cut failed");
        return 1;
    }
    return 0;
}

Advertisement

Answer

You need to close all unused file descriptors in both children and parents! In this case, when using dup2(), all file descriptors associated with pipes may be closed.

For clarity I used macros for file descriptors associated with stdin and stdout. Macros STDIN_FILENO and STDOUT_FILENO are declared in unistd.h.

Waiting for children (wait(&pid); and wait(&pid2);) is not needed. You do not need to wait for cat to end before running grep, as grep will process them as they come. Pipe should have a big buffer, like 65536 bytes, so after cat command ends data will be buffered in pipe, but it is not something to count on.

The following code, with only minor changes, works:

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

int main(){
    int fd[2], fd2[2];
    pid_t pid, pid2;
    char str[100];

    if(pipe(fd) != 0){
        fprintf(stderr, "Error pipe.n");
        return 1;
    }
    if(pipe(fd2) != 0){
        fprintf(stderr, "Error pipe.n");
        return 1;
    }

    do{
        pid = fork();
    }while(pid == -1 && errno == EAGAIN);

    if(pid == -1){
        perror("fork()");
        exit(1);
    }

    if(pid == 0){
        pid2 = fork();
        if(pid2 == 0){
            // fprintf(stderr, "1 - Grand Childn");
            dup2(fd[1], STDOUT_FILENO); // 1);
            close(fd[0]);
            close(fd[1]);
            close(fd2[1]);
            close(fd2[0]);

            execlp("cat", "cat", "/etc/passwd", NULL);
            perror("cat error");
        }else{
            // wait(&pid2);
            // fprintf(stderr, "2 - Childn");
            dup2(fd[0], STDIN_FILENO); //0);
            dup2(fd2[1], STDOUT_FILENO); // 1);
            close(fd[0]);
            close(fd[1]);
            close(fd2[1]);
            close(fd2[0]);

            execlp("grep", "grep", "1000", NULL);
            perror("grep failed");
        }
        return 1;
    }else{
        // wait(&pid);
        // fprintf(stderr, "3 - Parentn");
        dup2(fd2[0], STDIN_FILENO); //0);
        close(fd[0]);
        close(fd[1]);
        close(fd2[1]);
        close(fd2[0]);

        execlp("cut", "cut", "-d:", "-f1", NULL);
        perror("cut failed");
        return 1;
    }
    return 0;
}
Advertisement