I'm currently having problems with the following exercise:
I want to "mimic" the pipe command line ls | wc in linux bash with the following program.
What I do is:
- create a pipe
- create a reader child and writer child
- the writer child closes the pipe's reading side and redirects his stdout to the writing side of the pipe
- the reader child closes the pipe's writing side and makes the reading side of the pipe his stdin
- both children do an exec, the writer executes the
lsprogram, passes the output through the pipe to the reader that executes thewcprogram on that output.
When I do ls | wc in linux terminal I get the following result:
8 8 101
But if I execute my program I get the following result:
0 0 0
Here is my program:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <libgen.h>
#include <signal.h>
#include <errno.h>
int main(void){
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe)<0)
perror ("pipe error"), exit(1);
if ((pid1=fork())<0)
perror ("fork error"), exit(1);
else if (pid1==0) {
//reader child
close (mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO)!=STDIN_FILENO)
perror ("dup2 error"), exit(1);
close (mypipe[0]);
if (execlp("wc", "wc", NULL)<0)
perror("execlp1 error"), exit(1);
else { //pid >0, parent
if ((pid2=fork())<0)
perror ("fork error"), exit(2);
else if (pid2==0) {
//writer child
close(mypipe[0]);
if (dup2(mypipe[1], STDOUT_FILENO) != STDOUT_FILENO)
perror("dup2 error"), exit(1);
close (mypipe[1]);
if (execlp("ls", "ls", NULL)<0)
perror ("execlp error"), exit(1);
}
else { //parent
close(mypipe[0]);
close(mypipe[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
exit(0);
}
}
}
return 0;
}
What am I doing wrong? Thanks in advance for the answers!
Your code is confused. You have many irrelevant headers, and repeat
#include <errno.h>. In themain()function, you have:The
else if (pid1 == 0)clause is executed by the child. It closes the write end of the pipe, duplicates the read end to standard input and closes the read end of the pipe. It then doesexeclp()onwc. Only if the code fails to executewcwill theelseclause be executed, and then there is only the read end of the pipe left open. Meanwhile, the original process simply exits. That closes the pipe, so thewccommand gets no input, and reports0 0 0as a result.You need to rewrite the code. The parent process should wait until both its children execute. Especially while debugging, you should not ignore the exit status of children, and you should report it.
Here's some code that works. Note that it avoids bushy decision trees — it is a linear sequence of
if/else if/ … /elsecode. This is easier to understand, in general, than a bushy, multi-level set of conditions.A sample run of the program
pipe41on my machine produced: