So you have a loop that creates several child processes. Each of these child processes will be using two pipes: read from previous and write to the next. To set up a pipe for the reading end you need to close the write end of the pipe, and dup2
the read end into the stdin. Similar for the pipe where the process will be writing.
void set_read(int* lpipe)
{
dup2(lpipe[0], STDIN_FILENO);
close(lpipe[0]); // we have a copy already, so close it
close(lpipe[1]); // not using this end
}
void set_write(int* rpipe)
{
dup2(rpipe[1], STDOUT_FILENO);
close(rpipe[0]); // not using this end
close(rpipe[1]); // we have a copy already, so close it
}
When you fork each children you need to attach the pipes to it.
void fork_and_chain(int* lpipe, int* rpipe)
{
if(!fork())
{
if(lpipe) // there's a pipe from the previous process
set_read(lpipe);
// else you may want to redirect input from somewhere else for the start
if(rpipe) // there's a pipe to the next process
set_write(rpipe);
// else you may want to redirect out to somewhere else for the end
// blah do your stuff
// and make sure the child process terminates in here
// so it won't continue running the chaining code
}
}
With this in hand you can now write a loop that continuously forks, attaches the pipes, and then reuses the output pipe as the input pipe for the next one. Of course, once both ends of a pipe have been connected to child processes, the parent should not leave it open for itself.
// This assumes there are at least two processes to be chained :)
// two pipes: one from the previous in the chain, one to the next in the chain
int lpipe[2], rpipe[2];
// create the first output pipe
pipe(rpipe);
// first child takes input from somewhere else
fork_and_chain(NULL, rpipe);
// output pipe becomes input for the next process.
lpipe[0] = rpipe[0];
lpipe[1] = rpipe[1];
// chain all but the first and last children
for(i = 1; i < N - 1; i++)
{
pipe(rpipe); // make the next output pipe
fork_and_chain(lpipe, rpipe);
close(lpipe[0]); // both ends are attached, close them on parent
close(lpipe[1]);
lpipe[0] = rpipe[0]; // output pipe becomes input pipe
lpipe[1] = rpipe[1];
}
// fork the last one, its output goes somewhere else
fork_and_chain(lpipe, NULL);
close(lpipe[0]);
close(lpipe[1]);
The closing bits are very important! When you fork with an open pipe, there will be four open file descriptors: two on the parent process, and two others on the child process. You have to close all of those you won't be using. That's why the code above always closes the irrelevant ends of the pipes in the child processes, and both ends on the parent.
Also note that I am giving special treatment to the first and the last processes, because I don't know where the input for the chain will come from, and where the output will go to.