8

I'm trying to implement a multiple pipe for my shell in C.

All I have is a pipe function that pipe a | b but not a | b | c.

int   c[2];
int   returnv;
pid_t id;

pipe(c);
pid = fork()) == 0
if (pid)
{
  dup2(c[1], 0);
  close(p[1]);
  close(p[1]);
  execvp(array(0), array);
}

if ((pid = fork()) == 0)
{
  dup2(p[0], 1);
  close(p(0));
  close(p[0]);
  returnv = execvp(array[0], array);
}

close(p[1]);
wait(NULL);
wait(NULL);
wait(NULL);
return returnv;

And this is a second version:

int i = 0;

while (i < x)

{
 pipe(c);
 if ((pid = fork()) == 0)
 {
   dup2(t[i], 1);
   if (i < 2)
       dup2(p[0], 1);
   close(p[1]);
 r=  execvp(cmd[i][0], cmd[i]);
 }
     wait(NULL);
     close(p[0]);
     i += 1;
     t[i] = p[1];

How can I add the little something that will make this code manage multiple pipe please ? Thanks a lot in advance !

user2145240
  • 95
  • 1
  • 3
  • 9
  • Actually you are calling fork() twice, while you need only once. This because fork() returns two times: 0 for the son process and >1 for the father process (usually it is son's pid). I don't think you need all that code for doing what you need. – Acsor Jul 13 '13 at 12:44
  • I've spent so much time on this one, this is the only thing that works ^^ I guess there is just one call to execvp needed for multi pipe but I can't make it work. :( – user2145240 Jul 13 '13 at 12:58
  • 1
    Don't remove the code from the post it invalidates the answers – FDinoff Jul 14 '13 at 00:11
  • 1
    Does this answer your question? [Implementation of multiple pipes in C](https://stackoverflow.com/questions/8389033/implementation-of-multiple-pipes-in-c) – ggorlen Dec 05 '22 at 23:16

2 Answers2

16

Edit: according to your comment

To perform multiples pipes you need to store all your commands somewhere. That's why I used a tab of structure.

Check this new version maybe easier to understand

So first you need a tab or something to store all your commands:

int main()
{
  char *ls[] = {"ls", NULL};
  char *grep[] = {"grep", "pipe", NULL};
  char *wc[] = {"wc", NULL};
  char **cmd[] = {ls, grep, wc, NULL};

  loop_pipe(cmd);
  return (0);
}

Then the function who will run through the tab and launch everything

void    loop_pipe(char ***cmd) 
{
  int   p[2];
  pid_t pid;
  int   fd_in = 0;

  while (*cmd != NULL)
    {
      pipe(p);
      if ((pid = fork()) == -1)
        {
          exit(EXIT_FAILURE);
        }
      else if (pid == 0)
        {
          dup2(fd_in, 0); //change the input according to the old one 
          if (*(cmd + 1) != NULL)
            dup2(p[1], 1);
          close(p[0]);
          execvp((*cmd)[0], *cmd);
          exit(EXIT_FAILURE);
        }
      else
        {
          wait(NULL);
          close(p[1]);
          fd_in = p[0]; //save the input for the next command
          cmd++;
        }
    }
}
Alexis
  • 2,149
  • 2
  • 25
  • 39
  • 2
    @user2145240 I have changed my answer, the old one was a bit messy because I used it for many other things ;) – Alexis Jul 13 '13 at 19:44
  • 1
    @user2145240 can you show how you call it, because I it's working nicely on my computer, and also on ideone http://ideone.com/80e3nd – Alexis Jul 13 '13 at 22:37
  • 1
    @user2145240 Few things to check:printf("9--On rentre ici?"); please don't forget the \n at the end, Add a perror under the exec to be sure you don't have something missing in the env – Alexis Jul 13 '13 at 23:22
  • 1
    @user2145240 well the only thing who can create problems is int i = place; And since you don't display anything in the loop we can't be sure that it actually went inside. But I'm out of ideas, if you find the solution please let me know – Alexis Jul 13 '13 at 23:51
  • It enters well in the loop, and do the loop exactly three times. There are no problem with place – user2145240 Jul 13 '13 at 23:56
  • @ Alexis: It's finally working !!!! I had to initialize cmd[i+1] at NULL to make it finish well the loop. I'm so dumb. Thanks a lot !!!! – user2145240 Jul 14 '13 at 00:02
  • 2
    Great so I guess my answer was correct :) (because on my example I put the null at the end :D ) – Alexis Jul 14 '13 at 00:18
1

I will give a working version of the two pipe model and a hint for the three pipe model. Try it out and see if it works. NOTE: If you do not include the proper header files, dup2() will be a nightmare.

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

int p[2];
int pid;
int r;

main()
{
    char *ls_args[] = {"ls", NULL};
    char *grep_args[] = {"grep", "pipe", NULL};

    pipe(p);

    pid = fork();
    if (pid  != 0) {
            // Parent: Output is to child via pipe[1]

            // Change stdout to pipe[1]
            dup2(p[1], 1);
            close(p[0]);

            r = execvp("ls", ls_args);
    } else {
            // Child: Input is from pipe[0] and output is via stdout.
            dup2(p[0], 0);
            close(p[1]);

            r = execvp("grep", grep_args);
            close(p[0]);
    }

    return r;
}

For a|b|c, the hint is to use two pipes i.e. p1[2] and p2[2]. Try this out and let us know how it works.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
lsk
  • 532
  • 4
  • 5