tweaking for FCGI stuff
[gitmo/MooseX-Daemonize.git] / lib / MooseX / Daemonize / Core.pm
CommitLineData
18cc5c89 1package MooseX::Daemonize::Core;
4327fe98 2use strict; # cause Perl::Critic errors are annoying
3use MooseX::Getopt; # to load the NoGetopt metaclass
18cc5c89 4use Moose::Role;
5
6our $VERSION = 0.01;
7
ea9485d8 8use POSIX ();
18cc5c89 9
10has is_daemon => (
4327fe98 11 # NOTE:
12 # this should never be accessible
13 # from the command line
14 # - SL
15 metaclass => 'NoGetopt',
16 isa => 'Bool',
17 is => 'rw',
18 default => sub { 0 },
18cc5c89 19);
20
d8985b7d 21sub daemon_fork {
22 my ($self, %options) = @_;
23
24 $SIG{CHLD} = 'IGNORE'
25 if $options{ignore_zombies};
26
129f5643 27 if (my $pid = fork) {
28 return $pid;
29 }
30 else {
289fcbc7 31 $self->is_daemon(1);
129f5643 32 return;
33 }
34}
d8985b7d 35
36sub daemon_detach {
37 my ($self, %options) = @_;
38
39 return unless $self->is_daemon; # return if parent ...
40
41 # now we are in the daemon ...
42
129f5643 43 (POSIX::setsid) # set session id
d8985b7d 44 || confess "Cannot detach from controlling process";
45
46 unless ($options{no_double_fork}) {
47 $SIG{'HUP'} = 'IGNORE';
48 fork && exit;
49 }
50
ea9485d8 51 chdir '/'; # change to root directory
d8985b7d 52 umask 0; # clear the file creation mask
53
3c0d9597 54 unless ($options{dont_close_all_files}) {
55 # get the max numnber of possible file descriptors
56 my $openmax = POSIX::sysconf( &POSIX::_SC_OPEN_MAX );
57 $openmax = 64 if !defined($openmax) || $openmax < 0;
d8985b7d 58
3c0d9597 59 # close them all
60 POSIX::close($_) foreach (0 .. $openmax);
61 }
ea9485d8 62
4327fe98 63 # fixup STDIN ...
64
65 open(STDIN, "+>/dev/null")
66 or confess "Could not redirect STDOUT to /dev/null";
67
68 # fixup STDOUT ...
d8985b7d 69
129f5643 70 if (my $stdout_file = $ENV{MX_DAEMON_STDOUT}) {
d8985b7d 71 open STDOUT, ">", $stdout_file
129f5643 72 or confess "Could not redirect STDOUT to $stdout_file : $!";
73 }
74 else {
4327fe98 75 open(STDOUT, "+>&STDIN")
76 or confess "Could not redirect STDOUT to /dev/null";
129f5643 77 }
78
4327fe98 79 # fixup STDERR ...
80
d8985b7d 81 if (my $stderr_file = $ENV{MX_DAEMON_STDERR}) {
3c0d9597 82 open STDERR, ">", $stderr_file
d8985b7d 83 or confess "Could not redirect STDERR to $stderr_file : $!";
129f5643 84 }
d8985b7d 85 else {
4327fe98 86 open(STDERR, "+>&STDIN")
87 or confess "Could not redirect STDERR to /dev/null"; ;
88 }
89
90 # do a little house cleaning ...
91
92 # Avoid 'stdin reopened for output'
93 # warning with newer perls
94 open( NULL, '/dev/null' );
95 <NULL> if (0);
96
97 # return success
98 return 1;
ea9485d8 99}
18cc5c89 100
101sub daemonize {
d8985b7d 102 my ($self, %options) = @_;
103 $self->daemon_fork(%options);
104 $self->daemon_detach(%options);
18cc5c89 105}
106
1071;
d8985b7d 108
18cc5c89 109__END__
110
d8985b7d 111=pod
18cc5c89 112
d8985b7d 113=head1 NAME
18cc5c89 114
d8985b7d 115MooseX::Daemonize::Core - A Role with the core daemonization features
18cc5c89 116
117=head1 SYNOPSIS
d8985b7d 118
119 package My::Daemon;
120 use Moose;
4327fe98 121
d8985b7d 122 with 'MooseX::Daemonize::Core';
4327fe98 123
d8985b7d 124 sub start {
125 my $self = shift;
126 # daemonize me ...
127 $self->daemonize;
128 # return from the parent,...
129 return unless $self->is_daemon;
130 # but continue on in the child (daemon)
131 }
132
18cc5c89 133=head1 DESCRIPTION
134
4327fe98 135This is the basic daemonization Role, it provides a few methods (see
d8985b7d 136below) and the minimum features needed to properly daemonize your code.
137
138=head2 Important Notes
129f5643 139
d8985b7d 140None of the methods in this role will exit the parent process for you,
141it only forks and detaches your child (daemon) process. It is your
142responsibility to exit the parent process in some way.
143
4327fe98 144There is no PID or PID file management in this role, that is your
145responsibility (see some of the other roles in this distro for that).
129f5643 146
18cc5c89 147=head1 ATTRIBUTES
148
149=over
150
129f5643 151=item I<is_daemon (is => rw, isa => Bool)>
18cc5c89 152
d8985b7d 153This attribute is used to signal if we are within the
154daemon process or not.
18cc5c89 155
156=back
157
d8985b7d 158=head1 METHODS
18cc5c89 159
160=over
161
d8985b7d 162=item B<daemon_fork (%options)>
129f5643 163
d8985b7d 164This forks off the child process to be daemonized. Just as with
165the built in fork, it returns the child pid to the parent process,
1660 to the child process. It will also set the is_daemon flag
129f5643 167appropriately.
168
d8985b7d 169The C<%options> available for this function are:
170
171=over 4
172
173=item I<ignore_zombies>
174
175Setting this key to a true value will result in setting the C<$SIG{CHLD}>
176handler to C<IGNORE>. This tells perl to clean up zombie processes. By
177default, and for the most part you don't I<need> it, only when you turn off
178the double fork behavior (with the I<no_double_fork> option) in C<daemon_detach>
179do you sometimes want this behavior.
180
181=back
182
183=item B<daemon_detach (%options)>
129f5643 184
d8985b7d 185This detaches the new child process from the terminal by doing
186the following things.
129f5643 187
188=over 4
189
d8985b7d 190=item Becomes a session leader
18cc5c89 191
d8985b7d 192This detaches the program from the controlling terminal, it is
129f5643 193accomplished by calling POSIX::setsid.
18cc5c89 194
d8985b7d 195=item Performing the double-fork
196
197See below for information on how to change this part of the process.
198
129f5643 199=item Changes the current working directory to "/"
18cc5c89 200
d8985b7d 201This is standard daemon behavior, if you want a different working
202directory then simply change it later in your daemons code.
18cc5c89 203
129f5643 204=item Clears the file creation mask.
18cc5c89 205
129f5643 206=item Closes all open file descriptors.
18cc5c89 207
3c0d9597 208See below for information on how to change this part of the process.
209
129f5643 210=item Reopen STDERR, STDOUT & STDIN to /dev/null
18cc5c89 211
d8985b7d 212This behavior can be controlled slightly though the MX_DAEMON_STDERR
129f5643 213and MX_DAEMON_STDOUT environment variables. It will look for a filename
214in either of these variables and redirect STDOUT and/or STDERR to those
215files. This is useful for debugging and/or testing purposes.
18cc5c89 216
4327fe98 217=back
18cc5c89 218
d8985b7d 219The C<%options> available for this function are:
220
221=over 4
222
223=item I<no_double_fork>
224
225Setting this option to true will cause this method to not perform the
226typical double-fork, which is extra added protection from your process
227accidentally aquiring a controlling terminal. More information can be
228found above, and by Googling "double fork daemonize".
129f5643 229
d8985b7d 230If you the double-fork behavior off, you might want to enable the
231I<ignore_zombies> behavior in the C<daemon_fork> method.
232
3c0d9597 233=item I<dont_close_all_files>
234
235Setting this option to true will cause it to skip closing all the
236filehandles, this is useful if you are opening things like sockets
237and such in the pre-fork.
238
d8985b7d 239=back
240
241B<NOTE>
242
243If called from within the parent process (the is_daemon flag is set to
244false), this method will simply return and do nothing.
245
246=item B<daemonize (%options)>
247
248This will simply call C<daemon_fork> followed by C<daemon_detach>, it will
249pass any C<%options> onto both methods.
18cc5c89 250
251=item meta()
252
253The C<meta()> method from L<Class::MOP::Class>
254
255=back
256
d8985b7d 257=head1 STUFF YOU SHOULD READ
258
259=over 4
260
261=item Note about double fork
262
263Taken from L<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012>
4327fe98 264in a comment entitled I<The second fork _is_ necessary by Jonathan Bartlett>,
265it is not the definitive statement on the issue, but it's clear and well
d8985b7d 266written enough so I decided to reproduce it here.
267
268 The first fork accomplishes two things - allow the shell to return,
269 and allow you to do a setsid().
270
271 The setsid() removes yourself from your controlling terminal. You
272 see, before, you were still listed as a job of your previous process,
273 and therefore the user might accidentally send you a signal. setsid()
274 gives you a new session, and removes the existing controlling terminal.
275
276 The problem is, you are now a session leader. As a session leader, if
277 you open a file descriptor that is a terminal, it will become your
278 controlling terminal (oops!). Therefore, the second fork makes you NOT
279 be a session leader. Only session leaders can acquire a controlling
280 terminal, so you can open up any file you wish without worrying that
281 it will make you a controlling terminal.
282
283 So - first fork - allow shell to return, and permit you to call setsid()
284
285 Second fork - prevent you from accidentally reacquiring a controlling
286 terminal.
287
288That said, you don't always want this to be the behavior, so you are
289free to specify otherwise using the C<%options>.
290
291=item Note about zombies
292
293Doing the double fork (see above) tends to get rid of your zombies since
4327fe98 294by the time you have double forked your daemon process is then owned by
295the init process. However, sometimes the double-fork is more than you
d8985b7d 296really need, and you want to keep your daemon processes a little closer
297to you. In this case you have to watch out for zombies, you can avoid then
298by just setting the C<ignore_zombies> option (see above).
299
300=back
301
302=head1 ENVIRONMENT VARIABLES
303
4327fe98 304These variables are best just used for debugging and/or testing, but
305not used for actual logging. For that, you should reopen STDOUT/ERR on
306your own.
d8985b7d 307
308=over 4
309
310=item B<MX_DAEMON_STDOUT>
311
312A filename to redirect the daemon STDOUT to.
313
314=item B<MX_DAEMON_STDERR>
315
316A filename to redirect the daemon STDERR to.
317
318=back
319
18cc5c89 320=head1 DEPENDENCIES
321
129f5643 322L<Moose::Role>, L<POSIX>
18cc5c89 323
324=head1 INCOMPATIBILITIES
325
18cc5c89 326None reported.
327
18cc5c89 328=head1 BUGS AND LIMITATIONS
329
18cc5c89 330No bugs have been reported.
331
332Please report any bugs or feature requests to
333C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
334L<http://rt.cpan.org>.
335
336=head1 SEE ALSO
337
129f5643 338L<Proc::Daemon>
339
d8985b7d 340This code is based B<HEAVILY> on L<Proc::Daemon>, we originally
129f5643 341depended on it, but we needed some more flexibility, so instead
d8985b7d 342we just stole the code.
18cc5c89 343
344=head1 AUTHOR
345
129f5643 346Stevan Little C<< <stevan.little@iinteractive.com> >>
18cc5c89 347
18cc5c89 348=head1 LICENCE AND COPYRIGHT
349
d8985b7d 350Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights
18cc5c89 351reserved.
352
129f5643 353Portions heavily borrowed from L<Proc::Daemon> which is copyright Earl Hood.
354
18cc5c89 355This module is free software; you can redistribute it and/or
356modify it under the same terms as Perl itself. See L<perlartistic>.
357
18cc5c89 358=head1 DISCLAIMER OF WARRANTY
359
360BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
361FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
362OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
363PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
364EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
365WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
366ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
367YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
368NECESSARY SERVICING, REPAIR, OR CORRECTION.
369
370IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
371WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
372REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
373LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
374OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
375THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
376RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
377FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
378SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
379SUCH DAMAGES.
d8985b7d 380
381=cut