Search code examples
cexecvp

No such file or directory error using execvp


I wrote this program in order to use the execvp command and this is my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, const char * argv[]) {

    char **cmd;
    int i;

    if (argc == 1){

        fprintf(stdout, "No command inserted!\n");
        exit(EXIT_SUCCESS);

    }

    cmd = (char **) malloc( (argc + 1) * sizeof(char *));
    cmd[0] = (char *) malloc( strlen(argv[1] + 1 ) * sizeof(char) );
    strcpy(cmd[i], argv[i+1]);

    if (argc > 2){

        for (i = 1 ; i < argc - 1  ; i++ ){

            cmd[i] = (char *) malloc( strlen(argv[i+1] + 1 ) * sizeof(char) );
            strcpy(cmd[i], argv[i+1]);

        }

        cmd[argc] = NULL;
        execvp(cmd[0], cmd);

        fprintf(stderr, "Failed Execution or not existing command!!\n");
        exit(EXIT_FAILURE);

    }

    cmd[1] = NULL;

    execvp(cmd[0], cmd);

    fprintf(stderr, "Failed Execution or not existing command!!\n");
    exit(EXIT_FAILURE);

    return 0;
}

I run this program on the terminal using these commands ./a.out ls ./a.out who ./a.out ls -l ./a.out mkdir newdir

The first two worked fine as well as the other commands without arguments. With the last two I get a No such File or Directory error in the terminal, but actually the mkdir command creates the directory newdir... Can someone help me


Solution

  • you're setting cmd[argc] = NULL; but that's too much by 1 (argc is the count of args with your command included). So cmd[argc - 1] isn't initialized (note that the loop above stops at argc - 2

    You need to set cmd[argc - 1] to NULL instead or else another trash argument is passed to execvp, which explains for instance that mkdir works for the first argument, but fails when processing the garbage arg. All commands receive a garbage argument because of this shift.

    You need an array of pointers of size argc, not argc + 1 since the a.out command isn't considered.

    Also, as noted in comments, you're using i not initialized at first, which work (since your mkdir command works) but out of luck (undefined behaviour)

    A much simpler way to do it would be to copy the array of argv pointers (ignoring the first one which is your comment) without duplicating the memory for the string contents (since you're not modifying them).

       cmd = malloc( argc * sizeof(char *)); // argc because we need 1 slot for NULL termination
       for (i=0;i<argc-1;i++)
       {
         cmd[i] = argv[i+1];
       }
       cmd[i] = NULL;  // i is argc-1 now