Reputation: 13
I am using pipe, fork & exec to implement a user shell. The issue is that it does not work in certain cases. For eg it would work if I have ls | head but will not work for ls | cat. It will show the output of cat but will simply hang after that without returning to the prompt.
Referring to the code I have the input stored in c->args[0],for which I fork a child & execute it.
I understand that the second exec is still waiting for EOF, but closing file descriptors before that does not help.
Going through similar questions, I also tried closing file descriptors in the parent process before wait but after doing that even ls | head does not work. I have posted the relevant function below.
void executeProcess(Cmd c,int noofcmds)
{
// printf("Will be entering fork procedure \n");
int cmdNo;
pipe(fd);
for (cmdNo = 0;cmdNo < noofcmds; cmdNo ++)
{
int processid = fork();
pid_t childpid;
// printf("Process id %d\n",processid);
if (processid == 0)
{
// if (noofcmds != 1)
// {
if (cmdNo == 0)
{
printf("Inside first child \n");
close(fd[0]);
dup2(fd[1], 1);
// close(fd[0]);
} else if (cmdNo == noofcmds-1)
{
close(fd[1]);
dup2(fd[0], 0);
// close(fd[0]);
}
// close(fd[1]);
// close(fd[0]);
if (execvp(c->args[0],c->args) < 1)
{ printf("Error\n");
}
} else
{
// printf("Waiting in parent\n");
// close(fd[0]);
// close(fd[1]);
int status;
int returnedpid;
wait(&status);
printf("Returned after waiting\n");
// close(fd[0]);
// close(fd[1]);
}
c = c->next;
// close(fd[0]);
// close(fd[1]);
} // end of for
}
Upvotes: 1
Views: 1681
Reputation: 1101
Look at the sequence of events, with ls | cat
this is what happens right now:
1) pipe is created in parent.
2) ls
child is spawned
3) parent waits for ls
to finish
4) cat
child is spawned
5) parent waits for cat
to finish
As you noticed, in 5) parent still has the pipe open so cat
never finishes.
When you close it in the parent part of the code it gets closed ... before 3). So by the time cat
starts the pipe doesn't exist anymore -> no output from cat
.
What you need is to close it after 4) with something like:
...
else // in parent
{
// printf("Waiting in parent\n");
if (cmdNo == 1) // second child is spawned, can close the pipe now.
{
close(fd[0]);
close(fd[1]);
}
int status;
wait(&status);
printf("Returned after waiting\n");
}
Code will need more work to handle more than 2 commands in a pipe, but you get the idea...
Tip: find an editor which indents your code automatically, it'll make your life a lot easier !
Upvotes: 1