Clássico C. Usando pipes na função execvp, redirecionamento stdin e stdout

Eu quero simular bash no meu programa Linux C usando pipes e função execvp. por exemplo

ls -l | wc -l  

Existe o meu programa:

if(pipe(des_p) == -1) {perror("Failed to create pipe");}

if(fork() == 0) {    //first fork
  close(1);          //closing stdout
  dup(des_p[1]);     //replacing stdout with pipe write 
  close(des_p[0]);   //closing pipe read
  close(des_p[1]);   //closing pipe write

  if(execvp(bash_args[0], bash_args)) // contains ls -l
    /* error checking */
}
else {
  if(fork() == 0) {  //creating 2nd child
    close(0);        //closing stdin
    dup(des_p[0]);   //replacing stdin with pipe read
    close(des_p[1]); //closing pipe write
    close(des_p[0]); //closing pipe read

    if(execvp(bash_args[another_place], bash_args)) //contains wc -l
      /* error checking */
  }

  close(des_p[0]);
  close(des_p[1]);
  wait(0);
  wait(0);
}

Este código é executado, mas não faz a coisa certa. O que há de errado com esse código? Isso não está funcionando e eu não tenho idéia do porquê.

questionAnswers(2)

QuestionSolution

ou o filho não receberá EOF, porque o canal ainda está aberto para escrever no pai. Isso causaria o segundowait() pendurar. Funciona para mim:

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


int main(int argc, char** argv)
{
        int des_p[2];
        if(pipe(des_p) == -1) {
          perror("Pipe failed");
          exit(1);
        }

        if(fork() == 0)            //first fork
        {
            close(STDOUT_FILENO);  //closing stdout
            dup(des_p[1]);         //replacing stdout with pipe write 
            close(des_p[0]);       //closing pipe read
            close(des_p[1]);

            const char* prog1[] = { "ls", "-l", 0};
            execvp(prog1[0], prog1);
            perror("execvp of ls failed");
            exit(1);
        }

        if(fork() == 0)            //creating 2nd child
        {
            close(STDIN_FILENO);   //closing stdin
            dup(des_p[0]);         //replacing stdin with pipe read
            close(des_p[1]);       //closing pipe write
            close(des_p[0]);

            const char* prog2[] = { "wc", "-l", 0};
            execvp(prog2[0], prog2);
            perror("execvp of wc failed");
            exit(1);
        }

        close(des_p[0]);
        close(des_p[1]);
        wait(0);
        wait(0);
        return 0;
}
 Khan Power08 de abr de 2017 20:26
Dê uma olhada neste código na linha 61:Dynpipe. Descomentando essa linha e então rodando./Dynpipe "ls -l" "grep cpp" "wc -l" resultará em um travamento. Eu acredito que isso é porque a chamada do pai para fechar leitura / gravação acontece muito rápido, e o pipe apontado pelo descritor de arquivo é excluído.
 Nicholas Wilson08 de abr de 2017 16:38
Você está pensando em desligar, não fechar? Ao bifurcar uma criança, você quer fechar todos os fd que a criança usará.
 Khan Power15 de abr de 2017 05:51
@NicholasWilson Ahh eu vejo realmente. E peço desculpas por postar código; Eu não estava tentando procurar ajuda com isso, eu simplesmente não conseguia encontrar uma maneira de descrever o fenômeno que estava ocorrendo.
 Jonathan Leffler10 de dez de 2012 17:29
Há uma regra de polegar bastante confiável:Se você usardup() oudup2() para duplicar uma extremidade de um pipe para entrada padrão ou saída padrão, você precisaclose() ambas as extremidades do tubo original.  Pode haver circunstâncias em que esse não é o comportamento necessário, mas essas circunstâncias são raramente encontradas.
 Khan Power08 de abr de 2017 08:37
Só queria ressaltar que se você tem váriosexecvp chamadas que se comunicam entre si através de canos, somente pertoo fim da gravação dos tubos no pai (fecha ambos em filho). Se você fechar ambos no pai, as chamadas subseqüenteswaitpid vai travar.
 Nicholas Wilson10 de abr de 2017 16:54
@Khan você realmente deveria postar uma nova pergunta já que você está efetivamente pedindo ajuda para depurar seu código! Você precisa fechar todos os fd que a criança usa, seu código tem um problema não relacionado. Na linha comentada, você está fechando um fd que a próxima iteração do loop estaria usando! Você deve fechartodos os fds no pai - só quando você acabar de usá-los no pai. Se você tivesse verificado o código de retorno do dup2 você teria notado (você também precisa verificar os códigos de retorno de pipe / fork / close / execvp / waitpid).
 krzakov10 de dez de 2012 16:53
Cara, você é o chefe. Finalmente funciona (eu editei o primeiro código e agora funciona).

wait função faz. Ele vai esperar até que um processo filho existe. Você está esperando o primeiro filho sair antes de iniciar o segundo filho. O primeiro filho provavelmente não sairá até que haja algum processo que leia do outro lado do tubo.

 krzakov10 de dez de 2012 14:50
Para os registros, o caso ainda não está resolvido.
 krzakov10 de dez de 2012 14:32
Isso é difícil de me mostrar exemplo no meu código?
 Art10 de dez de 2012 14:22
Crie processos com o tubo entre então, entãowait duas vezes para ambos terminarem.
 Nicholas Wilson10 de dez de 2012 16:28
@krzakov Você precisa fechar o pipe fds no pai, ou o segundo filho não receberá EOF, e assim irá travar (a menos que o primeiro filho esteja muito interessado e faça chamadasshutdown() no seu final).
 Nicholas Wilson10 de dez de 2012 16:48
@krzakov Parece familiar ... Essa foi a minha resposta, menos o fato de que você não está esperando por ambos os filhos, como Art apontou que você deveria fazer. Está correto se faz o que você quer. Tudo o que posso garantir é que meu código compila e faz o que eu acho que você quer! (Eu desfiz as alterações na pergunta, pois, do contrário, é confuso.)
 krzakov10 de dez de 2012 16:33
@ NicholasWilson eu editei. Está correto agora?
 krzakov10 de dez de 2012 14:18
Quando eu removo primeiro wait (), há loucura na tela. Execvp começando após o término do programa principal. Como mudar então?

yourAnswerToTheQuestion