Done with Unix Single Piping but confused with Multipiping
Posted: Wed Oct 24, 2007 1:18 pm
I'm trying my hand at implementing a small shell. I'm actually stuck at piping... I am able to handle a single pipe but how do I solve the problem of multiple pipes? I know it can be solved using recursion or looping(I'd love to hear more about this) but some pseudo algorithm will be excellent... I'm currently doing something like a parent creates two children and the first one executes one command and pipes it onto the second child which displays the output...
And when I used valgrind, to my surprise I found 15 memory leaks from the piping function that I wrote and I don't understand what could've gone wrong... My pseudo code looks something like this:
Am I doing something wrong? And could someone give me some tips on how to go about this issue? I've written my parser in such a way that it gives me something like:
argv[0] = ls
argv[1] = -la
argv[2] = |
argv[3] = wc
argv[4] = |
argv[5] = wc
for an input like "ls -la | wc | wc"
I am able to get it to work for "ls -la | wc" but the next thing is what is puzzling me... Is it possible using the architecture that I've written?
And when I used valgrind, to my surprise I found 15 memory leaks from the piping function that I wrote and I don't understand what could've gone wrong... My pseudo code looks something like this:
Code: Select all
int fd[2]; /* provide file descriptor pointer array for pipe */
pid_t pid1, pid2; /* process ids for each child */
/* create pipe and check for an error */
/* apply fork and check for error */
/* processing for child */
close (fd[1]); /* close output end, leaving input open */
/* set standard input to pipe */
if (fd[0] != STDIN_FILENO)
{
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
{
perror("dup2 error for standard input");
exit(1);
}
close(fd[0]);
}
execlp the second function
//First child finished
else
{
/* processing for parent */
/* spawn second process */
/* apply fork again for second child*/
/* processing for child */
close (fd[0]);
/* set standard output to pipe */
if (fd[1] != STDOUT_FILENO)
{
if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
{
perror("dup2 error for standard output");
exit(1);
}
close(fd[1]); /* not needed after dup2 */
}
execlp the first function
/* print to the pipe, now standard output */
}
else
{
/* processing continues for parent */
close(fd[0]);
close(fd[1]);
waitpid (pid1, NULL, 0); /* wait for first child to finish */
waitpid (pid2, NULL, 0); /* wait for second child to finish */
}
}
argv[0] = ls
argv[1] = -la
argv[2] = |
argv[3] = wc
argv[4] = |
argv[5] = wc
for an input like "ls -la | wc | wc"
I am able to get it to work for "ls -la | wc" but the next thing is what is puzzling me... Is it possible using the architecture that I've written?