0

Sample code without error handling

int pipes[2];

pipe(pipes);
int pid = fork();

if (pid == CHILD)
{
   close(pipes[0]); //close useless read fd
   dup2(STDOUT_FILENO, pipes[1]); //replace default output by writer piped fd
   execve(...);
   close(pipes[1]); // ??????????
}
else //parent
{
  close(pipes[1]); //close useless write fd
  dup2(STDIN_FILENO, pipes[0]); //replace default input by reader piped fd
  read(pipes[0]..);
  close(pipes[0]);
}

In the child, we know that a default output/input is automatically closed at the end of the program (STDIN_FILENO/STDOUT_FILENO). If I use dup2() to change the default input/output, will my pipes[1] be closed automatically? Or Have I to do it myself and then how? I'm thinking that execve stops my program on its line on success.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • 3
    `execve` doesn't return. The current process will have been replaced by the new executable. – Colonel Thirty Two May 19 '17 at 14:15
  • ye I know it, it's not my problem –  May 19 '17 at 14:16
  • Closing a process also closes all file descriptors that that process had open. So yes, `pipes[1]` will be closed in the child process once it terminates. – Colonel Thirty Two May 19 '17 at 14:18
  • @Romain, ...and to contradict: What the first comment describes **is** your problem, because the `close` doesn't run at all unless you put it **before** the `execve()`. Consequently, your processes inherit two different copies of their stdin or stdout -- one on FD 0 or 1, and the other on the FIFO descriptor. – Charles Duffy May 19 '17 at 14:51
  • Actually, each process inherits a copy of **both** sides of the FIFO, which is even worse: The reader will never detect its stdin as closed, because *it itself* is holding the write side of the pipeline open. – Charles Duffy May 19 '17 at 14:53
  • 1
    **Rule of thumb**: if you duplicate one end of a pipe to standard input or standard output, you should close *both* ends of the original pipe before using `exec*()` functions (or otherwise continuing). There are exceptions; they are few and far between. It is very seldom (on SO, and IRL) that you encounter a program using pipes that closes too many descriptors; it is very common to find a program that doesn't close enough descriptors. It's especially common if there are multiple children and multiple pipes to confuse things. – Jonathan Leffler May 19 '17 at 14:59
  • @JonathanLeffler interessting. In my case, Im working on a shell and I have to handle multiple pipes. How should I close the descriptor, knowing that I can't close it before execve() (because I need to redirect the output to my pipe[1]) –  May 19 '17 at 16:36
  • You can and should close it before the `execve()` because that process is not going to do anything more with it — the replacement process won't know about the extra opened file descriptor. You need to distinguish between the parent process and the child process. The child process can't close the descriptors in the parent any more than the parent can close the descriptors in the child. _[…continued…]_ – Jonathan Leffler May 19 '17 at 17:26
  • _[…continuation…]_ In the fragment in the question, the parent is going to read the child's pipe. The `dup2(STDIN_FILENO, pipes[0])` is wrong; it closes the pipe file descriptor in `pipes[0]` and makes that descriptor refer to the same file as standard input. You should simply drop the `dup2()` in the parent; it isn't what you want. The rest then makes sense — the parent can read from the read end of the pipe. You need to capture the return value from `read()`; the data will not usually be null terminated (it won't be null terminated unless the writing (child) process writes the null byte.) – Jonathan Leffler May 19 '17 at 17:28

0 Answers0