1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// !> A pipe between two programs [fv]
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <wait.h>

#include <stdio.h>

#include <assert.h>

int main(int argc, char **argv) {

  /* Open files after program starts:
   * 0: stdin
   * 1: stdout
   * 2: stderr
   */

  int pipe_fd[2];

  // create a pipe:
  // pipe_fd[0] is the _read_ end
  // pipe_fd[1] is the _write_ end 
  assert(pipe(pipe_fd) != -1);
  /* Open files after pipe call:
   * 0: stdin
   * 1: stdout
   * 2: stderr
   * 3: pipe read end (pipe_fd[0])
   * 4: pipe write end (pipe_fd[1])
   */

  int write_fd = pipe_fd[1];
  int read_fd = pipe_fd[0];


  printf("read: %d, write: %d\n", read_fd, write_fd);

  pid_t reading_child = fork();
  assert(reading_child != -1);

  if (reading_child == 0) {
    /* Open files in reading_child:
     * 0: stdin
     * 1: stdout
     * 2: stderr
     * 3: pipe read end (pipe_fd[0] / read_fd)
     * 4: pipe write end (pipe_fd[1] / write_fd)
     */

    // both parent and child share both ends, so we'll just close the end we 
    // don't use
    close(pipe_fd[1]);
    /* Open files after closing write end:
     * 0: stdin
     * 1: stdout
     * 2: stderr
     * 3: pipe read end (pipe_fd[0] / read_fd)
     * 4: -
     */

    // close stdin
    close(0);
    /* Open files after closing stdin:
     * 0: -
     * 1: stdout
     * 2: stderr
     * 3: pipe read end (pipe_fd[0] / read_fd)
     * 4: -
     */


    // replace fd 0 with pipe_fd[0] / read_fd
    assert(dup(read_fd) == 0);
    /* Open files after dup:
     * 0: pipe read end (pipe_fd[0] / read_fd)
     * 1: stdout
     * 2: stderr
     * 3: pipe read end (pipe_fd[0] / read_fd)
     * 4: -
     */
    printf("About to run sort...\n");
    assert(-1 != execlp("sort", "sort", NULL));
    // should never get here
    return 1;
  }

  int writing_child = fork();
  assert(writing_child != -1);

  if (writing_child == 0) {
    /* Open files in writing_child:
     * 0: stdin
     * 1: stdout
     * 2: stderr
     * 3: pipe read end (pipe_fd[0] / read_fd)
     * 4: pipe write end (pipe_fd[1] / write_fd)
     */

    close(read_fd);    
    /* Open files after closing read end:
     * 0: stdin
     * 1: stdout
     * 2: stderr
     * 3: - 
     * 4: pipe write end (pipe_fd[1] / write_fd)
     */

    // close stdout
    close(1);
    /* Open files after closing stdout:
     * 0: stdin
     * 1: -
     * 2: stderr
     * 3: - 
     * 4: pipe write end (pipe_fd[1] / write_fd)
     */


    // replace stsdout with write end of pipe
    assert(dup(write_fd) == 1);
    /* Open files after dup:
     * 0: stdin
     * 1: pipe write end (pipe_fd[1] / write_fd)
     * 2: stderr
     * 3: - 
     * 4: pipe write end (pipe_fd[1] / write_fd)
     */

    // run: shuf -i 1-9
    assert(-1 != execlp("shuf", "shuf", "-i", "1-9", NULL));
    // should never get here
    close(pipe_fd[1]);
    close(1);
    return 1;
  }

  /* Open files in parent:
   * 0: stdin
   * 1: stdout
   * 2: stderr
   * 3: pipe read end (pipe_fd[0] / read_fd)
   * 4: pipe write end (pipe_fd[1] / write_fd)
   */
  close(write_fd);
  close(read_fd);
  /* Open files in parent after closing both ends of the pipe:
   * 0: stdin
   * 1: stdout
   * 2: stderr
   * 3: - 
   * 4: - 
   */

  // Wait for both children to finish
  wait(NULL);
  wait(NULL);

  return 0;
}