Я пытаюсь написать пользовательскую оболочку на C, которая поддерживает несколько каналов, используя fork
, dup2
и pipe
.Мой подход для c1 | c2 | c3
, создать матрицу 2 x 2 для хранения двух каналов, последовательно обработать три дочерних процесса, вызвать dup2
, чтобы дублировать stdin
и stdout
в правильный канал, затем вызвать exec
.
Оболочка отлично работает для следующих команд: "echo foo"
, "ls | grep something | wc"
.Но по какой-то причине, когда я выполняю строку, содержащую только один канал, как, например, "ls | grep something"
, оболочка выполняет эту команду, как и ожидалось, но завершается, не дожидаясь чтения дополнительных строк.Я потратил часы, пытаясь понять, почему он существует, если ему дается линия с одной трубой, но он отлично работает с более чем одной трубой, но мне не повезло.
Вот код, который создает дочерние процессы и запускает команды:
int main()
{
char input_line[1000];
size_t size;
size_t chars;
while(fgets(input_line, sizeof(input_line), stdin))
{
input_line[strcspn(input_line, "\n")] = 0;
struct PARSE_INFO* parse_info = initialize_parseInfo();
Parse(input_line, parse_info);
int num_commands = parse_info->num_commands;
int num_pipes = parse_info->num_pipes;
int pipes[num_pipes][2];
bool piping = num_pipes > 0;
// Piping the pipes
for(int i = 0; i < num_pipes; i++)
pipe(pipes[i]);
int i;
for(i = 0; i < num_commands; i++)
{
struct COMMAND* command = (parse_info->commands)[i];
int num_args = command->argnum;
char* newargv[num_args + 2];
create_argv(command, newargv, "/usr/bin");
int pid = fork();
if(pid == 0) // Child
{
char* newenviron[] = { NULL };
if(piping)
{
if(i < num_commands - 1) // Not at end of pipe so write to next pipe
{
dup2(pipes[i][1], STDOUT_FILENO);
}
if(i > 0) // Not at beginning of pipe so read from previous pipe
{
dup2(pipes[i - 1][0], STDIN_FILENO);
close(pipes[i -1][0]);
}
}
execve(newargv[0], newargv, newenviron);
perror("execve");
}
else // Parent
{
int status = 0;
wait(&status);
close(pipes[i][1]);
}
}
}
}
Я протестировал вызываемые здесь функции независимо друг от друга, и они, кажется, работают нормально, поэтому я решил не включать их вуменьшить беспорядок.Я подозреваю, что неправильно закрываю трубы.Меня озадачивает то, что, если я правильно понимаю, вызов dup2
в дочернем процессе должен только изменять дескрипторы файлов в этом процессе и не влиять на родительский процесс, я не уверен, почему он вызывает закрытие stdin
вродительский процесс.
Во время отладки я попытался прочитать некоторые входные данные из stdin
в конце цикла while, добавив этот код после блока else:
char someinput[256];
fgets(someinput, sizeof(someinput), stdin);
printf("End of loop input: %s\n");
Программа все еще прервалась ине ждал, чтобы прочитать любой вход.Я попытался напечатать someinput, и он содержал команду, введенную из stdin в начале цикла, используя первый вызов fgets.Любая помощь могла бы быть полезна!