Возникли проблемы с execvp () - PullRequest
       20

Возникли проблемы с execvp ()

1 голос
/ 30 сентября 2011

Итак, вот фрагмент моего кода, который доставляет мне проблемы:

void childProcessHandler(string command){


int argCounter = 0;
for(int i=0; i!=command.size(); i++)
    argCounter+=( command.at(i) == ' ');

char * temp, *token;
char *childArgs[argCounter];

argCounter = 1;

temp = new char [command.size()+1];
strcpy (temp, command.c_str());

token = strtok (temp," ");
childArgs[0] = token;

while (token!=NULL)
{
    token = strtok(NULL," ");
    childArgs[argCounter] = token;
    argCounter++;
}

//delete[] temp; //Should remove token as well?

execvp(childArgs[0], childArgs);

cout<<"PROBLEM!"<<endl;
exit(-1);

}

В методе main () мой код попадает в точку, где он forks () (затем родительский процесс ожидает завершения дочернего процесса.) Затем дочерний процесс (ID процесса == 0 yes?) Вызывает метод childProcessHandler с пользовательским вводом (команда для запуска + аргументы) в качестве аргумента. Затем я токенизирую пользовательский ввод и вызываю execvp.

Все компилируется и выполняется. Строка после execvp никогда не достигается, потому что execvp возвращается только в случае ошибки yes?

Проект состоит в том, чтобы смоделировать терминал Unix, однако, когда я даю ему команду «дата», ничего не печатается, как должно ... Дочерний процесс завершается, и родительский процесс возобновляется очень хорошо, но ничего не отправляется обратно в окно терминала. ...

Что я делаю не так?

(Также нам «рекомендовали» использовать strtok для токенизации, но если у кого-то есть что-нибудь попроще, я открыт для мнений.)

СПАСИБО!

EDIT

Приведенный выше код работает, например, если я наберу «date» вместо «date». Я думаю, что может быть что-то подозрительное в «tokenizer», не помещающем нулевой символ в конец массива childArgs []. Я поиграюсь с этим и спасибо за быстрые ответы!

(Ninja edit, также закомментировано delete [] temp)

Ответы [ 2 ]

2 голосов
/ 30 сентября 2011

Вы смешиваете std :: string и char / char *.Хорошо, но вы должны быть осторожны, они ведут себя по-разному.

В частности, эта строка:

temp = new char [command.size()+1];

Создает фактический массив для хранения строки.

token = strtok (temp," ");

Это делает токен (который является просто указателем), указывающий на место внутри temp.strtok () изменяет входную строку, чтобы сделать временную строку внутри строки (звучит безумно, я знаю).

Вам нужно скопировать строку, которую strtok () дает вам в постоянный дом.Либо используйте std :: string, чтобы сэкономить время и код, либо используйте способ char * и выделите новую строку самостоятельно.Например, вместо:

childArgs[0] = token;

вам нужно:

   childArgs[0] = new char[strlen(token)+1];
   strcpy(childArgs[0], token);

То же самое относится к токенам, хранящимся в массиве во время цикла по аргументам команды.

1 голос
/ 30 сентября 2011

Ваш вектор указателей childargs указывает на байты, выделенные в блоке памяти "temp". Когда вы освобождаете temp, вы удаляете память, на которую указывают указатели childargs, что может повредить некоторые значения в вашем векторе.

Удалите вызов delete [], чтобы прекратить освобождение памяти, на которую указывают указатели childargs. У вас не будет утечки памяти. Как только вы вызовете exec_ (), ваш образ процесса в любом случае будет заменен. Единственное, что переживает вызов exec _ () (по большей части), это ваши файловые дескрипторы.

В качестве теста попробуйте что-нибудь более простое: после вызова функции fork () в дочернем элементе просто вызовите exec с путем к дате. Сделайте это, прежде чем возиться с вектором списка параметров.

В качестве еще одного теста удалите ваш вызов exec и распечатайте весь вектор указателей, чтобы убедиться, что ваш токенизация работает так, как вы думаете. Помните, что ваша последняя запись должна быть NULL, чтобы вы знали, где находится конец вектора.

...