Chapter 27.2 — exec() Library Functions & PATH

Chapter 27.2 — exec() Library Functions & PATH
execl, execv, execlp, execvp, execle — All Variants Explained · EmbeddedPathashala
📌 Topic
exec() Family
🧠 Level
Beginner
💻 Examples
3 Programs
❓ Q&A
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
⚠️ Security Warning: Never put . (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

Q1. What is the difference between execv() and execvp()?
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.
Q2. Why must you cast NULL as (char *)NULL in execl/execlp/execle?
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.
Q3. Which exec functions use the PATH environment variable?
Answer: Only execlp() and execvp() — the ones with ‘p’ in the name. All others require a full or relative pathname to the executable.
Q4. If PATH = /usr/bin:/bin and you call execlp(“myapp”, …), which directory is checked first?
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).
Q5. What happens in execlp() if the filename contains a ‘/’ character?
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.
Q6. Which exec() functions allow specifying a custom environment?
Answer: Only execve() and execle() — the ones ending in ‘e’. All others inherit the environment from the calling process (via the global environ variable).
Q7. A shell like bash needs to run user commands like “ls -la”. Which exec function is most suitable and why?
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.
Q8. Are execlp() and execvp() safe to use in setUID programs?
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

→ Part 3: Args, Env & fexecve() 🏠 All Tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *