SEC. 1.6 SYSTEM CALLS 55
the parent executes a waitpid system call, which just waits until the child
terminates
(any child if more than one exists). Waitpid can wait for a specific child, or for any
old child by setting the first parameter to 1. When waitpid completes, the address
pointed to by the second parameter, statloc, will be set to the child process’ exit
status (normal or abnormal termination and exit value). Various options are also
provided, specified by the third parameter. For example, returning immediately if
no child has already exited.
Now consider how fork is used by the shell. When a command is typed, the
shell forks off a new process. This child process must execute the user command.
It does this by using the execve system call, which causes its entire core image to
be replaced by the file named in its first parameter. (Actually, the system call itself
is exec, but several library procedures call it with different parameters and slightly
different names. We will treat these as system calls here.) A highly simplified shell
illustrating the use of fork, waitpid, and execve is shown in Fig. 1-19.
#define TRUE 1
while (TRUE) {
/* repeat forever */
type prompt( );
/* display prompt on the screen */
read command(command, parameters); /* read input from terminal */
if (for k( ) != 0){
/* Parent code. */
waitpid(−1, &status, 0);
} else {
/* Child code. */
execve(command, parameters, 0);
}
}
/* fork off child process */
/* wait for child to exit */
/* execute command */
Figure 1-19. A stripped-down shell. Throughout this book, TRUE is assumed to
be defined as 1.
In the most general case, execve has three parameters: the name of the file to
be executed, a pointer to the argument array, and a pointer to the environment
array. These will be described shortly. Various library routines, including execl,
execv, execle, and execve, are provided to allow the parameters to be omitted or
specified in various ways. Throughout this book we will use the name exec to
represent the system call invoked by all of these.
Let us consider the case of a command such as
cp file1 file2
used to copy file1 to file2. After the shell has forked, the child process locates and
executes the file cp and passes to it the names of the source and target files.