Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a C shell. execvp returns 'No such file' error. creating argv array on-the-fly with malloc

I am building a shell and am having some trouble with the system call 'execvp'. I saw some other questions on this topic but they were vague, and did not appear to be completely addressed (whoever asked the questions didn't provide much information and didn't get good answers).

Obviously I have my own command line and I'm reading user input from stdin like

mysh some/path $ ps -a 

and I am building an args array as a char ** and the array itself works (I think) since when I print out the values within my function it shows

args[0] = 'ps'
args[1] = '-a'
args[2] = '(null)'

So, I call fork and execvp(cmnd, args) within my process, where cmnd is "ps" and args is as above, and perror etc.

I get

'Error: no such file or directory.'  

Do I need to put in the $PATH variable? Am I doing something else whacky?

Here's my code for generating the args array:

char ** get_args(char * cmnd) {
int index = 0;
char **args = (char **)emalloc(sizeof(char *));
char * copy = (char *) emalloc(sizeof(char)*(strlen(cmnd)));
strncpy(copy,cmnd,strlen(cmnd));
char * tok = strtok(copy," ");
while(tok != NULL) {
    args[index] = (char *) emalloc(sizeof(char)*(strlen(tok)+1));
    strncpy(args[index],tok,strlen(tok)+1);
    index++;
    tok = strtok(NULL," ");
    args = (char**) erealloc(args,sizeof(char*)*(index+1));
}
args[index] = NULL;
return args;
}

(emalloc and erealloc are just malloc and realloc with error checking built in)

So then I do this:

void exec_cmnd(char*cmnd, char**args) {
pid_t pid;
if((pid=fork())==0) {
    execvp(cmnd, args);
    perror("Error");
    free(args);
    free(cmnd);
    exit(1);
}
else {
    int ReturnCode;
    while(pid!=wait(&ReturnCode)) {
        ;
    }
}
}

And like I said above, when execvp is called inside my process it fails when I supply any arguments whatsoever but works without them (i.e. when argv == {'ps', NULL} )

If you need more information don't hesitate to ask. I need to solve this.

like image 755
matchdav Avatar asked May 22 '12 00:05

matchdav


2 Answers

It think you passed whole command line in first argument to execvp

you have to separate first token(command name) from cmnd to pass as first argument of execvp

You can call it as

execvp(args[0], args);

like image 124
ravi Avatar answered Oct 22 '22 11:10

ravi


Note in passing that you have a non-terminated string as a result of:

char * copy = (char *) emalloc(sizeof(char)*(strlen(cmnd)));
strncpy(copy, cmnd, strlen(cmnd));

strncpy() does not null terminate for you when you use it like that. You also need to allocate one more byte for the null. Consider using strdup() if it is available to you. If not, consider writing it. This misallocation is a problem even with the error checking versions of emalloc() and erealloc().

like image 44
Jonathan Leffler Avatar answered Oct 22 '22 10:10

Jonathan Leffler