Реализация конвейерной обработки в оболочке Linux - PullRequest
0 голосов
/ 18 февраля 2011

Я пытаюсь разработать оболочку в Linux как проект операционных систем.Одним из требований является поддержка конвейерной обработки (когда вызов чего-то вроде ls -l | less передает выходные данные первой команды второй).Я пытаюсь использовать команды C pipe () и dup2 (), но перенаправление, кажется, не происходит (меньше жалуется, что не получил имя файла).Можете ли вы определить, где я ошибаюсь / как я могу исправить это?

РЕДАКТИРОВАТЬ: я думаю, что мне нужно где-то использовать freopen или fdopen, так как я не использую read () илиwrite () ... это правильно?

(я слышал от других, кто делал этот проект, что использование freopen () - это еще один способ решения этой проблемы; если вы думаете, что это будет лучше,Советы по продвижению в этом направлении также приветствуются.)

Вот моя функция execute_external (), которая выполняет все команды, не встроенные в оболочку.Различные команды в конвейере (например, [ls -l] и [less]) хранятся в массиве commands [].

 void execute_external()
{        
    int numCommands = 1;
    char **commands;
    commands = malloc(sizeof(char *));

    if(strstr(raw_command, "|") != NULL)        
    {
        numCommands = separate_pipeline_commands(commands);
    }
    else
    {
        commands[0] = malloc(strlen(raw_command) * sizeof(char));
        commands[0] = raw_command;
    }

    int i;
    int pipefd[2];
    for (i = 0; i < numCommands; i++)
    {
        char **parameters_array = malloc(strlen(commands[i]) * sizeof(char *));
        int num_params;
        num_params = str_to_str_array(commands[i], parameters_array);

        if (numCommands > 1 && i > 0 && i != numCommands - 1)
        {
            if (pipe(pipefd) == -1)
            {
                printf("Could not open a pipe.");
            }
        }

        pid_t pid = fork();


        pmesg(2, "Process forked. ID = %i. \n", pid);
        int status;
        if (fork < 0)
        {
            fprintf(to_write_to, "Could not fork a process to complete the external command.\n");
            exit(EXIT_FAILURE);
        }

        if (pid == 0) // This is the child process
        {
            if (numCommands > 1) { close(pipefd[1]); } // close the unused write end of the pipe
                           if (i == 0) // we may be pipelining and this is the first process
            {
                dup2(1, pipefd[1]); // set the source descriptor (for the next iteration of the loop) to this proc's stdout
            }
            if (i !=0 && (i != numCommands-1)) // we are pipelining and this is not the first or last process
            {
                dup2(pipefd[0], 0); // set the stdin of this process to the source of the previous process
            }
            if (execvp(parameters_array[0], parameters_array) < 0)
            {
                fprintf(to_write_to, "Could not execute the external command. errno: %i.\n", errno);
                exit(EXIT_FAILURE);
            }
            else    { pmesg(2, "Executed the child process.\n");}
        }
        else
        {
            if (numCommands > 1) { close(pipefd[0]); } // close the unused read end of the pipe
            if (backgrounding == 0) { while(wait(&status) != pid); }// Wait for the child to finish executing
        } 
        free(parameters_array);
    }
free(commands);
    }

1 Ответ

1 голос
/ 02 марта 2011

Похоже, в вашем коде происходит несколько ошибок.

Во-первых, все ваши dup2 только у ребенка. Для того, чтобы соединить канал, вам нужно дублировать стандартный вывод родительского элемента на конец записи pipefd [1] канала. Тогда вы бы подключили конец чтения к стандартному вводу.

Кроме того, похоже, что один из ваших dup2 задом наперед, с dup2 fildes дублируется в fildes2. Поэтому, когда вы переназначаете stdin, вы хотите dup2 (in, 0), а для stdout вы хотите dup2 (out, 1).

Таким образом, урезанный фрагмент кода будет выглядеть так:

 int pipefd[2];
 pipe(pipefd);

 pid_t pid = fork();

 if (pid == 0) //The child
 {
      dup2(pipefd[0], 0);
 }
 else
 {
      dup2(pipefd[1], 1);
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...