I am wondering why the below produce different results:

char *const temp[] = {"cal","4","2019",NULL};


    execvp(temp[0],temp);
    perror("Return from execlp not expected");
    exit(EXIT_FAILURE);

when executed will produce a calendar with ONLY the month april

char *const temp[] = {"cal"};
char *const temp2[] ={"4","2019",NULL};

    execvp(temp[0],temp2);
    perror("Return from execlp not expected");
    exit(EXIT_FAILURE);

when executed will produce a calendar with ALL the months

I want to get the second form to work correctly, as for my problem i have 2 arrays, one to store all my commands, and the other to store all my arguments for the command. eg

array1[0] = command
array2[0] = arg1 ar2 arg3  // the arguments for the command in array1[0]

And within a loop until i hit the end of my command array use fork and excute these commands in a child class so that i can go through and execute all the commands in the array.

2 Answers

2
kiran Biradar On

As per execvp man

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

The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a NULL pointer

0
ybungalobill On

argv[0] is always assumed to be a name of the program, even if its not used by the execvp like in your case. The cal program itself starts interpreting the command line from argv[1]. (See @kiran Biradar answer.)

You'll need to copy the (pointers to the) arguments into a bigger array, and set a dummy argument for argv[0]. Here's some short code to do that:

char **combine_args(char *arg0, char **tail) {
    size_t n = 0;
    while(tail[n]) ++n;
    char **ret = malloc(sizeof(char*)*(n+2));
    ret[0] = arg0;
    memcpy(ret + 1, tail, sizeof(char*)*n);
    ret[n+1] = 0;
    return ret;
}

Next you can use it like this:

char *const temp[] = {"cal"};
char *const temp2[] ={"4","2019",NULL};

char **argv = combine_args(temp[0], temp2);

execvp(argv[0], argv);
perror("Return from execlp not expected");
exit(EXIT_FAILURE);

If you do it in a loop and you can change the temp2 array, then you can do it like this, without any allocations:

char *const temp[] = {"cal", "cal2", "cal3", NULL};
char *temp2[] ={NULL, "4","2019",NULL};

for(int i = 0; temp[i]; ++i)
{
    // ... fork here ...
    {
        temp2[0] = temp[i];
        execvp(temp2[0], temp2);
        perror("Return from execlp not expected");
        exit(EXIT_FAILURE);
    }
}