'Issue with dup2
I am trying a simple program where the STDOUT from Child process is directed to the Parent process. The program works if I don't fork multiple times and call the child_process and parent_process in a loop. However, when I put a for loop around the fork and child_process and parent_process, dup2 function returns -1 and hence the program fails. What am I doing wrong?
This code has a for loop around the child_process and parent_process and has issues with dup2
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 256
void child_process(int pipe_pair[2]){
// closes the child's STDOUT descriptor and replaces it with
// the write pipe linked to the parent's read pipe
if (dup2(pipe_pair[1], STDOUT_FILENO) == -1){
// if dup2 fails, perror writes to stderr so this reports
// appropriately either way as the child and parent share stderr
perror("dup2");
// parent will know if the child failed since we return 1
// (ideally return errno so that calling processes know the error code)
exit(EXIT_FAILURE);
}
// duplicated by dup2 above, no longer needed
close(pipe_pair[1]);
// close read end as we will never read from stdout
close(pipe_pair[0]);
// printf writes to stdout by default
// we could also use fprintf(stdout, ...)
printf("Hello, parent!\n");
// make sure the write buffer is flushed before we exit
fflush(stdout);
// close to make sure read() returns 0 in the parent
close(STDOUT_FILENO);
// child exits
exit(EXIT_SUCCESS);
}
void parent_process(int pipe_pair[2], pid_t cpid){
// cstatus will store the return of the child process
// buf will hold the child's writes to stdout --
// {0} initializes the array elements to 0x00
int cstatus;
char buf[BUFSIZE] = {0};
close(pipe_pair[1]); // we won't write to stdout
// read until closed, or error (0 or -1, respectively)
for (int n = 0; (n = read(pipe_pair[0], buf, BUFSIZE)) > 0;){
printf("Received %d bytes from child process: ", n);
// (needed otherwise write() may output before
// printf since stdio output to stdout is line buffered)
fflush(stdout);
// writes just what we read so no need to reset buf
write(STDOUT_FILENO, buf, n);
printf("\n");
fflush(stdout);
}
// close read pipe
close(pipe_pair[0]);
// waits for child process with pid 'cpid' to
// return and stores the exit code in cstatus
waitpid(cpid, &cstatus, 0);
printf("Child exit status was: %d\n", cstatus);
// terminate parent
//exit(EXIT_SUCCESS);
}
int main(int argc, char **argv){
// cpid stores the process id of the child process
// stdout_pipe array = pipe descriptor pair --
// [0] is the read end, [1] is the write end
pid_t cpid;
int stdout_pipe[2];
// call that creates the two unidirectional pipe streams
// and stores the descriptors in the array
if (pipe(stdout_pipe) == -1){
perror("pipe");
exit(EXIT_FAILURE);
}
// fork happens here, cpid will have the child's
// process id or -1 if the call fails
for (int i=0; i<3; i++) {
cpid = fork();
if (cpid == -1){
perror("fork");
exit(EXIT_FAILURE);
}
// child (fork returns 0 in the child and the child ID for the parent)
if (cpid == 0)
child_process(stdout_pipe);
// else when cpid is not 0 or -1 we're in the parent
else
parent_process(stdout_pipe, cpid);
}
// we shouldn't get here, but return int from main for correctness
return 0;
}
Solution 1:[1]
The problem is this block is outside the loop:
if (pipe(stdout_pipe) == -1){
perror("pipe");
exit(EXIT_FAILURE);
}
The first call to parent_process closes the pipe descriptors, and they are not reopened for the second iteration of the loop, so there is nothing to dup.
The simplest solution would be to move the pipe call in to the loop.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Lev M. |
