I'm not going to lie. This is a homework question. However, as far as I'm concerned, the points are gone baby gone. Right now, I'm just looking for an answer, because I -think- I might be insane.
The goal of this program is to execute the command ps -A | grep (inputstring) | wc -l
in a way similar to how the shell does it. So, I spawn the processes, and have them wait on each other. The newest process, the great-grandchild, execlp("ps","ps","-A",NULL)
which replaces itself with the ps -A
process. Before it execlp
, I make sure its standard output is going to the pipe output. The next process in line is wait()
ing, and already has itself set up so that the input pipe goes to standard in, and standard out goes to the output pipe, and it will execute grep, and so on.
I'm almost positive I have it set up correctly. And yet... the program does. Not. Work.
#include <stdlib.h>
#include <iostream>
#include <string>
#define MAXLINE 1500
#define READ 0
#define WRITE 1
using namespace std;
int main( int argc, char** argv ) {
//* start of input block
if ( argc != 2 ) {
cout << "Usage: ./a.out arg1" << endl;
return 0;
}
string in = argv[1];
// end of input block */
int pipeA[2], pipeB[2], pid, stat;
// get our first set of pipes
if ( pipe(pipeA) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}
if ( pipe(pipeB) < 0 ) {
cerr << "Pipe error.\n";
exit(-1);
}
// make the first fork
if ( (pid = fork() ) < 0 ) { cerr << "Fork error.\n"; exit(-1); }
if ( pid > 0 ) { // parent case
wait(&stat);
} else { // child case
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) { // child
wait(&stat);
dup2(pipeA[READ],READ);
execlp("wc","wc","-l",NULL);
} else { // grand-child
if ( (pid = fork()) < 0 ) { cerr << "Fork Error\n"; exit(-1); }
if ( pid > 0 ) { // still grand-child
wait(&stat);
dup2(pipeB[READ],READ);
dup2(pipeA[WRITE],WRITE);
close(pipeB[READ]);
execlp("grep","grep",in.c_str(),NULL);
} else { // great grand-child
dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1]
close(READ);
close(pipeB[READ]);
execlp("ps", "ps", "-A", NULL);
}
}
}
return 0;
}
EDIT: Changed to the two-pipe variant of my code.
I'm virtually certain this is what you're trying to do. Apologies in advance for the sloppy coding. its somewhat late here and I really should be sleeping right now:
On my system,
ps -A
reports 141 lines, of those 41 have the wordSystem
somewhere within, verified by simply runningps -A | grep System | wc -l
. The above code generates precisely the same output.Hope it helps you out.
I'm not sure but maybe calling dup2 before waiting on the child would fix the pipe problem.
The reason I'm not sure is that it normally stdin and stdout are bufferized so I suppose that even if you hook your pipe up with them after the child has finish running you should get the same results but maybe (if someone knows the answer to this please correct me) the buffers for stdin and stdout get wiped with the end of the child process.
Also, could you update the code in your question to contain the modified code with two sets of pipes ?