Saturday, March 7, 2015

Implementing a pipeline for two commands in Linux from C++

Executes the first command and redirects it's output to the second.

False waitExecution causes the the first command to be executed at the time of the call and the second when the background handler allows it.
redIn refers to the first command and redOut to the second.

If the command parameters do not contain "/" the executable is searched in PATH.

Throws errno in case of failed pipelining,failed forking,failed redirection when waitExecution is true and failed background handling and initiation of the new process.

redIn,redOut should be NULL if no redirection is required,append should be true if output needs to be redirected to a file,appened at the end.

Check LinuxShell for missing methods and complete source code.

void pipe(const char *command1, char *const args1[],const char *command2, char *const args2[],bool waitExecution,const char *redIn,const char* redOut,bool append){

  int pipeDesc[2];
  bool error=false;
  if(pipe(pipeDesc)<0){
    throw errno;
  }
  pid_t pid1,pid2;
  int in=-1,out=-1;
  if((pid1=fork())==0){//first command handling
    dup2(pipeDesc[1],1);
    close(pipeDesc[0]);
    close(pipeDesc[1]);
    if(redIn!=NULL){
      try{
        in=startRedirectIn(redIn);
      }catch(int ex){
        exit(ex);
      }
    }
    stopRedirect(in);
    execvp(command1,args1);
    exit(1);
  }
  if(pid1==-1){//fork error
    throw errno;
  }
  if((pid2=fork())==0){//second command handling
    dup2(pipeDesc[0],0);
    close(pipeDesc[0]);
    close(pipeDesc[1]);
    if(redOut!=NULL){
      try{
        in=startRedirectOut(redOut,append);
      }catch(int ex){
        exit(ex);
      }
    }
    stopRedirect(out);
    execvp(command2,args2);
    exit(1);
  }
  if(pid2==-1){//fork error
    throw errno;
  }
  close(pipeDesc[0]);
  close(pipeDesc[1]);

  if(waitExecution){
    int status;
    pid_t ws=wait(&status);
    if(ws!=-1){//first command is executed
      if(WIFEXITED(status)){
        int exitStatus=WEXITSTATUS(status);
        if(exitStatus!=0){
          kill(pid2,SIGKILL);
          throw exitStatus;
        }
      }
    }else{// error while executing the first command
      throw errno;
    }
    ws=wait(&status);
    if(ws!=-1){//second command is executed
      if(WIFEXITED(status)){
        int exitStatus=WEXITSTATUS(status);
        if(exitStatus!=0){
          throw exitStatus;
        }
      }
    }else{// error while executing the second command
      throw errno;
    }
  }else{// waitExecution is false
    int status;
    pid_t ws=wait(&status);
    bool pid1Finished=true;
    if(ws!=-1){//first command is executed
      if(WIFEXITED(status)){
        int exitStatus=WEXITSTATUS(status);
        if(exitStatus!=0){
          kill(pid2,SIGKILL);
          throw exitStatus;
        }
      }
    }else{// error while executing the first command
      throw errno;
    }
    if(kill(pid2,SIGSTOP)==0){
      backgroundProcs.push_back(pid2);
    }else{
      throw errno;
    }
  }


}

No comments: