Pipe команды с вилкой и dup2 - PullRequest
       102

Pipe команды с вилкой и dup2

0 голосов
/ 13 апреля 2020

Я написал следующий код для передачи двух команд:

#include <stdlib.h>
#include <unistd.h>

char    *program_1[3] = {"/bin/cat", "/dev/random", NULL};
char    *program_2[2] = {"/bin/ls", NULL};
char    *program_3[2] = {"/usr/bin/sort", NULL};

int main(void)
{
    int fd[2];
    int pid;

    pipe(fd);
    if ((pid = fork()) == 0) //Child process
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[0]);
        execve(program_3[0], program_3, NULL);
    }
    else if (pid > 0) //Parent process
    {
        dup2(fd[0], STDIN_FILENO);
        close(fd[1]);
        execve(program_2[0], program_2, NULL);
    }
    return (EXIT_SUCCESS);
}

Каждая пара program_x / program_y, где x! = Y, работает нормально, кроме этой. Когда я трубу сортирую в ls, ls хорошо печатает свой вывод на стандартный вывод, но затем сортировка выдает эту ошибку: sort: Input/output error.

Когда я набираю sort | ls в bash, он печатает результат ls как мой программа, но затем ожидает ввода.

Я что-то не так делаю?

edit: я пытаюсь переопределить поведение оболочки

Ответы [ 3 ]

0 голосов
/ 13 апреля 2020

Ваша программа не совсем эквивалентна тому, что обычно делает оболочка.

Вы заменяете родителя на ls; в то время как shell создаст дочерние процессы, подключит их и будет ждать их завершения sh.

Это больше похоже на:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char    *program_2[2] = {"/bin/ls", NULL};
char    *program_3[2] = {"/usr/bin/sort", NULL};

int main(void)
{
    int fd[2];
    pid_t pid;
    pid_t pid2;

    pipe(fd);
    if ((pid = fork()) == 0) //Child process
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[0]);
        execve(program_3[0], program_3, NULL);
    }
    else if (pid > 0) //Parent process
    {
        if ( (pid2 = fork()) == 0) {
            dup2(fd[0], STDIN_FILENO);
            close(fd[1]);
            execve(program_2[0], program_2, NULL);
        }
    }

    waitpid(pid, 0, 0);
    waitpid(pid2, 0, 0);
    return (EXIT_SUCCESS);
}
0 голосов
/ 16 апреля 2020

Я наконец нашел решение, мы были близки к:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

char    *cat[3] = {"/bin/cat", "/dev/random", NULL};
char    *ls[2] = {"/bin/ls", NULL};
char    *sort[2] = {"/usr/bin/sort", NULL};

int main(void)
{
    int fd[2];
    pid_t pid;
    pid_t pid2;

    pipe(fd);
    if ((pid = fork()) == 0)
    {
        dup2(fd[1], STDOUT_FILENO);
        close(fd[0]);
        execve(cat[0], cat, NULL);
    }
    else if (pid > 0)
    {
        if ( (pid2 = fork()) == 0)
        {
            dup2(fd[0], STDIN_FILENO);
            close(fd[1]);
            execve(ls[0], ls, NULL);
        }
        waitpid(pid2, 0, 0);
        close(fd[0]);
    }
    waitpid(pid, 0, 0);
    return (EXIT_SUCCESS);
}

Нам нужно закрыть конец чтения канала после завершения последнего процесса, таким образом, если первый процесс пытается выполнить запись канал, будет выдано сообщение об ошибке, и процесс завершится, в противном случае, если он только читает из стандартного ввода как sort, он будет продолжать читать, так как стандартный ввод по-прежнему открыт

0 голосов
/ 13 апреля 2020

Проблема состоит в том, что когда ls завершается, родительский процесс завершает работу, что закрывает конец чтения канала, что приведет к распространению ошибки на конец записи канала, который обнаруживается sort и он пишет сообщение об ошибке.

То, что этого не происходит в оболочке, объясняется тем, что оболочка обрабатывает каналы не так, как ваша простая примерная программа, и поддерживает правую часть канала открытой и работающей. (возможно, в фоновом режиме), пока вы не передадите EOF ( Ctrl-D ) программе sort.

...