markfiel
markfiel

Reputation: 77

Commands like "ls -l" not executing in execl, whereas in execvp it works

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

Answers (1)

Jonathan Leffler
Jonathan Leffler

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 whereas execvp() 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 entire argv as the 2nd parameter? So suppose argv[0] was "ls -l", why do we have to pass the entire argv 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 arguments
  • v — vector format arguments
  • p — do PATH lookup on the program (if the given name does not contain a slash)
  • e — take a vector of environment variables too

These 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

Related Questions