Big Dude Big Dude - 22 days ago 6
Linux Question

Pipe issue: first child writes too much in to pipe

I'm trying to write a program in

C
that creates 2 child processes with each one of them executing an
execvp
.

My problem is that the first child writes too much input into the pipe from which the other child reads.

int main(int argc, char* argv[]){

//unnamed pipe
int pipeFd[2], statusFirst,statusSecond;
pid_t childPidOne,childPidTwo;

if(pipe(pipeFd) < 0){
perror("Pipe error:\n");
exit(EXIT_FAILURE);
}

switch(childPidOne = fork()){
case -1:
perror("First Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("First child\n");
close(pipeFd[1]);
if( (execvp(argv[1], &argv[1])) < 0){
perror("First execvp error:\n");
}
printf("End First cild\n");
exit(0);
default:
//Do nothing
break;
}

switch(childPidTwo = fork()){
case -1:
perror("Second Fork error:\n");
exit(EXIT_FAILURE);
case 0:
printf("Second cild\n");
close(pipeFd[0]);
if( (execvp(argv[3], &argv[3])) < 0){
perror("Second execvp error:\n");
}
printf("End Second cild\n");
exit(0);
default:
//Do nothing
break;
}


close(pipeFd[0]);
close(pipeFd[1]);


if( (waitpid(childPidOne,&statusFirst,WUNTRACED | WCONTINUED)) < 0 ){
perror("First waitpid error:\n");
}else{
if (WIFEXITED(statusFirst)) {
printf("First exited, status=%d\n", WEXITSTATUS(statusFirst));
} else if (WIFSIGNALED(statusFirst)) {
printf("First killed by signal %d\n", WTERMSIG(statusFirst));
} else if (WIFSTOPPED(statusFirst)) {
printf("First stopped by signal %d\n", WSTOPSIG(statusFirst));
} else if (WIFCONTINUED(statusFirst)) {
printf("First continued\n");
}
}


if( (waitpid(childPidTwo,&statusSecond,WUNTRACED | WCONTINUED)) < 0 ){
perror("Second waitpid error:\n");
}
if (WIFEXITED(statusSecond)) {
printf("Second exited, status=%d\n", WEXITSTATUS(statusSecond));
} else if (WIFSIGNALED(statusSecond)) {
printf("Second killed by signal %d\n", WTERMSIG(statusSecond));
} else if (WIFSTOPPED(statusSecond)) {
printf("Second stopped by signal %d\n", WSTOPSIG(statusSecond));
} else if (WIFCONTINUED(statusSecond)) {
printf("Second continued\n");
}

exit(0);
return 0;
}


Maybe I have a wrong understanding of how pipe + fork + execvp work so let me tell you what I'm doing in my code:


  1. I create an unnamed pipe - both childs use the same pipe

  2. I'll create two childs by forking them

  3. Since I execute my program like this:
    ./pipeline [FIRST SYSTEM CALL] | [SECOND SYSTEM CALL]
    or just to give you an example:
    ./pipeline echo Hello | wc -m
    I close the reading site of the pipe

  4. And then call
    execvp(argv[1], &argv[1])



And this is where the error happens (I guess):
I am never closing the writing side until the second child does because
execvp
will never return if it succeeds.

And I know that
execvp
will not close open file descriptors ( it can be closed by using a flag in
fcntl
as mentioned in What does the FD_CLOEXEC flag do? ).

Example



Let me give you an example.

echo Hello | wc -m


outputs the result


6


Because the system call
wc
(word count) counts the characters (
-m
) in a given
String


That is correct because hello = 5 + 1 (which is
\n
or
\0
I guess) and that makes 6.

Now, running my program gives the result


56


Or to get more information

echo hello | wc


outputs


1 (line) 1 (word) 6 (characters)


And
./pipeline echo hello | wc


outputs


3 (lines) 9 (word) 56 (characters)


I've searched for days but I can't figure it out.

Any ideas?

Thanks a lot!

Answer

Solved it myself.

Forgot to use dup2.

Just type the dup2 command after the close command and you will be fine.