Question

I want to set up 2 pipes in my program. I have 1 pipe working fine, but I don't know where to place the second pipe.

The pseudo code of my setup is shown below,

Here is it with curly braces sorry about that

//the first pipe:   
pipe(pipe1) 

//the second pipe:  
pipe(pipe2) 

pid = fork()

if(pid == 0) {

  dup2(pipe1[1], 1)
  close(pipe1[0])
  execvp(beforepipe)
  }  

if(pid > 0) { //everything below is in here

  pid2 = fork()

  if(pid2 == 0){

    //pipe1
    dup2(pipe1[0],0)
    dup2(out,1)
    close(pipe1[1])
    execvp(afterpipe)

    //pipe2 does not work might need to be placed in different area
    dup2(pipe1[1],1)
    close(pipe1[0])
    execvp(beforepipe1)
    }

  if(pid2 > 0){
    close(pipe[0])
    close(pipe[1])
    wait() //this is an infinite for loop

    pid3 = fork()

    if(pid3 == 0){
      dup2(pipe2[0],0)
      dup2(out,1)
      close(pipe2[1])
      execvp(afterpipe2)
      }

    if(pid3 > 0) {
      close(pipe2[0])
      close(pipe2[1])
      wait()
      }
    }

The position of the second pipe is in the wrong place or the code is altogether wrong.

Any suggestions?

Was it helpful?

Solution

Your main problem is that you are not closing anywhere near enough file descriptors. Given a file input1 in the current directory containing your string "eschew obfuscation\", this code works for me (but note how many file descriptors have to be closed!).

  • Rule of thumb: if a pipe is dup2()d or dup()d to standard input or output, close both file pipe file descriptors.

Example code (with debug tracing in place):

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* command pipeline: cat input1 | tr a-z A-Z | tr \\ q */

int main(void)
{
    int pipe1[2];
    int pipe2[2];
    pid_t pid1;
    char *cmd1[] = { "cat", "input1",        0 };
    char *cmd2[] = { "tr",  "a-z",    "A-Z", 0 };
    char *cmd3[] = { "tr",  "\\",     "q",   0 };

    if (pipe(pipe1) != 0 || pipe(pipe2) != 0)
    {
        perror("pipe failed");
        return 1;
    }

    pid1 = fork();

    if (pid1 < 0)
    {
        perror("fork 1 failed");
        return 1;
    }

    if (pid1 == 0)
    {
        /* Child 1 - cat */
        dup2(pipe1[1], 1);
        close(pipe1[0]);
        close(pipe1[1]);
        close(pipe2[0]);
        close(pipe2[1]);
        execvp(cmd1[0], cmd1);
        perror("failed to execute cmd1");
        return 1;
    }

    printf("pid 1 = %d\n", pid1);
    fflush(stdout);

    pid_t pid2 = fork();
    if (pid2 < 0)
    {
        perror("fork 2 failed");
        return 1;
    }

    if (pid2 == 0)
    {
        /* Child 2 - tr a-z A-Z */
        dup2(pipe1[0], 0);
        dup2(pipe2[1], 1);
        close(pipe1[0]);
        close(pipe1[1]);
        close(pipe2[0]);
        close(pipe2[1]);
        execvp(cmd2[0], cmd2);
        perror("failed to execute cmd2");
        return 1;
    }

    printf("pid 2 = %d\n", pid2);
    fflush(stdout);

    pid_t pid3 = fork();
    if (pid3 < 0)
    {
        perror("fork 3 failed");
        return 1;
    }

    if (pid3 == 0)
    {
        /* Child 3 - tr \\ q */
        dup2(pipe2[0], 0);
        close(pipe1[0]);
        close(pipe1[1]);
        close(pipe2[0]);
        close(pipe2[1]);
        execvp(cmd3[0], cmd3);
        perror("failed to execute cmd3");
        return 1;
    }

    printf("pid 3 = %d\n", pid3);
    fflush(stdout);

    /* Parent - wait for the kids to all die */
    close(pipe1[0]);
    close(pipe1[1]);
    close(pipe2[0]);
    close(pipe2[1]);

    pid_t corpse;
    int   status;
    while ((corpse = wait(&status)) > 0)
        printf("Child %d died status 0x%.4X\n", corpse, status);

    return 0;
}

OTHER TIPS

execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)

I think the execvp() didnot return. So the code below the execvp() is irrelevent.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top