Implementing Inifinite Piping with C++

This is what I am feeling now after hours of efforts.


For an OS project, we have to implement a working Linux shell using C++ and GNU library. One of the hardest things was implementing the infinite piping. I spent hours on this because I didn’t fully understand the file descriptors, fork(), pipe(), and dup() system commands. Here is a really clean video of explaining them.

Make sure to check out his other videos if you still need help with forks and stuffs.

I have commented in the code below, and hope it will help someone to understand. I haven’t refactored the code as I need to finish the project as it’s due today. I am just posting this before I get lazy and forget.

// Handles piping.
// The input is 2d vector of commands 
// i.e : [ls],[cat],[grep,shell.cpp],[cut,-d,1-2]
int pipeLoop(vector &multiTokens) {
  // Need this for recording the status of each child.
  int status; 
  int statusArr[multiTokens.size()];

  // Initialize the pipes.
  // File descriptor size should be (n-1)*2 because there are 2 ends
  // in each pipe (write(1) and read(0)). i.e A  B  C
  // STD_IN : 0, STD_OUT : 1, STD_ERR : 2
  int pipeFdSize = (multiTokens.size() - 1) * 2; 
  int pipes[pipeFdSize];

  // Wait for each child.
  pid_t waitresult;

  //Initilize the fork() array depending on the size of the commands.
  pid_t forkArr[multiTokens.size()];

  // 0 : success , -1 : error 
  int return_value = -1;

  // Create the pipes. Notice here that we are offsetting by 2. 
  // because a pipe has two ends which requires two slots in the array.
  for (int i = 0; i < pipeFdSize; i += 2) {
    pipe(pipes + i);

  // Now the annoying part.
  for (int i = 0; i < multiTokens.size(); i++) {
    // Call fork() and check error.
    if ((forkArr[i] = fork()) == -1) {
      perror("Pipes fork error ");

    // Child process should execute the commands. Before we do that
    // we have to put a pipe between the parent process and the
    // child process. We will use dup2 because it allows us to set
    // STD_OUT and STD_IN for a specified process.
    if (forkArr[i] == 0) {
      // We need to take care of the special cases : first pipe
      // and last pipe. The pipes in the middle have same behavior.
      // i.e : ABCDE
      if (i == 0) {
        // First pipe. Duplicate a file descriptor to STD_OUT.
        // A  B and A's out is set to the pipe's write.
        dup2(pipes[1], 1);
      } else if (i == multiTokens.size() - 1) {
        // Last index. AB...D and the last's command needs to read
        // from the pipe. Thus, we set the last pipe's read to STD_IN
        // from previous command.
        dup2(pipes[2 * (multiTokens.size() - 1) - 2], 0);
      } else {
        // Middle pipes. A...C...E We want to read the STD_OUT from B
        // to the pipe before C and write STD_IN to the pipe for the next
        // command.
        dup2(pipes[2 * (i - 1)], 0);
        dup2(pipes[(2 * i) + 1], 1);
      // Always make sure to close the pipes. So then, the parent knows if
      // the child has reached to the end of file.
      closePipes(pipes, pipeFdSize);
      // Execute the command
      return_value = execute_line(multiTokens[i]);

  // This is the parent process.
  closePipes(pipes, pipeFdSize);

  // Check the status of each child and wait for finishing the execution.
  for (int i = 0; i < multiTokens.size(); i++) {
    waitresult = waitpid(forkArr[i], &status, WUNTRACED);
    statusArr[i] = status;

  // Last status should indicate the success of the piping.
  if (statusArr[multiTokens.size() - 1] == 0) {
    return_value = 0;

  return return_value;

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>