1

I'm trying to simulate bash pipe like ls | grep ma | wc but for some reason it seems like my third child process that executes wc just hangs. I can't find the culprit, please help.

Here's my code:


#include <stddef.h> 
#include <stdio.h>  
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define CMD_NUM 3

int main(void)
{

    pid_t pids[CMD_NUM]; 
    int *pipeFd;
    int pipeFds[CMD_NUM - 1][2]; 
    for (int i = 0; i < CMD_NUM - 1; i++)
        if (pipe(pipeFds[i]) == -1)
            perror("Error creating pipes");

    pids[0] = fork();
    if (pids[0] == 0)
    {
        printf("I'm in 1r if\n");
        pipeFd = pipeFds[0];
        close(pipeFd[0]);
        close(1);
        dup2(pipeFd[1], 1);

        char* argv[] = {"ls", "-l", NULL};
        execvp("ls", argv);
        perror("Error ls execvp");
        exit(1);
    }
    

    for (int i = 1; i < CMD_NUM - 1; i++)
        {
            printf("I'm in for\n");
            pids[i] = fork();
            if (pids[i] == 0)
            {
                close(0);
                close(1);

                pipeFd = pipeFds[i - 1]; 
                close(pipeFd[1]);
                dup2(pipeFd[0], 0);

                pipeFd = pipeFds[i]; 
                close(pipeFd[0]);
                dup2(pipeFd[1], 1);

                char* argv[] = {"grep", "ma", NULL};
                execvp("grep", argv);
                perror("Error in execvp");
                exit(1);
            }
        }

        pids[CMD_NUM - 1] = fork();
        if (pids[CMD_NUM - 1] == 0)
        {

            printf("I'm in 2n if\n");
            pipeFd = pipeFds[CMD_NUM - 2];
            close(pipeFd[1]);
            close(0);
            dup2(pipeFd[0], 0);

            char* argv[] = {"wc", NULL};
            perror("hello");
            execvp(argv[0], argv);
            perror("Error en execvp");
            exit(1);
        }

        for (int i = 0; i < CMD_NUM - 1; i++)
        {
            printf("I'm closing pipes\n");
            pipeFd = pipeFds[i];
            close(pipeFd[0]);
            close(pipeFd[1]);
        }

        printf("I'm waiting for my last child\n");
        waitpid(pids[CMD_NUM - 1], NULL, 0);
}

I'm only waiting for the last child because it's a requirement.

oguz ismail
  • 1
  • 16
  • 47
  • 69
lzy917
  • 43
  • 3
  • `grep` might just be taking a long time... have you tried running it without the `wc`, and seeing how long it takes? – cs1349459 Oct 13 '22 at 15:25
  • Related: https://stackoverflow.com/questions/60804552/pipe-two-or-more-shell-commands-in-c-using-a-loop/60805808#60805808 – Marco Bonelli Oct 13 '22 at 15:33
  • @cs1349459 well, when I only ran two commands , I tried with ```ls | grep ma```, it did work. Could the for loop be the problem? – lzy917 Oct 13 '22 at 15:34
  • 1
    You're almost certainly not closing all the pipes. A good place to start looking is your `dup2` code. The boiler plate should be `close(pipeFd[0]); dup2(pipeFd[1], 1); close(pipeFd[1]);`. (close the pipe end after you dup it) – William Pursell Oct 13 '22 at 16:02
  • 3
    You need to close *all* pipe ends in *every* child. You have 4 pipe ends, each child needs to close all 4. – n. m. could be an AI Oct 13 '22 at 16:43
  • 1
    You need to close the pipe ends for the _prior_ stage in the parent. See my answer: [fd leak, custom Shell](https://stackoverflow.com/a/52825582/5382650) – Craig Estey Oct 13 '22 at 17:29

0 Answers0