Часть проблемы заключается в коде обработки труб - как вы и подозревали.
else if (strcmp(argArray[i], "|") == 0) {
int fds[2];
pipe(fds);
pid_t pid;
if ((pid = fork()) == 0) {
dup2(fds[PIPE_WRITE], 1);
close(fds[PIPE_READ]);
close(fds[PIPE_WRITE]);
char** argList;
memcpy(argList, argArray, i);
execvp(argArray[0], argArray);
}
if ((pid = fork()) == 0) {
dup2(fds[PIPE_READ], 0);
close(fds[PIPE_READ]);
close(fds[PIPE_WRITE]);
execvp(argArray[i+1], pA);
}
close(fds[PIPE_READ]);
close(fds[PIPE_WRITE]);
wait(NULL);
wait(NULL);
printf("|\n");
}
Первый execvp()
, вероятно, был предназначен для использования argList
, поскольку вы только что скопировали туда какой-то материал.Однако вы скопировали i
байт, а не i
символьные указатели, и вы не гарантировали, что канал будет зарезан и заменен нулевым указателем.
memcpy(argList, argArray, i * sizeof(char *));
argList[i] = 0;
execvp(argList[0], argList);
Обратите внимание, что это не подтвердило отсутствие переполнения буфера на argList
; Обратите внимание, что для argList
не выделено место;если вы используете его, вы должны выделить память перед выполнением memcpy()
.
В качестве альтернативы, а проще говоря, вы можете обойтись без копии.Поскольку вы находитесь в дочернем процессе, вы можете просто zap заменить argArray[i]
нулевым указателем, не затрагивая ни родительский, ни другой дочерний процесс:
argArray[i] = 0;
execvp(argArray[0], argArray);
Вы также можетеобратите внимание, что при втором вызове execvp()
используется переменная pA
, которую невозможно увидеть;это почти наверняка неправильно инициализировано.Как умеренно хорошее практическое правило, вы должны написать:
execvp(array[n], &array[n]);
Вышеприведенные вызовы не соответствуют этой схеме, но если вы будете следовать ей, вы не ошибетесь.
У вас также должны быть базовые отчеты об ошибках и exit(1)
(или, возможно, _exit(1)
или _Exit(1)
) после каждого execvp()
, чтобы дочерний процесс не продолжался, если не удалось выполнить.Нет успешного возврата из execvp()
, но execvp()
наверняка может вернуться.
Наконец, пока эти вызовы execvp()
, вероятно, должны быть там, где вы делаете рекурсивный вызов.Вам нужно разобраться с каналами, прежде чем пытаться справиться с другим перенаправлением ввода / вывода.Обратите внимание, что в стандартной оболочке вы можете сделать:
> output < input command -opts arg1 arg2
Это обычное использование, но на самом деле разрешено.
Одна хорошая вещь - вы убедились, что исходные файловые дескрипторы из pipe()
закрыты во всех трех процессах (родительский и оба дочерних).Это распространенная ошибка, которую вы избегали делать;молодец.