A pipe can be created by calling pipe(int fd[2]). When an error occurs, it sets errno accordingly (check the man pages) and returns -1. When the pipe() function succeeds, a pipe will be created. The two file descriptors are needed when read(int fd[0]) or write(fd[1]) is called. Now we have the pipe which leads output to input.
The standard procedure is then to fork the parent. The result will be a child process which inherits the file descriptors of the parent.
What then should follow is the closing of the file descriptors which are not used. For example, when the parent wants to read data from the child, the parent closes fd[1] and the child closes fd[0].
When close() is used on a file descriptor, an EOF is encountered when using that file descriptor. Then a process won't block while trying to read the pipe when there is nothing in it. Also, no confusion is possible: no two file descriptors are the same.
In this context, the dup() and dup2() system calls are interesting. int dup( int oldfd ) duplicates and connects a file descriptor on the lowest available one. So, when standard input is closed with close(0) and dup(fd[0]) is called, it copies fd[0] and connects the copy on descriptor 0. Now your pipe is connected to standard input when you exec() a program!
In this example, we will create a child process which wants to send a message back to the parent. Thus, we need a pipe!
#include <stdio.h> #include <unistd.h> #include <sys/types.h>
void sillychild(int);
int main(void) { char sz_readbuffer[40]; /* where read() puts the bytes in */ int fd[2]; /* to access the pipe */ int n_bytes_read; /* how much bytes read() returns */ int n_pipe_returnvalue; /* the integer which pipe() returns */ pid_t childpid; /* the unique number of the child process */
n_pipe_returnvalue = pipe(fd); if (n_pipe_returnvalue == -1) { perror("pipe"); exit(1); }
childpid = fork(); if (childpid == -1) { perror("fork"); exit(1); }
if (childpid == 0) /* child process */ { close(fd[0]); /* Close read part of the pipe */ sillychild(fd[1]); exit(0); } else /* parent process */ { close(fd[1]); /* close write part of the pipe */ printf("I try to read from %d...\n",fd[0]); n_bytes_read = read(fd[0], sz_readbuffer, 80); printf("Result: %s\n#bytes: %d\n", sz_readbuffer, n_bytes_read); close(fd[0]); } return(0); }
void sillychild(int fd) { char sz_welcome_message[] = "Hello, world!";
write(fd, sz_welcome_message, sizeof(sz_welcome_message)); close(fd); }