Home > Net >  Having a single process write to two pipes in C
Having a single process write to two pipes in C

Time:01-24

I'm trying to implement a program that launches a process (call this app1) and pipes the stdout to two other apps (app2, app3 respectively). I have a functioning implementation where I fork() app1 twice and pipe the stdout for each, but I feel there's a cleaner solution.

What happens with my implementation is that app3 launches but doesn't show the stdout in the shell. Not looking for an exact answer to my problem, but a nudge in the right direction. I believe the issue is how I'm handling the file descriptors, but I'm still quite new to these functions so I'm not sure where I went wrong.

Here is what I have:

int pipepipe(char **app1, char **app1, char**app3){
   int fd[4]; 
   pipe(fd);
   pipe(fd 2);
   pid_t pid1 = fork();
   if(pid1 < 0){
      return 2;
   }
   if (pid1 == 0){ 
      dup2(fd[1], 1);
      dup2(fd[3], 1);
      for(int i = 0; i <4; i  ){
         close(fd[i]);
      }
      execvp(app1[0], app1); 
   }

   int pid2 = fork();
   if(pid2 <0){
      return 2; 
   }
   if(pid2 == 0){ 
      dup2(fd[0], 0); 
      for(int i = 0; i <4; i  ){
         close(fd[i]);
      }
      execvp(app2[0], app2);
   } 

   int pid3 = fork();
   if(pid3 < 0){
      return 2;
   }
   if(pid3 == 0){
      dup2(fd[2], 0);
      for(int i = 0; i < 4; i  ){
         close(fd[i]);
      }
      execvp(app3[0], app3);
   }
   
   waitpid(pid1, NULL, 0);
   waitpid(pid2, NULL, 0);
   waitpid(pid3, NULL, 0);

   for(int i = 0; i <4; i  ){
      close(fd[i]);
      }
   return 0;
} 

CodePudding user response:

The consecutive calls:

dup2(fd[1], 1);
dup2(fd[3], 1);

in the app1 child code are wrong. Individually, they're fine, but the second call closes the fd[1] that was duplicated to STDOUT_FILENO (aka 1). You have to use two separate file descriptors to write to the two pipes. So, rather than app1 writing to its standard output, you'll probably want to think about passing (string) arguments which tell it which file descriptors to write on. All command arguments are strings, so maybe:

char out1[6];
char out2[6];
sprintf(out1, "-o%d", fd[1]);
sprintf(out2, "-o%d", fd[3]);

and then add out1 and out2 to the arguments in the app1 array. You'd not close either fd[1] or fd[3]; you would still close fd[0] and fd[2].

If you need to differentiate between the two apps (if app1 writes different data to app2 and app3), then you use different option letters (maybe -o and -O?) to identify which is which.

Obviously, you need appropriate argument parsing code in app1 so it knows what to do.

The alternative is designate that file descriptor 3 will be the output to app2 and file descriptor 4 will be the output to app3 (leaving the standard I/O descriptors unchanged):

dup2(fd[1], 3);
dup2(fd[2], 4);

You just have to be a bit careful that you don't close either 3 or 4 in the loop over the 4 file descriptors. The chances are that you have the following numbers:

fd[0] = 3
fd[1] = 4
fd[2] = 5
fd[3] = 6

in which case, the two dup calls would be fine, but the close loop would need to avoid closing fd[0] and fd[1] (because those values are 3 and 4).

On the whole, I prefer the explicit options, but YMMV.

  • Related