Pedro Barros
Pedro Barros

Reputation: 183

Using pipes to connect child processes in a shell

I'm trying to child process communication in my shell. Like this:

ls | ls -l
ls -l | wc -l

The problem is, when I do "ls | ls -l" it works, and I get what was expected, only "ls -l". But if I do "ls -l | wc -l" it just stays like waiting like the program was in a cycle.

Here's my code:

void execute_commands(COMMAND *commlist) {

pid_t process;
COMMAND *first = commlist;
int fd_before[2];
int fd_actual[2];
int status;

while(commlist != NULL) {       

  if(commlist->next != NULL) pipe(fd_actual);

  if ((process = fork()) < 0){ }         // FAILED

  else if (process == 0) {               

    if(first != commlist) {
      dup2(fd_before[0], PIPE_READ);
    }

    if(commlist->next != NULL) {
      dup2(fd_actual[1], PIPE_WRITE);
    }

    /* You can ignore this, it's from input files /*
    if(inputfile != NULL) {  
      int in = open(inputfile, 0);      
      if(in < 0) exit(1);
      dup2(in, 0);
      close(in);
    }
    /* You can ignore this, it's from input files /*
    if(outputfile != NULL) {  
      int out = creat(outputfile, 0644);
      dup2(out, 1);
      close(out);
    }

    if(execvp(commlist->argv[0], commlist->argv)< 0) exit(1);
  }
  else {
    wait(&status);
    commlist = commlist->next;
    fd_before[0] = fd_actual[0];
    fd_before[1] = fd_actual[1];
  }                                    
  close(fd_before[PIPE_READ]);
  close(fd_before[PIPE_WRITE]);
  close(fd_actual[PIPE_READ]);
  close(fd_actual[PIPE_WRITE]);
}

/*wait(&status); Should wait be here, or where it currently is? */

}

--

I have another doubt, if I change my code and put this, within the child process:

close(fd_before[PIPE_READ]);
close(fd_before[PIPE_WRITE]);
close(fd_actual[PIPE_READ]);
close(fd_actual[PIPE_WRITE]);

It's going to close my current input and output, and not receive or output anything.

But when I do that inside the inputsfile "close(in);", it still works. What's the difference?

Upvotes: 0

Views: 385

Answers (1)

Jonathan Ross
Jonathan Ross

Reputation: 550

This is working for ls -l | ls -l because ls in that form doesn't read standard input, so it will run even if you neglect to set up stdin properly.

For ls -l | wc -l, wc needs stdin to count lines, and it's not receiving any input.

Several other things are missing

  • Without the definition of PIPE_READ and PIPE_WRITE we can't see where you're expecting to the duplicate descriptors to appear
  • There is an unclosed comment in the code so it's clearly not complete
  • At some point you will need to exec() your commands (ls, wc, et cetera)

Since this looks like an assignment, I'll direct you to existing posts showing this in greater detail:

Understanding how to connect pipes and wait for them in a custom C shell

UNIX Pipes Between Child Processes

Upvotes: 2

Related Questions