I'm trying to learn about pipes and redirections. For this purpose I'm doing some little programs to get used to the related system calls. On this one, I'm trying to launch cat on a file, pipe4.c, and pipe its output to grep that I launch after. It doesn't work and I don't understand the results, I though that the logic was good but I'm clearly missing something with fork. What am I doing wrong?
Here's the code:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFF_SIZE 4092
//redirecting the output of a program ('cat' here)
//to the stdin of another program ('grep' here)
void err_handler(char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(void)
{
//creating a pipe to communicate between the child processes
int p[2];
if (pipe(p) < 0)
err_handler("pipe error: ");
/*
** forking for cat
*/
pid_t cat_pid;
if ((cat_pid = fork()) < 0)
err_handler("fork error: ");
if (cat_pid)
close(p[1]);
if (!cat_pid) {
printf("===CAT===\n");
dup2(p[1], STDOUT_FILENO);
close(p[0]);
close(p[1]);
execl("/bin/cat", "cat", "pipe4.c", NULL);
exit(EXIT_SUCCESS);
}
/*
** forking for grep
*/
pid_t grep_pid;
if ((grep_pid = fork()) < 0)
err_handler("fork_error: ");
if (grep_pid)
wait(&grep_pid);
if (!grep_pid) {
printf("===GREP===\n");
dup2(p[0], STDIN_FILENO);
close(p[0]);
close(p[1]);
execl("/bin/grep", "grep", "\"err_handler\"", NULL);
exit(EXIT_SUCCESS);
}
return 0;
}
I only get this on my terminal:
> pom@parrot ~/dev/19/syscall> sudo ./a.out
> ===GREP===
> ===CAT===
> ===GREP===
The order in which those lines are printed changes each time I execute it. What I expect is obviously all the lines containing "err_handler" in my pipe4.c file, like if I did it directly in the shell:
> pom@parrot ~/dev/19/syscall> cat pipe4.c | grep "err_handler"
> void err_handler(char *msg) err_handler("pipe error: ");
> err_handler("fork error: "); err_handler("creat error: ");
> err_handler("read error: ");
> err_handler("write error:");
There are (I think!) 3 major issues.
1) you are not using wait correctly. I would advise using waitpid instead.
2) at least on my system, /bin/grep does not exist. It is /usr/bin/grep. But since you are returning EXIT_SUCCESS when exec
fails, you aren't seeing an error. You should replace execl (...); exit(EXIT_SUCCESS)
, with execl(...); perror("execl"); exit(EXIT_FAILURE);
3) You are searching for literal quotes. It is as if you ran:
grep '"err_handler"'
That is, the argument to execl when you spawn grep should be "err_handler"
, not "\"err_handler\""