The terminal is controlled by the foreground process group. When the shell invokes the parent, it makes the parent the leader of the foreground process group. The child inherits that group and has access to the terminal.
However, when the parent exits, the shell takes back control of the terminal and becomes the leader of the foreground process group. The child is no longer in the foreground process group, so it has no access to the terminal. In this case, fgets()
will return NULL
and an error code will be set.
If you take input from someplace other than the terminal, such as a pipe, then you'll see that the program works as expected. For example:
$ echo test | ./parent ./child
So this problem only occurs when input comes from the terminal.
In retrospect, answering this question would have been more straighforward if the fgets error code was checked. In this case, fgets returns null, but then you need to check feof()
and/or ferror()
to determine if this means that the end of the file was reached (stdin closed) or there was an error. In this case, the NULL meant there was an EIO
error.
Earlier wrong answer (see comment thread for explanation, leaving this here because of the lengthy discussion):
When you fork, the child process inherits stdin etc. When the parent process exits, it closes stdin, so the child tries to read from a closed descriptor and gets nothing. By adding the call to wait()
, you keep stdin open and this allows your child program to work as expected.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…