Search code examples
cunixexecvp

Trying to understand how execvp works


I found so many explanations and answers on execvp but it all seems confusing. execvp takes a command and sends it to kernel and then does something, execvp creates an image, execvp is system call, execvp ...etc. As a beginner with limited C language and Linux experience, only the following explanation seemed to click for me:

It's executing ls with 2 arguments: > and awd.txt. It is equivalent to running:

'ls' '>' 'awd.txt'

Here is the thread: What does execvp actually do?

However, I asked the following question to the person who answered and he did not reply, hence I'm asking separately in a desperate attempt to understand it.

So to execute ls -a in execvp, we should do execvp ("ls", args); where args is {"ls", "-a"}? or execvp (args[0], args)?

Can someone tell me if it's true: execvp takes the first argument from the array args and then sends that to kernel to follow the following array arguments? So execvp(args[0],args); would be that from args [] = {"ls", "-a"} array the args[0] takes ls, sends it to the kernel and then what?It goes looking for another args[0] and finds -a and sends that, and the kernel determines that these two makes a command like ls -a?


Solution

  • The prototype is:

      int execvp(const char *file, char *const argv[]);
    

    The first argument, file is the name of the program to execute. execvp will search your path and try to find a match. From the manpage:

    The execlp(), execvp(), and execvpe() functions duplicate the actions of the shell in searching for an executable file if the specified file name does not contain a slash (/) character.
    The file is sought in the colon-separated list of directory pathnames specified in the PATH environment variable.

    If/when execvp finds a match, that program will be loaded into memory and replace your current running program.

    The arguments the new program will see are the argv array specified in execvp. You are expected to have a null pointer as the last element, or your program may crash looking for a null.

    If you do:

    char *argv[]={"bar","bash","penguin",0};
    execvp("foo",argv);
    

    then when foo starts, it will have the same environment as your current program, its argc will be 3 and its argv will be the above list. Even though the program name is "foo", it's argv[0] while running will show up as "bar".

    You don't actually have to have argv[0] be the name of the new program. It is expected, but not required.

    Incidentally, with your example of

    ls > awd.txt
    

    If you did this on the command line, your shell would fork creating a new copy of itself. The child shell would open awd.txt and do a dup2() to put the child fd attached to awd.txt as 1. After some other housekeeping, the child shell would do something like.

    execvp("ls", {"ls", 0})
    

    so in the created "ls" argc==1 and argv[1] ==0. Traditionally , we would say that ls has 0 arguments.