Initial revision
authorrms <rms>
Tue, 19 May 1992 21:52:57 +0000 (21:52 +0000)
committerrms <rms>
Tue, 19 May 1992 21:52:57 +0000 (21:52 +0000)
manual/process.texi [new file with mode: 0644]

diff --git a/manual/process.texi b/manual/process.texi
new file mode 100644 (file)
index 0000000..a29262b
--- /dev/null
@@ -0,0 +1,739 @@
+@node Child Processes, Job Control, Process Startup, Top
+@chapter Child Processes
+
+@cindex process
+@dfn{Processes} are the primitive units for allocation of system
+resources.  Each process has its own address space and (usually) one
+thread of control.  A process executes a program; you can have multiple
+processes executing the same program, but each process has its own copy
+of the program within its own address space and executes it
+independently of the other copies.
+
+@cindex child process
+@cindex parent process
+Processes are organized hierarchically.  Each process has a @dfn{parent
+process} which explicitly arranged to create it.  The processes created
+by a given parent are called its @dfn{child processes}.  A child
+inherits many of its attributes from the parent process.
+
+This chapter describes how a program can create, terminate, and control
+child processes.  Actually, there are three distinct operations
+involved: creating a new child process, causing the new process to
+execute a program, and coordinating the completion of the child process
+with the original program.
+
+The @code{system} function provides a simple, portable mechanism for
+running another program; it does all three steps automatically.  If you
+need more control over the details of how this is done, you can use the
+primitive functions to do each step individually instead.
+
+@menu
+* Running a Command::           The easy way to run another program.
+* Process Creation Concepts::   An overview of the hard way to do it.
+* Process Identification::      How to get the process ID of a process.
+* Creating a Process::          How to fork a child process.
+* Executing a File::            How to get a process to execute another
+                                        program.
+* Process Completion::          How to tell when a child process has
+                                        completed.
+* Process Completion Status::   How to interpret the status value 
+                                         returned from a child process.
+* BSD Wait Functions::         More functions, for backward compatibility.
+* Process Creation Example::    A complete example program.
+@end menu
+
+
+@node Running a Command
+@section Running a Command
+@cindex running a command
+
+The easy way to run another program is to use the @code{system}
+function.  This function does all the work of running a subprogram, but
+it doesn't give you much control over the details: you have to wait
+until the subprogram terminates before you can do anything else.
+
+@comment stdlib.h
+@comment ANSI
+@deftypefun int system (const char *@var{command})
+@pindex sh
+This function executes @var{command} as a shell command.  In the GNU C
+library, it always uses the default shell @code{sh} to run the command.
+In particular, it searching the directories in @code{PATH} to find
+programs to execute.  The return value is @code{-1} if it wasn't
+possible to create the shell process, and otherwise is the status of the
+shell process.  @xref{Process Completion}, for details on how this
+status code can be interpreted.
+
+@pindex stdlib.h
+The @code{system} function is declared in the header file
+@file{stdlib.h}.
+@end deftypefun
+
+@strong{Portability Note:} Some C implementations may not have any
+notion of a command processor that can execute other programs.  You can
+determine whether a command processor exists by executing @code{system
+(o)}; if the return value is nonzero, a command processor is available.
+
+The @code{popen} and @code{pclose} functions (@pxref{Pipe to a
+Subprocess}) are closely related to the @code{system} function.  They
+allow the parent process to communicate with the standard input and
+output channels of the command being executed.
+
+@node Process Creation Concepts
+@section Process Creation Concepts
+
+This section gives an overview of processes and of the steps involved in
+creating a process and making it run another program.
+
+@cindex process ID
+@cindex process lifetime
+Each process is named by a @dfn{process ID} number.  A unique process ID
+is allocated to each process when it is created.  The @dfn{lifetime} of
+a process ends when its termination is reported to its parent process;
+at that time, all of the process resources, including its process ID,
+are freed.
+
+@cindex creating a process
+@cindex forking a process
+@cindex child process
+@cindex parent process
+Processes are created with the @code{fork} system call (so the operation
+of creating a new process is sometimes called @dfn{forking} a process).
+The @dfn{child process} created by @code{fork} is an exact clone of the
+original @dfn{parent process}, except that it has its own process ID.
+
+After forking a child process, both the parent and child processes
+continue to execute normally.  If you want your program to wait for a
+child process to finish executing before continuing, you must do this
+explicitly after the fork operation, by calling @code{wait} or
+@code{waitpid} (@pxref{Process Completion}).  These functions give you
+limited information about why the child terminated---for example, its
+exit status code.
+
+A newly forked child process continues to execute the same program as
+its parent process, at the point where the @code{fork} call returns.
+You can use the return value from @code{fork} to tell whether the program
+is running in the parent process or the child.
+
+@cindex process image
+Having several processes run the same program is only occasionally
+useful.  But the child can execute another program using one of the
+@code{exec} functions; see @ref{Executing a File}.  The program that the
+process is executing is called its @dfn{process image}.  Starting
+execution of a new program causes the process to forget all about its
+previous process image; when the new program exits, the process exits
+too, instead of returning to the previous process image.
+
+@node Process Identification
+@section Process Identification
+
+The @code{pid_t} data type represents process IDs.  You can get the
+process ID of a process by calling @code{getpid}.  The function
+@code{getppid} returns the process ID of the parent of the parent of the
+current process (this is also known as the @dfn{parent process ID}).
+Your program should include the header files @file{unistd.h} and
+@file{sys/types.h} to use these functions.
+@pindex sys/types.h
+@pindex unistd.h
+
+@comment sys/types.h
+@comment POSIX.1
+@deftp {Data Type} pid_t
+The @code{pid_t} data type is a signed integer type which is capable
+of representing a process ID.  In the GNU library, this is an @code{int}.
+@end deftp
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun pid_t getpid ()
+The @code{getpid} function returns the process ID of the current process.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun pid_t getppid ()
+The @code{getppid} function returns the process ID of the parent of the
+current process.
+@end deftypefun
+
+@node Creating a Process
+@section Creating a Process
+
+The @code{fork} function is the primitive for creating a process.
+It is declared in the header file @file{unistd.h}.
+@pindex unistd.h
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun pid_t fork ()
+The @code{fork} function creates a new process.
+
+If the operation is successful, there are then both parent and child
+processes and both see @code{fork} return, but with different values: it
+returns a value of @code{0} in the child process and returns the child's
+process ID in the parent process.
+
+If process creation failed, @code{fork} returns a value of @code{-1} in
+the parent process.  The following @code{errno} error conditions are
+defined for @code{fork}:
+
+@table @code
+@item EAGAIN
+There aren't enough system resources to create another process, or the
+user already has too many processes running.
+
+@item ENOMEM
+The process requires more space than the system can supply.
+@end table
+@end deftypefun
+
+The specific attributes of the child process that differ from the
+parent process are:
+
+@itemize @bullet
+@item
+The child process has its own unique process ID.
+
+@item
+The parent process ID of the child process is the process ID of its
+parent process.
+
+@item
+The child process gets its own copies of the parent process's open file
+descriptors.  Subsequently changing attributes of the file descriptors
+in the parent process won't affect the file descriptors in the child,
+and vice versa.  @xref{Control Operations}.
+
+@item
+The elapsed processor times for the child process are set to zero;
+see @ref{Processor Time}.
+
+@item
+The child doesn't inherit file locks set by the parent process.
+@xref{Control Operations}.
+
+@item
+The child doesn't inherit alarms set by the parent process.
+@xref{Setting an Alarm}.
+
+@item
+The set of pending signals (@pxref{Delivery of Signal}) for the child
+process is cleared.  (The child process inherits its mask of blocked
+signals and signal actions from the parent process.)
+@end itemize 
+
+
+@comment unistd.h
+@comment BSD
+@deftypefun pid_t vfork ()
+The @code{vfork} function is similar to @code{fork} but more efficient;
+however, there are restrictions you must follow to use it safely.
+
+While @code{fork} makes a complete copy of the calling process's address
+space and allows both the parent and child to execute independently,
+@code{vfork} does not make this copy.  Instead, the child process
+created with @code{vfork} shares its parent's address space until it calls
+one of the @code{exec} functions.  In the meantime, the parent process
+suspends execution.
+
+You must be very careful not to allow the child process created with
+@code{vfork} to modify any global data or even local variables shared
+with the parent.  Furthermore, the child process cannot return from (or
+do a long jump out of) the function that called @code{vfork}!  This
+would leave the parent process's control information very confused.  If
+in doubt, use @code{fork} instead.
+
+Some operating systems don't really implement @code{vfork}.  The GNU C
+library permits you to use @code{vfork} on all systems, but actually
+executes @code{fork} if @code{vfork} isn't available.  If you follow
+the proper precautions for using @code{vfork}, your program will still
+work even if the system uses @code{fork} instead.
+@end deftypefun
+
+@node Executing a File
+@section Executing a File
+@cindex executing a file
+@cindex @code{exec} functions
+
+This section describes the @code{exec} family of functions, for executing
+a file as a process image.  You can use these functions to make a child
+process execute a new program after it has been forked.
+
+@pindex unistd.h
+The functions in this family differ in how you specify the arguments,
+but otherwise they all do the same thing.  They are declared in the
+header file @file{unistd.h}.
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execv (const char *@var{filename}, char *const @var{argv}@t{[]})
+The @code{execv} function executes the file named by @var{filename} as a
+new process image.
+
+The @var{argv} argument is an array of null-terminated strings that is
+used to provide a value for the @code{argv} argument to the @code{main}
+function of the program to be executed.  The last element of this array
+must be a null pointer.  @xref{Program Arguments}, for information on
+how programs can access these arguments.
+
+The environment for the new process image is taken from the
+@code{environ} variable of the current process image; see @ref{Environment
+Variables}, for information about environments.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execl (const char *@var{filename}, const char *@var{arg0}, @dots{})
+This is similar to @code{execv}, but the @var{argv} strings are
+specified individually instead of as an array.  A null pointer must be
+passed as the last such argument.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execve (const char *@var{filename}, char *const @var{argv}@t{[]}, char *const @var{env}@t{[]})
+This is similar to @code{execv}, but permits you to specify the environment
+for the new program explicitly as the @var{env} argument.  This should
+be an array of strings in the same format as for the @code{environ} 
+variable; see @ref{Environment Access}.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execle (const char *@var{filename}, const char *@var{arg0}, char *const @var{env}@t{[]}, @dots{})
+This is similar to @code{execl}, but permits you to specify the
+environment for the new program explicitly.  The environment argument is
+passed following the null pointer that marks the last @var{argv}
+argument, and should be an array of strings in the same format as for
+the @code{environ} variable.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execvp (const char *@var{filename}, char *const @var{argv}@t{[]})
+The @code{execvp} function is similar to @code{execv}, except that it
+searches the directories listed in the @code{PATH} environment variable
+(@pxref{Standard Environment}) to find the full file name of a
+file from @var{filename} if @var{filename} does not contain a slash.
+
+This function is useful for executing system utility programs, because
+it looks for them in the places that the user has chosen.  Shells use it
+to run the commands that users type.
+@end deftypefun
+
+@comment unistd.h
+@comment POSIX.1
+@deftypefun int execlp (const char *@var{filename}, const char *@var{arg0}, @dots{})
+This function is like @code{execl}, except that it performs the same
+file name searching as the @code{execvp} function.
+@end deftypefun
+
+
+The size of the argument list and environment list taken together must not
+be greater than @code{ARG_MAX} bytes.  @xref{System Parameters}.
+
+@strong{Incomplete:}  The POSIX.1 standard requires some statement here
+about how null terminators, null pointers, and alignment requirements
+affect the total size of the argument and environment lists.
+
+These functions normally don't return, since execution of a new program
+causes the currently executing program to go away completely.  A value
+of @code{-1} is returned in the event of a failure.  In addition to the
+usual file name syntax errors (@pxref{File Name Errors}), the following
+@code{errno} error conditions are defined for these functions:
+
+@table @code
+@item E2BIG
+The combined size of the new program's argument list and environment list
+is larger than @code{ARG_MAX} bytes.
+
+@item ENOEXEC
+The specified file can't be executed because it isn't in the right format.
+
+@item ENOMEM
+Executing the specified file requires more storage than is available.
+@end table
+
+If execution of the new file succeeds, it updates the access time field
+of the file as if the file had been opened.  @xref{File Times}, for more
+details about access times of files.
+
+The point at which the file is closed again is not specified, but
+is at some point before the process exits or before another process
+image is executed.
+
+Executing a new process image completely changes the contents of memory,
+except for the arguments and the environment, but many other attributes
+of the process are unchanged:
+
+@itemize @bullet
+@item
+The process ID and the parent process ID.  @xref{Process Creation Concepts}.
+
+@item
+Session and process group membership.  @xref{Job Control Concepts}.
+
+@item
+Real user ID and group ID, and supplementary group IDs.  @xref{Process
+Persona}.
+
+@item
+Pending alarms.  @xref{Setting an Alarm}.
+
+@item
+Current working directory and root directory.  @xref{Working Directory}.
+
+@item
+File mode creation mask.  @xref{Setting Permissions}.
+
+@item
+Process signal mask; see @ref{Process Signal Mask}.
+
+@item
+Pending signals; see @ref{Blocking Signals}.
+
+@item
+Elapsed processor time associated with the process; see @ref{Processor Time}.
+@end itemize
+
+If the set-user-ID and set-group-ID mode bits of the process image file
+are set, this affects the effective user ID and effective group ID
+(respectively) of the process.  These concepts are discussed in detail
+in @ref{User/Group IDs of a Process}.
+
+Signals that are set to be ignored in the existing process image are
+also set to be ignored in the new process image.  All other signals are
+set to the default action in the new process image.  For more
+information about signals, see @ref{Signal Handling}.
+
+File descriptors open in the existing process image remain open in the
+new process image, unless they have the @code{FD_CLOEXEC}
+(close-on-exec) flag set.  The files that remain open inherit all
+attributes of the open file description from the existing process image,
+including file locks.  File descriptors are discussed in @ref{Low-Level
+Input/Output}.
+
+Streams, by contrast, cannot survive through @code{exec} functions,
+because they are located in the memory of the process itself.  The new
+process image has no streams except those it creates afresh.  Each of
+the streams in the pre-@code{exec} process image has a descriptor inside
+it, and these descriptors do survive through @code{exec} (provided that
+they do not have @code{FD_CLOEXEC} set.  The new process image can
+reconnect these to new streams using @code{fdopen} (@pxref{Descriptors
+and Streams}).
+
+@node Process Completion
+@section Process Completion
+@cindex process completion
+@cindex waiting for completion of child process
+@cindex testing exit status of child process
+
+The functions described in this section are used to wait for a child
+process to terminate or stop, and determine its status.  These functions
+are declared in the header file @file{sys/wait.h}.
+@pindex sys/wait.h
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefun pid_t waitpid (pid_t @var{pid}, int *@var{status_ptr}, int @var{options})
+The @code{waitpid} function is used to request status information from a
+child process whose process ID is @var{pid}.  Normally, the calling
+process is suspended until the child process makes status information
+available by terminating.
+
+Other values for the @var{pid} argument have special interpretations.  A
+value of @code{-1} or @code{WAIT_ANY} requests status information for
+any child process; a value of @code{0} or @code{WAIT_MYPGRP} requests
+information for any child process in the same process group as the
+calling process; and any other negative value @minus{} @var{pgid}
+requests information for any child process whose process group ID is
+@var{pgid}.
+
+If status information for a child process is available immediately, this
+function returns immediately without waiting.  If more than one eligible
+child process has status information available, one of them is chosen
+randomly, and its status is returned immediately.  To get the status
+from the other eligible child processes, you need to call @code{waitpid}
+again.
+
+The @var{options} argument is a bit mask.  Its value should be the
+bitwise OR (that is, the @samp{|} operator) of zero or more of the
+@code{WNOHANG} and @code{WUNTRACED} flags.  You can use the
+@code{WNOHANG} flag to indicate that the parent process shouldn't wait;
+and the @code{WUNTRACED} flag to request status information from stopped
+processes as well as processes that have terminated.
+
+The status information from the child process is stored in the object
+that @var{status_ptr} points to, unless @var{status_ptr} is a null pointer.
+
+The return value is normally the process ID of the child process whose
+status is reported.  If the @code{WNOHANG} option was specified and no
+child process is waiting to be noticed, the value is zero.  A value of
+@code{-1} is returned in case of error.  The following @code{errno}
+error conditions are defined for this function:
+
+@table @code
+@item EINTR
+The function was interrupted by delivery of a signal to the calling
+process.
+
+@item ECHILD
+There are no child processes to wait for, or the specified @var{pid}
+is not a child of the calling process.
+
+@item EINVAL
+An invalid value was provided for the @var{options} argument.
+@end table
+@end deftypefun
+
+These symbolic constants are defined as values for the @var{pid} argument
+to the @code{waitpid} function.
+
+@table @code
+@item WAIT_ANY
+This constant macro (whose value is @code{-1}) specifies that
+@code{waitpid} should return status information about any child process.
+
+@item WAIT_MYPGRP
+This constant (with value @code{0}) specifies that @code{waitpid} should
+return status information about any child process in the same process
+group as the calling process.
+
+These symbolic constants are defined as flags for the @var{options}
+argument to the @code{waitpid} function.  You can bitwise-OR the flags
+together to obtain a value to use as the argument.
+
+@item WNOHANG
+This flag specifies that @code{waitpid} should return immediately
+instead of waiting, if there is no child process ready to be noticed.
+
+@item WUNTRACED
+This flag specifies that @code{waitpid} should report the status of any
+child processes that have been stopped as well as those that have
+terminated.
+@end table
+
+@deftypefun pid_t wait (int *@var{status_ptr})
+This is a simplified version of @code{waitpid}, and is used to wait
+until any one child process terminates.
+
+@example
+wait (&status)
+@end example
+
+@noindent
+is equivalent to:
+
+@example
+waitpid (-1, &status, 0)
+@end example
+
+Here's an example of how to use @code{waitpid} to get the status from
+all child processes that have terminated, without ever waiting.  This
+function is designed to be a handler for @code{SIGCHLD}, the signal that
+indicates that at least one child process has terminated.
+
+@example
+void
+sigchld_handler (int signum)
+@{
+  int pid;
+  int status;
+  while (1) @{
+    pid = waitpid (WAIT_ANY, &status, WNOHANG);
+    if (pid < 0) @{
+      perror ("waitpid");
+      break;
+    @}
+    if (pid == 0)
+      break;
+    notice_termination (pid, status);
+  @}
+@}
+@end example
+@end deftypefun
+
+@node Process Completion Status
+@section Process Completion Status
+
+If the exit status value (@pxref{Program Termination}) of the child
+process is zero, then the status value reported by @code{waitpid} or
+@code{wait} is also zero.  You can test for other kinds of information
+encoded in the returned status value using the following macros.
+These macros are defined in the header file @file{sys/wait.h}.
+@pindex sys/wait.h
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WIFEXITED (int @var{status})
+This macro returns a non-zero value if the child process terminated
+normally with @code{exit} or @code{_exit}.
+@end deftypefn
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WEXITSTATUS (int @var{status})
+If @code{WIFEXITED} is true of @var{status}, this macro returns the
+low-order 8 bits of the exit status value from the child process.
+@end deftypefn
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WIFSIGNALED (int @var{status})
+This macro returns a non-zero value if the child process terminated
+because it received a signal that was not handled.
+@end deftypefn
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WTERMSIG (int @var{status})
+If @code{WIFSIGNALED} is true of @var{status}, this macro returns the
+signal number of the signal that terminated the child process.
+@end deftypefn
+
+@comment sys/wait.h
+@comment BSD
+@deftypefn Macro int WCOREDUMP (int @var{status})
+This macro returns a non-zero value if the child process terminated
+and produced a core dump.
+@end deftypefn
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WIFSTOPPED (int @var{status})
+This macro returns a non-zero value if the child process is stopped.
+@end deftypefn
+
+@comment sys/wait.h
+@comment POSIX.1
+@deftypefn Macro int WSTOPSIG (int @var{status})
+If @code{WIFSTOPPED} is true of @var{status}, this macro returns the
+signal number of the signal that caused the child process to stop.
+@end deftypefn
+
+
+@node BSD Wait Functions
+@section BSD Process Wait Functions
+
+The GNU library also provides these related facilities for compatibility
+with BSD Unix.  BSD uses the @code{union wait} data type to represent
+status values rather than an @code{int}.  The two representations are
+actually interchangeable; they describe the same bit patterns.  The GNU
+C Library defines macros such as @code{WEXITSTATUS} so that they will
+work on either kind of object, and the @code{wait} function is defined
+to accept either type of pointer as its @var{status_ptr} argument.
+
+These functions are declared in @file{sys/wait.h}.
+@pindex sys/wait.h
+
+@comment sys/wait.h
+@comment BSD
+@deftp {Data Type} {union wait}
+This data type represents program termination status values.  It has
+the following members:
+
+@table @code
+@item int w_termsig
+This member is equivalent to the @code{WTERMSIG} macro.
+
+@item int w_coredump
+This member is equivalent to the @code{WCOREDUMP} macro.
+
+@item int w_retcode
+This member is equivalent to the @code{WEXISTATUS} macro.
+
+@item int w_stopsig
+This member is equivalent to the @code{WSTOPSIG} macro.
+@end table
+
+Instead of accessing these members directly, you should use the
+equivalent macros.
+@end deftp
+
+@comment sys/wait.h
+@comment BSD
+@deftypefun pid_t wait3 (union wait *@var{status_ptr}, int @var{options}, void * @var{usage})
+If @var{usage} is a null pointer, this function is equivalent to
+@code{waitpid (-1, @var{status_ptr}, @var{options})}.
+
+The @var{usage} argument may also be a pointer to a 
+@code{struct rusage} object.  Information about system resources used by
+terminated processes (but not stopped processes) is returned in this
+structure.
+
+@strong{Incomplete:}  The description of the @code{struct rusage} structure
+hasn't been written yet.  Put in a cross-reference here.
+@end deftypefun
+
+@comment sys/wait.h
+@comment BSD
+@deftypefun pid_t wait4 (pid_t @var{pid}, union wait *@var{status_ptr}, int @var{options}, void *@var{usage})
+If @var{usage} is a null pointer, this function is equivalent to
+@code{waitpid (@var{pid}, @var{status_ptr}, @var{options})}.
+
+The @var{usage} argument may also be a pointer to a 
+@code{struct rusage} object.  Information about system resources used by
+terminated processes (but not stopped processes) is returned in this
+structure.
+
+@strong{Incomplete:}  The description of the @code{struct rusage} structure
+hasn't been written yet.  Put in a cross-reference here.
+@end deftypefun
+
+@node Process Creation Example
+@section Process Creation Example
+
+Here is an example program showing how you might write a function
+similar to the built-in @code{system}.  It executes its @var{command}
+argument using the equivalent of @samp{sh -c @var{command}}.
+
+@example
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* @r{Execute the command using this shell program.}  */
+#define SHELL "/bin/sh"
+
+int 
+my_system (char *command)
+@{
+  int status;
+  pid_t pid;
+
+  pid =  fork ();
+  if (pid == 0) @{
+    /* @r{This is the child process.  Execute the shell command.} */
+    execl (SHELL, SHELL, "-c", command, NULL);
+    exit (EXIT_FAILURE);
+  @}
+  else if (pid < 0)
+    /* @r{The fork failed.  Report failure.}  */
+    status = -1;
+  else @{
+    /* @r{This is the parent process.  Wait for the child to complete.}  */
+    if (waitpid (pid, &status, 0) != pid)
+      status = -1;
+  @}
+  return status;
+@}
+@end example
+
+@comment Yes, this example has been tested.
+
+There are a couple of things you should pay attention to in this
+example.
+
+Remember that the first @code{argv} argument supplied to the program
+represents the name of the program being executed.  That is why, in the
+call to @code{execl}, @code{SHELL} is supplied once to name the program
+to execute and a second time to supply a value for @code{argv[0]}.  
+
+The @code{execl} call in the child process doesn't return if it is
+successful.  If it fails, you must do something to make the child
+process terminate.  Just returning a bad status code with @code{return}
+would leave two processes running the original program.  Instead, the
+right behavior is for the child process to report failure to its parent
+process.  Calling @code{exit} accomplishes this.