Execing Processes in C

Our example demonstrates how to replace the current process with a new one using the exec family of functions in C. This is similar to the classic exec function in Unix-like operating systems.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    // For our example we'll exec 'ls'. We'll use the full path to the binary.
    char *binary = "/bin/ls";

    // exec requires arguments in array form (as opposed to one big string).
    // We'll give 'ls' a few common arguments. Note that the first argument
    // should be the program name.
    char *args[] = {"ls", "-a", "-l", "-h", NULL};

    // exec also needs the environment variables.
    // Here we just provide the current environment.
    extern char **environ;

    // Here's the actual execve call. If this call is successful,
    // the execution of our process will end here and be replaced
    // by the '/bin/ls -a -l -h' process. If there is an error,
    // execve will return -1.
    if (execve(binary, args, environ) == -1) {
        perror("execve");
        exit(EXIT_FAILURE);
    }

    // This line will only be reached if execve fails
    return 0;
}

When we compile and run our program, it is replaced by ls:

$ gcc exec_process.c -o exec_process
$ ./exec_process
total 16K
drwxr-xr-x  2 user user 4.0K Jun 15 10:00 .
drwxr-xr-x 10 user user 4.0K Jun 15 09:59 ..
-rwxr-xr-x  1 user user 8.3K Jun 15 10:00 exec_process
-rw-r--r--  1 user user  721 Jun 15 10:00 exec_process.c

Note that C, being closer to the operating system, provides direct access to system calls like fork and exec. The fork function, which is not available in some higher-level languages, is often used in conjunction with exec to create new processes in Unix-like systems.

In this example, we’ve used execve, which is one of the exec family of functions. It replaces the current process image with a new process image, which in this case is the ls command. The program’s execution ends at the execve call if it’s successful, as the entire process is replaced.

Remember that error handling is crucial when working with these low-level system functions. Always check the return values and use perror or similar functions to print informative error messages.