Search code examples
fileperlforkstdoutstderr

Replacing `close` with `open` `/dev/null`?


We have such Perl code:

if (fork==0) {
  # in child process close STDOUT и STDERR, for the parent process didn't wait a response from the child and finished quickly
  close(STDOUT); 
  if (!defined fileno(CGI::Carp::SAVEERR)) {close(STDERR)} # TODO learn to close redirected STDERR
  else        { close(CGI::Carp::SAVEERR); } 

  # ...
}

We had the problem described in Perl: STDOUT reopened as FH only for input - To solve it I was recommended not to close STDOUT and instead to reopen it as '/dev/null'.

Should I replace in the above code ALL calls of close with open /dev/null? or only close(STDOUT) and close(STDERR)?

Won't this replacement break "parent process didn't wait a response from the child and finished quickly"?


Solution

  • There seem to be a few things to clear up.

    The parent does need to reap its child processes (wait or waitpid on SIGCHLD), if that is what you mean by "wait a response from the child". However, if parent exits first the child is re-parented by init and all is well. This is not affected by the child's closing (reopening) of its streams.

    As for "closing" the streams, they should be redirected (reopened) to /dev/null instead. See, for instance, Complete disassociation of child from parent in perlipc for how the streams are shut down for daemonization, and an answer in the post linked in the question.

    Finally, it appears that STDERR was saved and redirected to a file in CGI::Carp. Whether you now want to close or restore it is up to intent/design. If the log to which STDERR is going and the stream itself should be closed you should first close the log, on what the module should restore STDERR (check please), and then redirect the stream to /dev/null.

    Altogether, perhaps

    my $pid = fork // die "Can't fork: $!";  #/
    
    if ($pid == 0) 
    {
        open STDOUT, '>', '/dev/null' or die "Can't write to /dev/null: $!";
    
        if (defined(fileno(CGI::Carp::SAVEERR)) 
        {
            close $fh_log_to_which_STDERR_was_redirected  or die $!;
            close CGI::Carp::SAVEERR                      or die $!;
        }    
        open STDERR, '>', '/dev/null' or die "Can't write to /dev/null: $!";
        ...
    }
    

    but check your CGI::Carp handling since there is no information on that in the question.

    Context of fork isn't given but consider IPC::Run3 or IPC::Run to launch and manage processes.