Hasnain Ali
Hasnain Ali

Reputation: 97

Using dup2() system call for piping more than 3 programs?

I am learning to use Linux system calls using C. I don't understand the use of dup2 at all. So far I did dup2 for 2 commands and it works okay, but I can't think of a way for doing 3+ commands.

For example if I want to execute three commands:

./program1  
./program2  
./program3

Suppose these three program depends on user input. How can I use fork() and dup2() to pipe the outputs of these program?

For only 2 commands I have done this and it works like a charm:

pid2=fork();
if(pid2==0)
{   
    close(pipe1[0]);
    dup2(pipe1[1], STDOUT_FILENO);
    close(pipe1[1]);
    execvp("./addone",argp);
}
else
{
    wait(NULL);
    close(pipe1[1]);
    dup2(pipe1[0], STDIN_FILENO);
    close(pipe1[0]);
    execvp("./addone",argp);
}

Upvotes: 0

Views: 1548

Answers (1)

Janez Kuhar
Janez Kuhar

Reputation: 4286

First of, your else is redundant as "the exec() family of functions replaces the current process image with a new process image [exec(3) — Linux manual page]. So, the child will never continue execution past the if block and the code in the else block is the code that the parent should execute anyway.

For 3 processes to emulate the following bash behaviour ./addone | ./addone | ./addone, you would want to write something like:

#include <unistd.h>         // dup2(), pipe(), fork(), execvp()
#include <sys/wait.h>       // waitpid()
int main() {
    int pipe1[2], pipe2[2];
    int pid0, pid1, pid2;
    char *argp = {"./addone", "first_argument", "second_argument", NULL};

    pipe(pipe1);
    pid0 = fork(); 
    if (pid0 == 0) {
        // close the read end of pipe1:
        close(pipe1[0]);
        // redirect stdout to the write end of pipe1:
        dup2(pipe1[1], 1);

        execvp("./addone", argp);
    }

    pipe(pipe2);
    pid1 = fork();
    if (pid1 == 0) {
        // close the write end of pipe1:
        close(pipe1[1]);
        // close the read end of pipe2:
        close(pipe2[0]);            
        // redirect stdin to the read end of pipe1:
        dup2(pipe1[0], 0);
        // redirect stdout to the write end of pipe2:
        dup2(pipe2[1], 1);
    
        execvp("./addone", argp);
    }
    
    pid2 = fork();
    if (pid2 == 0) { 
        // close unused pipe1:
        close(pipe1[0]);
        close(pipe1[1]);
        // close the write end of pipe2:
        close(pipe2[1]);
        // redirect stdin to the read end of pipe2:
        dup2(pipe2[0], 0);

        execvp("./addone", argp);
    }

    waitpid(pid0, NULL, 0);
    waitpid(pid1, NULL, 0);
    waitpid(pid2, NULL, 0);
}

Upvotes: 1

Related Questions