Some years ago, before the Net::Server and Net::Daemon modules were on CPAN, a friend asked me to write him a simple daemon that would sniff out servers for Quake, Unreal, etc. That is, one tool to do all of these types, and provide a way for him to connect and get the list, etc. etc. Of course, since then people have written much more feature-ful tools like this, some of them even in C :-). What I took away from the experience, though, is the following subroutine. Since he planned on having this thing run for days at a time, I wanted it to daemon-ize itself just as cleanly as sendmail, inetd, or any other legacy daemon written in C. So I turned to my trusty copy of "Advanced UNIX Programming" by the (late) great W. R. Stevens, and churned out this piece.
What you see here is a much more literate version, one that has some commentary sprinkled around, and some better attention to indentation and such, for the sake of readability. The one (optional) parameter it takes at invocation is a simple boolean of whether to die on errors or not. Unless explicitly specified, the default is to die when an error occurs. When the function returns (error-free), the caller may feel confident that they are now well and properly backgrounded. STDIN, STDOUT and STDERR are no longer available to you, but they are available to be reopened onto any files you like.
This could maybe be made more efficient or more compact, but soon after this was when Net::Daemon came out, and soon after that Net::Server. If you have real server-implementation needs, I recommend one of those (I provide support for Net::Server natively in my RPC::XML package). But if you have a simpler task for which you want to background and not worry about terminal-related and process-group-related signals and issues, this may hopefully be of use. Enjoy.
Update: Added a chdir to root.
--rjray
sub become_daemon { my $dont_die = shift || 0; my ($child, $sig); $child = fork; if (defined $child) { exit 0 if $child; } else { $dont_die && return "Error in fork: $!"; die "$0 died in fork: $!, dead"; } # # First-generation child. # setpgrp; close(STDIN); close(STDOUT); close(STDERR); chdir '/'; umask 0; for (qw(TSTP TTIN TTOU)) { $SIG{$_} = 'IGNORE' if (exists $SIG{$_} +) } # # In case of SysV, re-spawn to avoid danger of re-acquiring a cont +rol # terminal. Now the child is not the pgrp leader. # $sig = $SIG{HUP}; $SIG{HUP} = 'IGNORE'; $child = fork; if (defined $child) { exit 0 if $child; } elsif ($child) { $dont_die && return "Error in (1st-generation child) fork: $!" +; die "$0 (1st-generation child) died in fork: $!, dead"; } # # Restore HUP (which will probably be set later on, anyway) and re +turn. # $SIG{HUP} = $sig; return; }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Forking the polite way
by rob_au (Abbot) on Feb 12, 2002 at 12:19 UTC | |
by rjray (Chaplain) on Feb 13, 2002 at 05:16 UTC | |
|
Re: Forking the polite way
by Zaxo (Archbishop) on Feb 12, 2002 at 09:23 UTC |