Является ли dup2 правильным способом для имитации поведения последовательности команд в терминале Linux? - PullRequest
3 голосов
/ 31 марта 2019

Я пытаюсь смоделировать поведение терминала в Linux, создавая мини-оболочку в коде c, но я столкнулся с проблемой при попытке реализовать последовательности команд, так как вывод первого не будет получен должным образом рядом через трубы. Мы хотим реализовать это путем передачи стандартного вывода первой команды (потомок 1) во второй (потомок 2, рожденный после того, как потомок 1 умер) через каналы и с использованием этого в качестве стандартного ввода для второй. Обратите внимание, что я использую оператор fork () в начале цикла for, поэтому каждая итерация создает дочернего элемента, который умирает до рождения другого.

Я пытался использовать другие команды, кроме dup2, но ничего не получалось. Кроме того, первая команда, похоже, возвращает список, уже отсортированный при использовании примера команды, такого как «ls | sort», и перехвата вывода первой.

argvv - это переменная типа char ***, которая содержит одну запись для каждой команды на первом уровне, а для каждой команды - запись с каждым аргументом на втором уровне

/*pipes have been created already; p1, p2 (p2 only useful for sequences of 3 commands)*/

for (command_counter = 0; command_counter < num_commands; command_counter++)
        {

            int chid = fork();

            switch (chid)
            {
                case 0: // child


                //COMMAND EXECUTION


                /*Running commands with pipes */

                    /*Data is only ran through pipes if there's more than one command*/

/*we only implemented the version for two commands so far*/

                /*...*/
                if(num_commands==2)
                {
                    /*Data is only ran through pipes if there's more than one command*/
                    if(command_counter==0)
                    {//The first command takes no input from pipe
                        close(p1[0]);
                        close(p2[0]);
                        close(p2[1]);
                        dup2(p1[1], 1);
                        close(p1[1]);
                    }
                    if(command_counter==1)
                    { //Last command takes input only, output goes to stdout or output file
                        close(p2[1]);
                        close(p2[0]);
                        close(p1[1]);
                        dup2(p1[0], 0);
                        close(p1[0]);
                    }

                }


                execvp(argvv[command_counter][0], argvv[command_counter]);

                case -1:    // error
                perror("Couldn't create child process\n");
                exit(-1);

                default:
                    // father
                        waitpid(chid, 0, 0);

            }
        }
        close(p1[1]);
        close(p1[0]);
        close(p2[1]);
        close(p2[0]);

Я ожидал, что программа будет работать нормально, но она просто останавливается при выполнении команды сортировки. Я почти уверен, что ошибка заключается в использовании dup2 примерно в секунду для итерации, но я хотел бы знать наверняка, что мне следует сделать, чтобы исправить это

1 Ответ

1 голос
/ 31 марта 2019

У вас есть пара правильных вещей:

  1. Вы создаете новый процесс и правильно проверяете статус.
  2. Вы вправе закрыть все файловые дескрипторы каналав котором дочерний и родительский процессы не нужны.

Что нужно, чтобы получить права:

Когда создается дочерний элемент [command_counter], он разделяет канал child[command_counter-1] (если command_counter >= 0) и каналchild[command_counter +1] (если command_counter +1 < num_commands).

Ждать детей следует начинать только после создания последнего ребенка.Если вы начнете ждать раньше, то один из каналов может быть заполнен, и система начнет ждать, пока процесс прочитает канал.Но если последний ребенок еще не создан, то никто не читает трубку, и все это заходит в тупик.(никто не читает канал, когда пишущий ожидает его чтения).

Если вы создаете все процессы заранее, перед тем как начать ждать, не забудьте закрыть все каналы вродительский процесс, прежде чем начать ждать.В противном случае, когда первый дочерний элемент завершит работу, следующий дочерний элемент не получит сигнал EOF, поскольку канал еще открыт (родительским элементом).

...