title: UNIX pipes on C block on read
body: <p>I'm struggling to implement a shell with pipelines for class.</p>
  
  <pre><code>typedef struct {
      char** cmd;
      int in[2];
      int out[2];
  } cmdio;
  
  cmdio cmds[MAX_PIPE + 1];
  </code></pre>
  
  <p>Commands in the pipeline are read and stored in <code>cmds</code>.</p>
  
  <p><code>cmdio[i].in</code> is the pair of file descriptors of the input pipe returned by <code>pipe()</code>. For the first command, which reads from terminal input, it is just {fileno(stdin), -1}. <code>cmdin[i].out</code>is similar for the output pipe/terminal output. <code>cmdio[i].in</code> is the same as <code>cmd[i-1].out</code>. For example:</p>
  
  <pre><code>$ ls -l | sort | wc
  
  CMD: ls -l 
  IN: 0 -1
  OUT: 3 4
  
  CMD: sort 
  IN: 3 4
  OUT: 5 6
  
  CMD: wc 
  IN: 5 6
  OUT: -1 1
  </code></pre>
  
  <p>We pass each command to process_command, which does a number of things:</p>
  
  <pre><code>for (cmdi = 0; cmds[cmdi].cmd != NULL; cmdi++) {
      process_command(&amp;cmds[cmdi]);
  }
  </code></pre>
  
  <p>Now, inside process_command:</p>
  
  <pre><code>if (!(pid_fork = fork())) {
      dup2(cmd-&gt;in[0], fileno(stdin));
      dup2(cmd-&gt;out[1], fileno(stdout));    
      if (cmd-&gt;in[1] &gt;= 0) {
          if (close(cmd-&gt;in[1])) {
              perror(NULL);
          }
      }
      if (cmd-&gt;out[0] &gt;= 0) {
          if (close(cmd-&gt;out[0])) {
              perror(NULL);
          }
      }
      execvp(cmd-&gt;cmd[0], cmd-&gt;cmd);
      exit(-1);
  }
  </code></pre>
  
  <p>The problem is that reading from the pipe blocks forever:</p>
  
  <pre><code>COMMAND $ ls | wc
  Created pipe, in: 5 out: 6
  Foreground pid: 9042, command: ls, Exited, info: 0
  [blocked running read() within wc]
  </code></pre>
  
  <p>If, instead of exchanging the process with <code>execvp</code>, I just do this:</p>
  
  <pre><code>if (!(pid_fork = fork())) {
      dup2(cmd-&gt;in[0], fileno(stdin));
      dup2(cmd-&gt;out[1], fileno(stdout));
      if (cmd-&gt;in[1] &gt;= 0) {
          if (close(cmd-&gt;in[1])) {
              perror(NULL);
          }
      }
      if (cmd-&gt;out[0] &gt;= 0) {
          if (close(cmd-&gt;out[0])) {
              perror(NULL);
          }
      }
  
      char buf[6];
      read(fileno(stdin), buf, 5);
      buf[5] = '\0';
  
      printf("%s\n", buf);
      exit(0);
  }
  </code></pre>
  
  <p>It happens to work:</p>
  
  <pre><code>COMMAND $ cmd1 | cmd2 | cmd3 | cmd4 | cmd5 
  Pipe creada, in: 11 out: 12
  Pipe creada, in: 13 out: 14
  Pipe creada, in: 15 out: 16
  Pipe creada, in: 17 out: 18
  hola!
  Foreground pid: 9251, command: cmd1, Exited, info: 0
  Foreground pid: 9252, command: cmd2, Exited, info: 0
  Foreground pid: 9253, command: cmd3, Exited, info: 0
  Foreground pid: 9254, command: cmd4, Exited, info: 0
  hola!
  Foreground pid: 9255, command: cmd5, Exited, info: 0
  </code></pre>
  
  <p>What could be the problem?</p>