Question

I'm writing a shell in C, and I'm having trouble understanding the filepath parameter needed for execvp(filepath,argv).

If the user typed wanted to run ls -a in their current directory ... let's say /home/user1 ... what would be the filepath and argv for running ls in said directory?

Would the filepath be the directory for where the command will be executed from /home/user1 or would it be the command's location /bin/ls?

Was it helpful?

Solution 2

To run /bin/ls -a in the current directory you would need:

The same as argv passed into main() when a C program starts except NULL terminated, and path is the same as argv[0].

char* argv[] = { "/bin/ls", "-a", NULL };
execvp(argv[0], argv);

OTHER TIPS

The filepath argument to execvp() can take either of two forms — it contains a slash or it does not contain a slash.

With slash

The filepath argument specifies the pathname of the executable, either an absolute name (starts with slash) or a relative name (does not start with slash, but does contain a slash). The execvp() function makes no changes to the argument, and the program is executed (or not) assuming that the file named exists and is executable.

Without slash

The filepath arguments specifies a 'simple' name such as ls. The excevp() function then seeks to execute a program with the name ls found in one of the directories listed in the $PATH environment variable. The p in execvp() is for 'path', as in path lookup.

Applying the theory

If the user types ls -a to a shell, the normal way to execute that would be to create an array of character pointers equivalent to:

char *argv[] = { "ls", "-a", 0 };

execvp(argv[0], argv);

The execvp() will now do the path-based analysis and attempt to execute ls from one of the directories listed in $PATH.

If the user types /bin/ls -a to a shell, then the normal way to execute that would be to create an array of character pointers equivalent to:

char *argv[] = { "/bin/ls", "-a", 0 };

execvp(argv[0], argv);

The execvp() will now execute the absolute pathname specified, because that's what the user requested (as opposed to, say, /usr/bin/ls or /usr/local/bin/ls).

Note that the processing is actually the same — you split the command line into words; each word becomes an element of an array of character pointers that is terminated with a null pointer, and you pass the first word to execvp() as the 'filepath' argument, and the whole array as the second argument.

Obviously, a shell can cache the locations of the actual executables, and many shells do, so that execvp() doesn't have to do work trying to find the program (and the shells don't call execvp() but typically call execv() with the absolute pathname of the executable. But that isn't necessary; it is an optimization.

Note, too, that there is nothing to stop you doing:

char *argv[] = { "/honky/tonk/toys", "-a", 0 };
execvp("ls", argv);

Now argv[0] should be "/honky/tonk/toys" and not ls, for all it is the ls executable that is run. What you find in /proc depends on you having /proc on your system (Mac OS X does not support it, for example), but the symlink to the binary should be a link to /bin/ls. On Linux, you're apt to find that ps reports the binary name (ls), even though /proc/PID/cmdline contains the original arguments (so argv[0] is /honky/tonk/toys). Whether this is good or not depends on your viewpoint, but all the world is not Linux.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top