Search code examples
cshellexecvpdouble-pointer

Double pointer as argument to execvp()


I am trying to execute execvp() using a custom **tokens double pointer as input, instead of argv[] on a "create a custom shell" assignment, like this:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

int main(){
    char *token;
    char **tokens = malloc(sizeof(char*)*512); //512 is for the maximum input-command length
    char *command=malloc(sizeof(char)*512);
    int i = 0;
    pid_t child_pid;
    int status;
    //***********take input from user*************************************
    fgets(command,512,stdin);

    //***********parse input*********************************************
    token = strtok(command," \t");

    while( token != NULL ) {

        tokens[i]=token;
        i ++;
        token = strtok(NULL, " \t");

    }
    child_pid = fork();

    if(child_pid == 0) {
        /* This is done by the child process. */
        execvp(tokens[0], tokens);
    } else {
        waitpid(child_pid, &status, WUNTRACED);
    }
}

The problem is definately on this line:

execvp(tokens[0], tokens);

and I just can't understand why it can't be executed and print to my stdout. I have tried this:

execvp("ls", tokens);

and it works just fine. And this:

printf("%s\n", tokens[0]);

with the output being (according to the test input: ls ):

ls


Solution

  • You have several problems in your code, including:

    1. The array of argument pointers passed to execvp() must be terminated by a null pointer. You do not ensure that.

    2. The string obtained via fgets will include all characters up to and including the line's newline, if the buffer is large enough to accommodate it. You do not include the newline among your token delimiter characters, so for a one-word command ls, the command passed to execvp() is equivalent to "ls\n", not "ls". It is unlikely (but not impossible) that ls\n is an available command on your machine.

    3. You do not check the return value of execvp(), or of any of your other functions, nor do you handle any errors. execvp() is special in that it returns only if there is an error, but you would have saved yourself some confusion if you had handled that case by emitting an error message.

    After I correct the first two of those, your program successfully runs an "ls" command for me.