0

Im trying to replicate the multiple pipes execution of bash, and Im getting no output from terminal. First I create the number of pipes that my program will need depending on the number of commands, then in a while loop I launch each process executing each command in the child proccess and working with the correct FDs of pipes, in case it is first command, I dont read from any pipe, on the other hand, in case it is last command, I dont redirect the output to any pipe. I printed each fd to check if my program is doing well and it looks everything okay but as I said I dont get any output of the last commands.

Here is a snippet of my code about how I deal with the process and the pipes, if you need something more just let me know.

int i;
int *pipes;

i = 0;
pipes = ft_calloc(sizeof(int), gdata->n_pipes * 2);
while (i < gdata->n_pipes)
{
    pipe(pipes + (i * 2));
    i++;
}
int cc = 0; //command count
int r = 0;  
int m;
pid_t pid;
while (gdata->cmds[r])  //double pointer array that contains the commands to execute ex: [["ls -l"], ["grep i"], ["wc -l"]]
{
    pid = fork();
    if (pid < 0)
    {
        perror("Fork: ");
        exit(EXIT_FAILURE);
    }
    if (pid == 0)
    {
        if (r > 0)
        {
            if (dup2(pipes[(cc - 1) * 2], STDIN_FILENO) < 0)
            {
                perror("dup");
                exit(EXIT_FAILURE);
            }
        }
        if (r < gdata->commands - 1)
        {
            if (dup2(pipes[cc * 2 + 1], STDOUT_FILENO) < 0)
            {
                perror("dup");
                exit(EXIT_FAILURE);
            }
        } 
        int k = 0;
        while (k < gdata->n_pipes * 2)
        {
            close(pipes[k]);
            k++;
        }
        handle_path(gdata->cmds[r], gdata->envp); // function that calls execve to execute commands
    }
    waitpid(pid, &m, 0);
    r++;
    cc++;
}
int y = 0;  
while (y < gdata->n_pipes * 2)
{
    close(pipes[y]);
    y++;
}

Do you have any idea what I'm doing wrong, Thanks for the help!

GonWTC
  • 5
  • 2
  • For a working example, see my answer: [fd leak custom shell](https://stackoverflow.com/a/52825582) – Craig Estey Jun 28 '22 at 16:17
  • 1
    One of the issues is that you call `pipe` for _all_ the pipes you need in the parent before you do any `fork` calls. Thus, all child processes hold open all pipe ends. This doesn't work too well. What you want is to create only one pipe at a time, by the parent, as you fork. A given child only holds open the exact pipe ends it needs. (e.g.) If you have: `A | B | C | D` then 4 procs and 3 pipes (e.g. `int p[3][2];`). The "ownership" is which proc holds which pipe end open: `A=p[0][1] B=p[0][0],p[1][1] C=p[1][0],p[2][1] D=p[2][0]` – Craig Estey Jun 28 '22 at 16:32
  • You aren't closing enough file descriptors in the child. **Rule of thumb**: If you [`dup2()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html) one end of a pipe to standard input or standard output, close both of the original file descriptors from `pipe()` as soon as possible. In particular, that means before using any of the [`exec*()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/execvp.html) family of functions. The rule also applies with either `dup()` or [`fcntl()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html) with `F_DUPFD`. – Jonathan Leffler Jun 28 '22 at 19:26
  • And, as @CraigEstey noted, you have to close all the pipes that each child is not using at all. If the parent process opens all the pipes before launching any children, then the children all have to close a lot of pipes. The parent process also needs to close all the pipes once it has launched (forked) all the children. That can be a lot of calls to `close()` — it should be a loop-driven sequence of calls, of course. – Jonathan Leffler Jun 28 '22 at 19:28

0 Answers0