c - execl`d program doesn't give promt back

Viewed 71

EDIT: THE QUESTION IS ANSWERED IN COMMENTS

So, i'm studying pipes. Long story short, i have two programs:

  1. first program creates a pipe and two forks: first fork closes read descriptor and writes some stuff to write one (then closes it), second fork closes write one, dup2 on read side of pipe to standard input (end closes read side itself) and execl second program, giving a size of a text the first fork writes as an argument; the parent closes both pipe sides and waitpids for child that wasexecld (second one).
  2. second program just reads from its standard input (pipe side) the stuff and writes it out to standard output, then closes pipe side just in case.

In such a setup everything works as I intended, but when I delete waitpid in first program (or just wait for the first child that writes instead of the second one), the second one behaves weirdly - it executes till the end, passing through all the IO (that is, the printf before exit got executed), and then doesn't give me the prompt back. That is, the terminal looks like the program awaits for an input from standard input. If i execute the first program without execl, then everything works fine, If I execute just the second one with one argument, then it waits only until input is provided to standard input (as it should as it is not a part of a pipe in this case).

As i know, when parent terminates, the child is "inherited" by init and got waited. But even if it wasn't, that is, even if it remained as a zombie, then it still would be weird - why i cannot get my prompt back until i wait explicitly?

The code is below (of the setup that works correctly):

First program

  /* headers */
  int main(void)      
  {   
      int fildes[2];
      pid_t p1, p2;
      int status;
      char mess[] = "written from execved program!\n";
      int buf = strlen(mess);
      
      if(pipe(fildes) == -1) {
          perror("pipe in main");
          exit(EXIT_FAILURE);
      }
      p1 = fork(); 
      if(p1 == -1) {
          perror("fork p1 in main");
          exit(EXIT_FAILURE);
      }
      else if (p1 == 0) {
          printf("Child 1!\n");
          close(fildes[0]);
          write(fildes[1], mess, buf);
          close(fildes[1]);
          printf("Before exit in child 1!\n");
          exit(EXIT_SUCCESS);
      }
      
      p2 = fork(); 
      if(p2 == -1) {
          perror("fork p2 in main");
          exit(EXIT_FAILURE);
      }
      else if (p2 == 0) {
          printf("Child 2!\n");
          dup2(fildes[0], 0);
          close(fildes[0]);
          close(fildes[1]);
          char s_buf[30];
          sprintf(s_buf, "%d", buf);
          execl("./pipe2slave", "pipe2slave", s_buf, (char *) 0);
          perror("execl have returned");
          exit(EXIT_FAILURE);
      }
      close(fildes[0]);
      close(fildes[1]);
  /* 
   below if I wait for, say, p1, or don't wait it all, 
   the weird behavior described in my question happens 
  */
      if(waitpid(p2, &status, 0) == -1) { 
          perror("waitpid in main");
          exit(EXIT_FAILURE);
      }   
      if(WIFEXITED(status))
          printf("pipe2slave exit status is %d\n", WEXITSTATUS(status));
      printf("End of main in pipe2!\n"); 
      exit(EXIT_SUCCESS);  
  }

Second program

   /* headers */ 
   int main(int argc, char **argv) 
   {
        if (argc != 2) {
            perror("pipe2slave - not enough args");
            exit(EXIT_FAILURE);
        }
        printf("program name is %s\n", argv[0]);
        int buf = atoi(argv[1]);
        printf("%d\n", buf);
        char mess_in[buf];
        read(0, mess_in, buf);
        write(1, mess_in, buf);
        fsync(1);
        close(0);
        printf("end of slave!\n");
        exit(EXIT_SUCCESS); 
    }

Thank you in advance!

0 Answers
Related