I have to write a program that displays the same output as if I write ps aux | grep root | wc -l
ps aux | grep root | wc -l
ps aux | grep root | wc -l
in the terminal. After searching for answers in this web and not finding anything, and trying to understand this program from GitHub (which doesn't finish properly when I run it), this has been my humble attempt:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
// Program to execute ps aux | grep root | wc -l
int main(int argc, char const *argv[]) {
int parent_child_fd[2];
pid_t child,grandchild;
if (pipe(parent_child_fd) == -1) {
perror("Error creating parent_child_fd");
return EXIT_FAILURE;
}
if ((child = fork()) == -1) {
perror("Error forking child");
return EXIT_FAILURE;
}else if(child == 0){
int child_grandchild_fd[2];
if (pipe(child_grandchild_fd) == -1) {
perror("Error creating child_grandchild_fd");
exit(EXIT_FAILURE);
}
close(parent_child_fd[1]);
close(child_grandchild_fd[0]);
dup2(parent_child_fd[0],0);
close(parent_child_fd[0]);
dup2(child_grandchild_fd[1],1);
close(child_grandchild_fd[1]);
if ((grandchild = fork()) == -1) {
perror("Error forking child");
exit(EXIT_FAILURE);
}else if(grandchild == 0){
close(child_grandchild_fd[1]);
dup2(child_grandchild_fd[0],0);
execlp("/usr/bin/wc","/usr/bin/wc","-l",(char*)NULL);
perror("Grandchild failed executing wc");
exit(EXIT_FAILURE);
}
execlp("/bin/grep","/bin/grep","root",(char*)NULL);
perror("Child failed executing grep");
exit(EXIT_FAILURE);
}
close(parent_child_fd[0]);
dup2(parent_child_fd[1],1);
close(parent_child_fd[1]);
execlp("/bin/ps","/bin/ps","aux", (char*)NULL);
perror("Parent failed executing ps");
return -1;
}
However, I always get the same output:
Signal 17 (CHLD) caught by ps (3.3.12). /bin/ps:ps/display.c:66: please report this bug
Could someone give me an explanation why this program doesn't work properly? Because I'm sure it's not because of the supposed bug I have to report.
Forking program is not excessively complex but requires very strict coding practices because when it goes wrong it is harder to debug. Here I had to first let only parent run (just ps
), then parent and child ( ps | wc
). At that moment I noticed that operations on child_grandchild_fd
were interleaved amont operations on parent_child_fd
, but it gave expected results.
But at the moment of uncommenting the grandchild part, I noticed that your code was closing child_grandchild_fd
before the fork , so when you try to use it in grandchild, you only dup already closed handles. So the grandchild reads from a closed handle and exits before using the content of the pipes.
The fix is trivial: just fork at first, then manage the pipe in the branches:
...
if (pipe(child_grandchild_fd) == -1) {
perror("Error creating child_grandchild_fd");
exit(EXIT_FAILURE);
}
close(parent_child_fd[1]);
dup2(parent_child_fd[0],0);
close(parent_child_fd[0]);
if ((grandchild = fork()) == -1) {
perror("Error forking child");
exit(EXIT_FAILURE);
}else if(grandchild == 0){
close(child_grandchild_fd[1]);
dup2(child_grandchild_fd[0],0);
execlp("/usr/bin/wc","/usr/bin/wc","-l",(char*)NULL);
perror("Grandchild failed executing wc");
exit(EXIT_FAILURE);
}
dup2(child_grandchild_fd[1],1); // moved after the fork
close(child_grandchild_fd[0]);
close(child_grandchild_fd[1]);
execlp("/usr/bin/grep","/usr/bin/grep","root",(char*)NULL);
perror("Child failed executing grep");
exit(EXIT_FAILURE);
...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.