Reputation: 77
Using the code below in the execl
variant, ls
works, but ls -l
does not work, but in my execvp
approach ls
and ls-l
works. The reason why I adopted the execl
approach is because the path of the binaries could differ whereas execvp
did not provide me that feature. Ideally I want execl
to also work on ls -l
, but right now it does not work on ls -l
. I tried reading the man pages but it did not help.
void child(int argc, char *argv[MAX_ARGS])
{
execvp(argv[0], argv);
}
void child(char *argv[], char* path)
{
execl(path, argv, NULL);
}
Upvotes: 2
Views: 26212
Reputation: 754420
With execl()
, you have to list the arguments one by one; it is only useful if you know exactly what you're going to execute ahead of time:
execl("/bin/ls", "ls", "-l", (char *)0);
execl("/bin/sh", "sh", "-c", "ls -l", (char *)0);
execl("/bin/ls", "pink elephants", "-l", (char *)0);
Etc.
If you don't know how many arguments you'll have to deal with, use execvp()
or one of the other members of the execv*()
family. Also note that you have to specify the path of the command; execvp()
does a search down $PATH
, but execl()
does not.
Also note that you get to choose the value passed as argv[0]
.
The reason why I adopted the
execl()
approach is because the path of the binaries could differ whereasexecvp()
did not provide me that feature.
I'm not sure what you mean here. With execvp()
, you can specify:
char *argv[] = { "ls", "-l", 0 };
execvp(argv[0], argv);
execv("/bin/ls", argv);
The execvp()
will search for ls
on $PATH
and execute the first program found that matches. The second will execute /bin/ls
without looking at $PATH
at all.
char *argv[] = { "/bin/ls", "-l", 0 };
execv(argv[0], argv);
execvp(argv[0], argv);
Either of these will work; the second won't use a PATH-based search because the executable name (argv[0]
) contains a slash.
What confuses me is that in
execvp(argv[0], argv);
why are we passing the entireargv
as the 2nd parameter? So supposeargv[0]
was"ls -l"
, why do we have to pass the entireargv
as the 2nd parameter?
Supposing argv[0]
contains "ls -l"
, you have a problem. Most systems do not have a file "/bin/ls -l
" or "/usr/bin/ls -l
" (where the blank is part of the name), but that's what you'd be seeking to execute.
The exec*()
functions are the low-level functions for executing processes. The first argument designates the program to be run (normally, a binary; sometimes a script with a shebang line such as #!/bin/sh
as the first line). In the case of execv()
or execvp()
or execve()
or execvpe()
, the second argument is the vector of arguments, just like the main()
function receives a vector of arguments (or argument vector, hence argv
). This is a null-terminated list of the arguments to the program. If you want to execute the ls
command with the option -l
, then you need to specify in the argv
the three(!) values "ls"
, "-l"
and a null pointer:
char argv[] = { "ls", "-l", 0 };
With the execl*()
functions, you specify the program to be run as the first argument, and this is then followed by the argument vector written out:
execl("/bin/ls", "ls", "-l", (char *)0);
If you have 10 arguments, you have to write out 10 arguments (plus the null pointer).
In the exec*()
functions, the names contain:
l
— list format argumentsv
— vector format argumentsp
— do PATH lookup on the program (if the given name does not contain a slash)e
— take a vector of environment variables tooThese combine to give:
execl()
execv()
execlp()
execle()
execvp()
execve()
It is occasionally a tad irksome that there isn't an execlpe()
and execvpe()
(but see the Linux extension execvpe(3)
). It is also traditional for the man 2 exec
pages to omit some of these from the synopsis but mention them in the body of the manual page — a tradition/legacy dating back to at least 7th Edition UNIX™ in 1979 (and perpetuated at least until RHEL 5 Linux and Mac OS X 10.7.5; the man 2 execl
page mentions execve()
but does not list it in the Synopsis section). The other exec*()
functions can all be built atop execve()
— that is the fundamental function in the set (and is listed as execve(2)
in the Linux manuals as a result).
Upvotes: 14