exec() Family
Beginner
3 Programs
8 Questions
Why Are There So Many exec() Functions?
All exec functions do the same thing: replace the current process with a new program. But they differ in how you pass the program name and how you pass arguments. Think of them as different remote controls for the same TV — all change the channel, but buttons are arranged differently.
All these functions are just wrappers around the one true system call: execve().
Decoding the Name: What Each Letter Means
| Letter in Name | Meaning | What it controls | Example |
|---|---|---|---|
| v | Vector | Arguments passed as array (argv[]) | execve, execvp |
| l | List | Arguments passed as individual strings (varargs) | execle, execlp, execl |
| p | PATH | Search PATH variable for the program | execlp, execvp |
| e | Environment | Caller provides custom environment (envp[]) | execve, execle |
All 6 exec() Functions — Side by Side
| Function | Program Spec | Args Style | Environment | Uses PATH? |
|---|---|---|---|---|
execve(path, argv, envp) |
Full pathname | Array | envp argument | No |
execle(path, arg..., envp) |
Full pathname | List (varargs) | envp argument | No |
execlp(file, arg...) |
Filename only | List (varargs) | Inherits caller’s environ | Yes |
execvp(file, argv) |
Filename only | Array | Inherits caller’s environ | Yes |
execv(path, argv) |
Full pathname | Array | Inherits caller’s environ | No |
execl(path, arg...) |
Full pathname | List (varargs) | Inherits caller’s environ | No |
27.2.1 How PATH Search Works (execlp / execvp)
When you use execlp() or execvp(), you only give a filename like "ls" — no full path needed. The function searches directories listed in the PATH environment variable, one by one, until it finds the executable.
| PATH = /home/ravi/bin:/usr/local/bin:/usr/bin:/bin |
|---|
| Step 1: Look for “ls” in /home/ravi/bin → Not found |
| Step 2: Look for “ls” in /usr/local/bin → Not found |
| Step 3: Look for “ls” in /usr/bin → Not found |
| Step 4: Look for “ls” in /bin → FOUND! → exec /bin/ls |
. (current directory) at the start of PATH in root or setUID programs. A malicious user could place a fake ls in the current directory and trick the program into running it!Example 1: execlp() — Search PATH for Program
Instead of writing /bin/echo, we just say "echo" and let execlp() find it via PATH.
/* example1_execlp.c
* gcc -o ex1 example1_execlp.c && ./ex1
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(void)
{
printf("Using execlp to run 'echo'...\n");
/* execlp: just give filename, PATH is searched automatically */
/* Arguments: filename, arg0(program name), arg1, ..., NULL */
execlp("echo", /* filename to search in PATH */
"echo", /* argv[0] — program name */
"Hello from",
"execlp!",
(char *)NULL); /* MUST end with NULL — cast required */
/* Only reached on error */
fprintf(stderr, "execlp failed: %s\n", strerror(errno));
return 1;
}
/* -----------------------------------------------
* Try breaking it: remove /bin from PATH
* $ PATH=/tmp ./ex1
* → execlp fails: No such file or directory
* ----------------------------------------------- */
Example 2: execvp() — Array Args + PATH Search
Same as execlp but arguments are in an array. Useful when you build args dynamically at runtime.
/* example2_execvp.c
* gcc -o ex2 example2_execvp.c && ./ex2
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
/* Build argument array dynamically */
char *cmd_args[] = {
"grep", /* argv[0]: program name */
"-r", /* recursive */
"--include=*.c",/* only .c files */
"main", /* search for "main" */
"/usr/src", /* search in this dir */
NULL /* terminator */
};
printf("Running: grep -r --include=*.c main /usr/src\n");
printf("Using execvp (PATH search, array args)\n\n");
/* execvp: filename + array, PATH searched for "grep" */
execvp("grep", cmd_args);
fprintf(stderr, "execvp failed: %s\n", strerror(errno));
return 1;
}
/* -----------------------------------------------
* execvp is perfect when arg count varies:
*
* void run_cmd(char *name, char **args) {
* execvp(name, args);
* perror("exec");
* }
* ----------------------------------------------- */
Example 3: execle() — List Args + Custom Environment
Use execle() when you want to pass a specific environment AND use list-style arguments.
/* example3_execle.c
* gcc -o ex3 example3_execle.c && ./ex3
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(void)
{
/* Custom environment to pass to printenv */
char *my_env[] = {
"DEVICE=nRF52840",
"STACK=BlueZ",
"COMPANY=Thundersoft",
NULL
};
printf("Launching printenv with custom environment...\n\n");
/* execle: full pathname + list args + custom envp at END */
/* Note: NULL before envp is crucial! */
execle("/usr/bin/printenv", /* full path (no PATH search) */
"printenv", /* argv[0] */
"DEVICE", /* print only DEVICE variable */
(char *)NULL, /* NULL terminates arg list */
my_env); /* envp comes AFTER the NULL */
fprintf(stderr, "execle failed: %s\n", strerror(errno));
return 1;
}
/* Expected output:
* Launching printenv with custom environment...
*
* nRF52840
*
* Only our custom env is visible to the child — not the
* caller's environment!
*/
Quick Decision Guide: Which exec() to Use?
| Situation | Use This | Why |
|---|---|---|
| Know full path, fixed args, custom env | execve() |
Most direct, lowest level |
| Know full path, fixed args, inherit env | execl() |
Simple, no env needed |
| Just have command name, inherit env | execlp() |
PATH search, list args |
| Command name, dynamic arg array | execvp() |
PATH + array = most flexible for shells |
| Full path, list args, custom env | execle() |
Control env, no PATH |
| Full path, dynamic array, inherit env | execv() |
No PATH, array args |
❓ Interview Questions — exec() Library Functions
Answer: execv() requires a full pathname (e.g., /bin/ls), while execvp() accepts just a filename (e.g., “ls”) and searches the PATH environment variable to find the executable. Both take arguments as a NULL-terminated array.
Answer: These functions use variadic arguments (va_list). On some architectures, a plain NULL may be treated as an integer 0 rather than a pointer. Casting ensures the compiler passes a null pointer with the correct size, preventing stack corruption.
Answer: Only execlp() and execvp() — the ones with ‘p’ in the name. All others require a full or relative pathname to the executable.
Answer: /usr/bin is checked first. The directories in PATH are searched left to right. If myapp is in /bin, it searches /usr/bin first (not found), then /bin (found and execed).
Answer: PATH is ignored entirely. The filename is treated as a relative or absolute pathname and used directly. For example, execlp(“./myapp”, …) looks only in the current directory, not in PATH directories.
Answer: Only execve() and execle() — the ones ending in ‘e’. All others inherit the environment from the calling process (via the global environ variable).
Answer: execvp() is ideal. The shell receives the command as tokens (dynamic array, not fixed count), and uses PATH to find the executable. execvp() takes an argv array and searches PATH — matching exactly what a shell needs.
Answer: No — they should be avoided or used with great caution. A malicious user could modify PATH to point to a fake executable. In secure code, always use execve() or execv() with a full hardcoded pathname, or ensure PATH is set to a known-safe value before calling the ‘p’ variants.
Next: Argument Lists, Environment & fexecve()
Sections 27.2.2, 27.2.3, 27.2.4 — more exec() details
