When I recently wrote about find's -exec option , I casually talked about 'the
exec()
family of system calls'. This is an odd phrasing and sort of an odd thing to say about Unix system calls, because they don't usually come in families. So let's list off the
exec()
family:
execv()execve()execvp()execvpe()
execl()execlp()execle()
(This is the list on Linux and OpenBSD; the FreeBSD list has
execvP()
but not
execvpe()
. The POSIX version leaves out
execvpe()
and adds
fexecve()
, which I don't quite put into this exec() family.)
One of these things is not like the others. Out of the entire list of at least six exec() functions, generally only
execve()
is a system call; the other
exec*()
functions are library functions layered on top of it. That there are convenient library functions layered on top of a system call (or a bunch of them) isn't odd; that's what all of stdio is, for example. What makes this situation feel odd is that the names are so close to each other. I have a decent memory for Unix libc function names and most of the time I probably couldn't pick the actual
exec()
system call out of a lineup like this.
(Right now it's very much in my memory that
execve()
is the underlying system call on most Unixes, of course.)
This multiplicity goes all the way back to V7 Unix, which documents all of
execl()
,
execv()
,
execle()
, and
execve()
in its
exec(2)
manpage. In V7, as is the case today, the underlying system call is
execve()
, although it had a different system call name. Even V6 had
execl()
and
execv()
in the V6
exec(2)
manpage .
(The V6 system call was just called
exec
and took only the program to be executed and
argv
. When V7 added the environment, it kept the V6
exec
call but added a new
exece
system call that took the environment (well,
envp
) as an additional argument.)
PS: Some Unixes have underlying system calls that are variants of each other, due to the slow growth and improvement in the system call API over time (for example, to add 64-bit variants of what used to be 32-bit calls). However, usually you only use and think about the most recent version of the system call; they aren't a family of variants the way the
exec()
family is.