Создание оболочки C. execvp возвращает ошибку «Нет такого файла». создание массива argv на лету с помощью malloc

Я создаю оболочку, и у меня возникли проблемы с системным вызовом «execvp». Я видел несколько других вопросов по этой теме, но они были расплывчатыми и, казалось, не были полностью рассмотрены (кто бы ни задавал вопросы, он не предоставил много информации и не получил хороших ответов).

Очевидно, у меня есть собственная командная строка, и я читаю пользовательский ввод со стандартного ввода, например

mysh some/path $ ps -a 

и я создаю массив args как char **, и сам массив работает (я думаю), поскольку, когда я распечатываю значения в своей функции, он показывает

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

Итак, я вызываю fork и execvp(cmnd, args) внутри своего процесса, где cmnd — это «ps», а args — как указано выше, а perror и т. д.

я получил

'Error: no such file or directory.'  

Нужно ли указывать переменную $PATH? Я делаю что-то еще дурацкое?

Вот мой код для создания массива args:

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 и errealloc — это просто malloc и realloc со встроенной проверкой ошибок)

Итак, я делаю это:

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)) {
        ;
    }
}
}

И, как я сказал выше, когда execvp вызывается внутри моего процесса, он терпит неудачу, когда я предоставляю какие-либо аргументы, но работает без них (т.е. когда argv == {'ps', NULL} )

Если вам нужна дополнительная информация, не стесняйтесь спрашивать. Мне нужно решить это.


person matchdav    schedule 22.05.2012    source источник


Ответы (2)


Он думает, что вы передали всю командную строку в первом аргументе execvp

вам нужно отделить первый токен (имя команды) от cmnd, чтобы передать его в качестве первого аргумента execvp

Вы можете назвать это как

execvp(args[0], args);

person ravi    schedule 22.05.2012
comment
Это точно. Если вы хотите выполнить ps -a, вам нужно вызвать execvp("ps", {"ps", "-a", NULL}). - person caf; 22.05.2012

Попутно обратите внимание, что у вас есть незавершенная строка в результате:

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

strncpy() не завершается для вас нулем, когда вы используете его таким образом. Вам также нужно выделить еще один байт для нуля. Рассмотрите возможность использования strdup(), если он вам доступен. Если нет, подумайте над тем, чтобы написать это. Это неправильное распределение является проблемой даже для версий emalloc() и erealloc() с проверкой ошибок.

person Jonathan Leffler    schedule 22.05.2012
comment
Или в соответствии с темой использовать (или внедрить и использовать) estrdup(). - person Michael Burr; 22.05.2012
comment
Хорошо (почти): измените его на size_t len и потеряете приведение, поскольку аргумент для malloc() и strncpy() также является size_t. Обратите внимание, что вы должны проверять copy перед копированием на него, а не после! И аргумент должен быть char const *str, так как вы не собираетесь его изменять. - person Jonathan Leffler; 22.05.2012