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.