execvp(3)

C library function

Replaces the program in the current process with a command looked up in PATH, its arguments passed in an array terminated by NULL.

Synopsis
#include <unistd.h>
int execvp(const char *file, char *const argv[]);

Description

execvp loads another program into the current process and runs it from the start. The code, data and stack of the old program are replaced; the PID does not change, and open file descriptors stay open (except those marked close-on-exec). You almost always call it in a child created by fork, so that the parent carries on.

The p in the name means that file is looked up in the directories listed in the PATH variable, the way the shell does it, unless it contains a /: then it is used as is. The v means the arguments come in an array (a vector). By convention, argv[0] is the command name, and the last element must be NULL. The new program receives the environment of the current process.

The other members of the family change one letter: execlp takes the arguments one by one, ending with (char *) NULL, execv does not search PATH, and the underlying system call, execve, wants an exact path and an explicit environment.

Return value

On success, execvp never returns: there is no calling program left to receive a value. If it does return, it failed, the value is -1 and errno gives the cause: ENOENT when the command cannot be found, EACCES when the file is not executable.

Pitfalls

  • Everything after execvp runs only if it fails. Put a perror and an exit there, or the child goes on running the parent's code.

  • An argument array without a final NULL makes execvp read past the end of the array.

  • The printf buffer is lost in the replacement. Flush it with fflush(stdout) before the call.

  • No such file or directory can also come from a script whose interpreter does not exist, such as a #!/bin/sh line ending in a Windows carriage return.

Example

launch.c
#include <stdio.h>#include <unistd.h>
int main(int argc, char **argv){    if (argc < 2) {        fprintf(stderr, "usage: %s command [arguments]\n", argv[0]);        return 2;    }    execvp(argv[1], argv + 1);    perror(argv[1]);    return 127;}
Terminal
$ gcc -Wall -Wextra launch.c -o launch$ ./launch echo hello from execvphello from execvp$ ./launch no-such-commandno-such-command: No such file or directory$ echo $?127

argv + 1 is already an array in the right format: it starts at the command name and ends with the NULL that the C standard guarantees at argv[argc].

C

pipe_chain

Write pipe_chain, which starts each command of a list in its own child with execvp and feeds the output of each one to the next.

Open the exercise

Now write it yourself.