I am trying to implement piping in Unix, and have been asked to do it recursively. I have a sh program that parses input by the pipe character and then forks a child process to begin the piping. I am going to use the command cat file | grep the | more
as an example.
My sh.c program first parses the input string into pipeCmds which is just an array of char * that point at the different parts of the input string. It forks the first child and then begins the recursivePipe() call which should set up all the pipes. After the pipes are set up I exec("more") in this case.
pid = fork();
if(pid == 0){
recursivePipe(pipeCmds[numCmds-2], numCmds-1);
exec(pipeCmds[numCmds-1]); // exec("more")
}else{
pid = wait(getpid());
}
Here is the recursivePipe function that should set up each pipe based on how many commands were in the string (ie. numCmds)
int recursivePipe(char * cmd, int index){
/* cmd = more */
int pid, fd, copy;
int ttyfd;
char tty[64];
if(index < 1){
printf("index is 0... RETURN\n");
return;
}
pipe(pd);
// First fork a new child to stage the WRITING proc
printf("forking to %s from %s\n", cmd, pipeCmds[index]);
pid = fork();
if(pid == 0){
// Child
close(pd[0]); // Close the child's read
//if(index != (numCmds-2)){ // If we are not on the last command, make stdout be the pipe
dup2(pd[1], 1); // Place the WRITE end of the pipe into stdout so anything coming from the pipe
close(pd[1]);
//}
copy = dup(1);
close(1);
gettty(tty);
ttyfd = open(tty, O_WRONLY);
if(ttyfd == 1){
printf("exec(%s) from %s\n", cmd, pipeCmds[index]);
close(1);
dup(copy);
close(copy);
}
/*copy = dup(0);
close(0);
gettty(tty);
ttyfd = open(tty, O_RDONLY);
if(ttyfd == 0){
getc();
close(0);
dup(copy);
close(copy);
}*/
exec(cmd);
}else{
// Parent
printf("in parent: %s[%d]\n", pipeCmds[index], index);
close(pd[1]); // Close the parent's write since more doesn't have to write
//if(index != 0){ // If we are not on the first command, make stdin be the pipe
dup2(pd[0], 0); // Place the READ end of pipe into stdin so that more's stdin comes from the pipe
close(pd[0]);
//}
printf("lets recurse!: %s[%d]\n", pipeCmds[index], index);
// if(index > 0){
recursivePipe(pipeCmds[index-2], index-1); // This will set up all other procs too with correct pipes
//pid = wait(getpid());
// }
printf("done recurse!: %s[%d]\n", pipeCmds[index], index);
}
}
Basically, I attempt to pipe(), then in the child process I close the READ end of the pipe and set stdout to now be the pipe. So in this case, on the first call of recursivePipe(), the parent section is the "more" proc and the child section is the "grep the" part. So "more" closes its stdin and replaces it with the pipe so it reads all output from "grep the"
Based on my printf() inside the function, here is the output of that command:
forking to grep the from more
in parent: more[2]
lets recurse!: more[2]
forking to cat file from grep the
exec( grep the ) from more
exec(cat file) from grep the
in parent: grep the [1]
lets recurse!: grep the[1]
index is 0... RETURN
done recurse!: grep the [1]
done recurse!: more[2]
And then it appears to cat file correctly and send it to more, but the grep program is never used between the two. It is as if cat and more are communicating directly rather than through grep.
Can anyone with knowledge of the unix system help me figure out why my recursion isn't setting up the pipes correctly? Thanks