It is said that fork
system call creates a clone of the calling process, and then (usually) the child process issues execve
system call to change its i
Other variations of exec abound:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
Each step is relatively simple.
In Unix, your process has two parts -- a read-only memory area with the application code ("text") and the read-write memory area ("data").
A fork clones the read-write area, leaving the text page alone. You now have two processes running the same code. They differ by a register value -- the return value from fork -- which separates parent from child.
An exec replaces the text page, leaving the data page alone. There are many forms of exec, depending on how much environment information you're passing to it. See http://linux.die.net/man/3/exec for an additional list of variants.
What does
execve
stand for?
The 6 variations of the exec functions in C are are exec{l,v}{,e,p}
. See function prototypes below for details.
Command-line arguments
v
- Command-line arguments are passed to the function as an array (vector) of pointers.l
- Command-line arguments are passed individually (a list) to the function.Environment variables (optional)
e
- An array of pointers to environment variables is explicitly passed to the new process imageLocate the file to be executed (optional)
p
- Uses the PATH environment variable to find the file named in the file argument to be executedint execl (char const *path, char const *arg0, ...);
int execle(char const *path, char const *arg0, ..., char const *envp[]);
int execlp(char const *file, char const *arg0, ...);
int execv (char const *path, char const *argv[]);
int execve(char const *path, char const *argv[], char const *envp[]);
int execvp(char const *file, char const *argv[]);
Source
The reason for the two-step is flexibility. Between the two steps you can modify the context of the child process that the newly exec'ed program will inherit.
Some things you may want to change are:
If you did not split up fork and exec and instead had a single spawn-like system call, it would need to take arguments for each of these process attributes if you wanted them set differently in a child process. For example, see the argument list to CreateProcess in the Windows API.
With fork/exec, you change whatever inheritable process attributes you want to in the child before you exec the new program.
Setting up file descriptors is one of the more common things to change in a child's process context. If you want to capture the output of a program, you will typically create a pipe in the parent with the pipe(2) system call, and after fork(2)ing, you will close the write end in the parent process and close the read end in the child process before calling execve(2). (You'll also use dup(2) to set the child end of the pipe to be file descriptor 1 (stdout)). This would either be impossible or restrictive in a single system call.
The "exec" family of functions replace the current process image(from where it is called) with a new process image, so the calling image is replaced by the new process image. For eg. if you were to run the 'ls' command from a shell(/bin/sh or /bin/csh) then the shell would fork to a new process which would then execute ls. Once the ls command exits it returns control to the parent process, which in this example is the shell.
If there were no fork functionality then the shell would be replaced by the 'ls' process which upon exit would leave you with an inaccessible terminal since the shell's image in memory was replaced upon the exec call to ls.
For variations in the 'exec' family look at 0x6adb015's answer.