title: Writing own shell - code hangs when handling certain pipes - in C
body: <p>I'm currently writing my own shell as a project for a class, and have everything virtually working. My problem is with my pipes, sometimes they work, and sometimes, they just hang until I interrupt them. I've done research on this, and it seems that the function that is getting it's stdin written to isn't receiving an EOF from the first process; usually as I've learned the problem is that the pipe isn't being closed, but this isn't the case (to my knowledge) with my code.</p>
  
  <p>All redirection works and any variation thereof:</p>
  
  <ul>
  <li><code>ls -l &gt; file1</code></li>
  <li><code>wc &lt; file1 &gt; file2</code></li>
  </ul>
  
  <p>The following piped commands work:</p>
  
  <ul>
  <li><code>w | head -n 4</code></li>
  <li><code>w | head -n 4 &gt; file1</code></li>
  </ul>
  
  <p>This doesn't work: <code>ls | grep file1</code> it shows the correct output and never ends unless an interrupt signal is sent to it by the user. <code>ls | grep file1 &gt; file2</code> also does not work. It hangs without showing output, creates the file2, but never writes to it.</p>
  
  <p>Anyway, I hope there's something I'm missing that someone else can notice; I've been at this for a while. Let me know if there's anymore code I can provide. The code I've posted below is the main file, nothing removed.</p>
  
  <pre><code>/*
   * This code implemenFts a simple shell program
   * At this time it supports just simple commands with 
   * any number of args.
   */
  
  #include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;signal.h&gt;
  #include &lt;sys/wait.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  #include "input.h"
  #include "myShell.h"
  #include "BackgroundStack.h"
  
  /*
   * The main shell function
   */ 
  main() {
      char *buff[20];
      char *inputString;
  
      BackgroundStack *bgStack = malloc(sizeof(BackgroundStack));
      initBgStack(bgStack);
  
      struct sigaction new_act;
      new_act.sa_handler = sigIntHandler;
      sigemptyset ( &amp;new_act.sa_mask );
      new_act.sa_flags = SA_RESTART;
      sigaction(SIGINT, &amp;new_act, NULL);
  
      // Loop forever
      while(1) {
          const char *chPath;
  
          doneBgProcesses(bgStack);
  
          // Print out the prompt and get the input
          printPrompt();
  
          inputString = get_my_args(buff);
          if (buff[0] == NULL) continue;
  
          if (buff[0][0] == '#') continue;
  
          switch (getBuiltInCommand(buff[0])) {
              case EXIT:
                  exit(0);
                  break;
              case CD:
                  chPath = (buff[1]==NULL) ? getenv("HOME") : buff[1];
                  if (chdir(chPath) &lt; 0) {
                      perror(": cd");
                  }
                  break;
              default:
                  do_command(buff, bgStack);
          }
  
          //free up the malloced memory
          free(inputString);
      }// end of while(1)
  }
  
  static void sigIntHandler (int signum) {}
  
  /* 
   * Do the command
   */
  int do_command(char **args, BackgroundStack *bgStack) {
      int status, statusb;  
      pid_t child_id, childb_id;
      char **argsb;
      int pipes[2];
  
      int isBgd = isBackgrounded(args);
      int hasPipe = hasAPipe(args);
  
      if (isBgd) removeBackgroundCommand(args);
      if (hasPipe) {
          int cmdBi = getSecondCommandIndex(args);
          args[cmdBi-1] = NULL;
          argsb = &amp;args[cmdBi];
          pipe(pipes);
      }
  
      // Fork the child and check for errors in fork()
      if((child_id = fork()) == -1) {
          switch(errno) {
              case EAGAIN:
                  perror("Error EAGAIN: ");
                  return;
              case ENOMEM:
                  perror("Error ENOMEM: ");
                  return;
          }
      }
  
      if (hasPipe &amp;&amp; child_id != 0) {
          childb_id = fork();
          if(childb_id == -1) {
              switch(errno) {
                  case EAGAIN:
                      perror("Error EAGAIN: ");
                      return;
                  case ENOMEM:
                      perror("Error ENOMEM: ");
                      return;
              }
          }
      }
  
      if(child_id == 0 || (childb_id == 0 &amp;&amp; hasPipe)) {
          if (child_id != 0 &amp;&amp; hasPipe) args = argsb;
          if (child_id == 0 &amp;&amp; isBgd) {
              struct sigaction new_act;
              new_act.sa_handler = SIG_IGN;
              sigaction(SIGINT, &amp;new_act, 0);
          }
  
          if (child_id == 0 &amp;&amp; hasPipe) {
              if (dup2(pipes[1], 1) != 1) fatalPerror(": Pipe Redirection Output Error");
              close(pipes[0]);
              close(pipes[1]);
          }
          if (child_id != 0 &amp;&amp; hasPipe) {
              if (dup2(pipes[0], 0) != 0) fatalPerror(": Pipe Redirection Input Error");
              close(pipes[0]);
              close(pipes[1]);
              waitpid(child_id, NULL, 0);
          }
  
          if ((child_id != 0 &amp;&amp; hasPipe) || !hasPipe) {
              if (hasAReOut(args)) {
                  char outFile[100];
                  getOutFile(args, outFile);
  
                  int reOutFile = open(outFile, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE);
                  if (reOutFile&lt;0) fatalPerror(": Redirection Output Error");
  
                  if (dup2(reOutFile,1) != 1) fatalPerror(": Redirection Output Error");
                  close(reOutFile);
              }
          }
  
          if ( (child_id == 0 &amp;&amp; hasPipe) || !hasPipe) {
              if (hasAReIn(args)) {
                  char inFle[100];
                  getInFile(args, inFle);
  
                  int reInFile = open(inFle, O_RDWR);
                  if (reInFile&lt;0) fatalPerror(": Redirection Input Error");
  
                  if (dup2(reInFile,0) != 0) fatalPerror(": Redirection Input Error");
                  close(reInFile);
              } else if (isBgd &amp;&amp; !hasPipe) {
                  int bgReInFile = open("/dev/null", O_RDONLY);
                  if (bgReInFile&lt;0) fatalPerror(": /dev/null Redirection Input Error");
  
                  if (dup2(bgReInFile,0) != 0) fatalPerror(": /dev/null Redirection Input Error");
                  close(bgReInFile);
              }
          }
  
          // Execute the command
          execvp(args[0], args);
          perror(args[0]);
  
          exit(-1);
      }
  
      // Wait for the child process to complete, if necessary
      if (!isBgd) waitpid(child_id, &amp;status, 0);
      else if (!hasPipe) {
          printf("Child %ld started\n", (long)child_id);
          BackgroundProcess *bgPrs = malloc(sizeof(BackgroundProcess)); 
          bgPrs-&gt;pid = child_id;
          bgPrs-&gt;exitStatus = -1;
  
          addProcessToBgStack(bgStack, bgPrs);
      }
      if (hasPipe) waitpid(childb_id, &amp;statusb, 0);
      if ( WIFSIGNALED(status) &amp;&amp; !isBgd )    printf("Child %ld terminated due to signal %d\n", (long)child_id, WTERMSIG(status) );
      if ( hasPipe &amp;&amp; WIFSIGNALED(statusb) ) printf("Child %ld terminated due to signal %d\n", (long)childb_id, WTERMSIG(status) );
  
  } // end of do_command
  </code></pre>