900 Chapter 44
After duplicating pfd[1], we now have two file descriptors referring to the write end
of the pipe: descriptor 1 and pfd[1]. Since unused pipe file descriptors should be
closed, after the dup2() call, we close the superfluous descriptor:
close(pfd[1]);
The code we have shown so far relies on standard output having been previously
open. Suppose that, prior to the pipe() call, standard input and standard output had
both been closed. In this case, pipe() would have allocated these two descriptors to
the pipe, perhaps with pfd[0] having the value 0 and pfd[1] having the value 1. Con-
sequently, the preceding dup2() and close() calls would be equivalent to the following:
dup2(1, 1); /* Does nothing */
close(1); /* Closes sole descriptor for write end of pipe */
Therefore, it is good defensive programming practice to bracket these calls with an
if statement of the following form:
if (pfd[1] != STDOUT_FILENO) {
dup2(pfd[1], STDOUT_FILENO);
close(pfd[1]);
}
Example program
The program in Listing 44-4 uses the techniques described in this section to bring
about the setup shown in Figure 44-1. After building a pipe, this program creates
two child processes. The first child binds its standard output to the write end of the
pipe and then execs ls. The second child binds its standard input to the read end of
the pipe and then execs wc.
Listing 44-4: Using a pipe to connect ls and wc
––––––––––––––––––––––––––––––––––––––––––––––––––––––– pipes/pipe_ls_wc.c
#include <sys/wait.h>
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int pfd[2]; /* Pipe file descriptors */
if (pipe(pfd) == -1) /* Create pipe */
errExit("pipe");
switch (fork()) {
case -1:
errExit("fork");
case 0: /* First child: exec 'ls' to write to pipe */
if (close(pfd[0]) == -1) /* Read end is unused */
errExit("close 1");