Reputation: 3
I'm trying to replicate this bash command: ps aux | grep bash
to C language. I have written something but it doesn't seem to work. The result is literally that nothing happens, the prompt is printed again in bash. This is the code:
int main()
{
int pid;
int pip[2];
char *argexec1[] = {"/bin/grep", "bash", NULL};
char *argexec2[] = {"/bin/ps", "aux", NULL};
if (pipe(pip) == -1){
perror("pipe error \n");
exit(1);
}
if (pid = fork() == -1){
perror("fork error");
exit(1);
}
if (pid == 0)
{
dup2(pip[0], 0);
close(pip[1]);
close(pip[0]);
execvp("grep", argexec1);
perror("exec1 failed\n");
exit(1);
}
else
{
dup2(pip[1], 1);
close(pip[0]);
close(pip[1]);
execvp("ps", argexec2);
perror("exec2 failed\n");
exit(1);
}
Upvotes: 0
Views: 722
Reputation: 5201
In the child process, if execvp() fails, don't call exit() but _exit() otherwise the inherited I/O contexts may trigger duplicate I/O flushes and several other undesirable things.
. "==" has a higher precedence than "=". This makes your statement fail here:
if (pid = fork() == -1)
Add parenthesis:
if ((pid = fork()) == -1)
Here is your program with the fixes:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int pid;
int pip[2];
char *argexec1[] = {"/bin/grep", "bash", NULL};
char *argexec2[] = {"/bin/ps", "aux", NULL};
if (pipe(pip) == -1){
perror("pipe error \n");
exit(1);
}
if ((pid = fork()) == -1){
perror("fork error");
exit(1);
}
if (pid == 0) {
// Child process
dup2(pip[0], 0);
close(pip[1]);
close(pip[0]);
execvp("grep", argexec1);
perror("exec1 failed\n");
_exit(1);
} else {
// Father process
dup2(pip[1], 1);
close(pip[0]);
close(pip[1]);
execvp("ps", argexec2);
perror("exec2 failed\n");
exit(1);
}
return 0;
}
But actually, if you want to make it like the shell, you are supposed to wait for the end of the commands before exiting the program and return the exit code of the last process in the pipe. So, the father should launch two processes and wait for their end:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
int status1, status2;
int pid1, pid2;
int pip[2];
char *argexec1[] = {"/bin/grep", "bash", NULL};
char *argexec2[] = {"/bin/ps", "aux", NULL};
if (pipe(pip) == -1){
perror("pipe error \n");
exit(1);
}
if ((pid1 = fork()) == -1){
perror("fork error");
exit(1);
}
if (pid1 == 0) {
// Child process#1
dup2(pip[0], 0);
close(pip[1]);
close(pip[0]);
execvp("grep", argexec1);
perror("exec1 failed\n");
_exit(2);
} else {
// Father process
if ((pid2 = fork()) == -1){
perror("fork error");
exit(1);
}
if (pid2 == 0) {
// Child process#2
dup2(pip[1], 1);
close(pip[1]);
close(pip[0]);
execvp("ps", argexec2);
perror("exec2 failed\n");
_exit(2);
} else {
// Father process
close(pip[0]);
close(pip[1]);
// Wait for the end of the programs
if (-1 == waitpid(pid1, &status1, 0)) {
perror("wait1 error");
exit(1);
}
if (-1 == waitpid(pid2, &status2, 0)) {
perror("wait2 error");
exit(1);
}
// Return the exit code of the last program in the pipe
if (WIFEXITED(status1)) {
return WEXITSTATUS(status1);
} else {
// The process may have received a signal, return the whole status...
return status1;
}
}
}
return 0;
}
Upvotes: 1