пользовательская оболочка, завершающаяся после чтения одной команды - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь написать пользовательскую оболочку на 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");

Программа все еще прервалась ине ждал, чтобы прочитать любой вход.Любая помощь могла бы быть полезна!

...