Конвейер для перенаправления stdout одной программы на stdin другой

Нам нужно написать программу на C, которая по существу перенаправит стандартный вывод одной команды/программы на другой стандартный вывод команды/программы, используя конвейеры. Если программе в командной строке был передан ./a.out ls -l \; more, она должна перенаправить стандартный вывод ls -l на more, где \; является разделителем. Эта программа должна работать для любой команды/программы, которая находится на нашем пути, поэтому: ./a.out cat filename.c \; more должно совпадать с вводом: cat filename.c | more.

Моя проблема в том, что моя программа не может работать должным образом или каналы работают не так, как ожидалось. По сути, я просто не получаю никаких результатов, кроме отладки оператора печати, которую я разместил. Чтобы быть точным, программа печатает: Exec... и затем ERROR, что все в родительском коде.

  #include <fcntl.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/wait.h>
  void pipeit(char * pro1, char * pro2, char * p1args[], char * p2args[])
  {
     pid_t pid;
     int fd[2];
     int st;
     pipe(fd);
     pid = fork();

     if(pid < 0)
     {
        printf("Error Forking...\n");
        exit(-1);
     }
     else if(pid == 0)
     {
        dup2(fd[1],1);
        close(fd[0]);
        close(1);
        printf("Exec 1...\n");
        execv(pro1, p1args);
        printf("ERROR\n");
     }
     else
     {
        waitpid(pid,&st,0);
        if(st<0)
        {
           printf("Child Error\n");   
        }
        dup2(fd[0],0);
        close(fd[1]);
        close(0);
        printf("Exec...\n");
        execv(pro2,p2args);
        printf("ERROR\n");
     }
     return;
  }
  /* THIS IS JUST COMMAND LINE PARSING */
  int main(int argc, char * argv[])
  {
     int i = 1;
     char * pro1;
     char * pro2;
     char * first[argc+1];
     char * second[argc+1];
     while(i<argc && argv[i][0] != ';')
     {
        if(i == 1)
        {
           pro1 = argv[i];
        }
        else
        {
           first[i] = argv[i];
        }
        i++; 
     }
     first[i] = NULL;
     while(i<argc)
     {
        if(argv[i][0] == ';')
        {
           i++;
           pro2 = argv[i];
        }
        else
        {
           second[i] = argv[i];
        }
        i++; 
     }
     second[i] = NULL;
     pipeit(pro1,pro2,first, second);
     return 0;
  }

person GreenSkies    schedule 03.03.2017    source источник


Ответы (1)


У ребенка вы имеете:

    dup2(fd[1],1);
    close(fd[0]);
    close(1);

Это дублирует канал для стандартного вывода, но затем закрывает стандартный вывод. Исправьте, не закрывая стандартный вывод и закрывая оба конца канала. Эмпирическое правило: если вы дублируете один конец канала для стандартного ввода, вывода или ошибки, вы должны закрыть оба исходных дескриптора канала.

    dup2(fd[1],1);
    close(fd[0]);
    close(fd[1]);

У вас есть аналогичная проблема в родителях с закрытием стандартного ввода.

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

person Jonathan Leffler    schedule 03.03.2017