File Coverage

blib/lib/MooseX/Daemonize/Core.pm
Criterion Covered Total %
statement 54 54 100.0
branch 23 32 71.8
condition 1 3 33.3
subroutine 10 10 100.0
pod 3 3 100.0
total 91 102 89.2


line stmt bran cond sub pod time code
1 13     13   802000 use strict;
  13         28  
  13         313  
2 13     13   45 use warnings;
  13         17  
  13         529  
3             package MooseX::Daemonize::Core;
4             # ABSTRACT: A Role with the core daemonization features
5              
6             our $VERSION = '0.21';
7              
8 13     13   2018 use MooseX::Getopt; # to load the NoGetopt metaclass
  13         2041097  
  13         294  
9 13     13   56 use Moose::Role;
  13         16  
  13         59  
10 13     13   48358 use POSIX ();
  13         54102  
  13         322  
11 13     13   61 use namespace::autoclean;
  13         13  
  13         75  
12              
13             has is_daemon => (
14             # NOTE:
15             # this should never be accessible
16             # from the command line
17             # - SL
18             metaclass => 'NoGetopt',
19             isa => 'Bool',
20             is => 'rw',
21             default => sub { 0 },
22             );
23              
24             has ignore_zombies => (
25             metaclass => 'Getopt',
26             isa => 'Bool',
27             is => 'rw',
28             default => sub { 0 },
29             );
30              
31             has no_double_fork => (
32             metaclass => 'Getopt',
33             isa => 'Bool',
34             is => 'rw',
35             default => sub { 0 },
36             );
37              
38             has dont_close_all_files => (
39             metaclass => 'Getopt',
40             isa => 'Bool',
41             is => 'rw',
42             default => sub { 0 },
43             );
44              
45             sub _get_options {
46 17     17   33 my ($self, %options) = @_;
47             # backwards compatibility.. old code might be calling daemon_fork/_detach with options
48 17         53 foreach my $opt (qw( ignore_zombies no_double_fork dont_close_all_files )) {
49 51 100       202 $self->$opt( $options{ $opt } ) if ( defined $options{ $opt } );
50             }
51             }
52              
53              
54             sub daemon_fork {
55 11     11 1 69 my ($self, %options) = @_;
56              
57 11         70 $self->_get_options( %options );
58              
59 11 100       369 $SIG{CHLD} = 'IGNORE'
60             if $self->ignore_zombies;;
61              
62 11 100       11622 if (my $pid = fork) {
63 5         185 return $pid;
64             }
65             else {
66 6         920 $self->is_daemon(1);
67 6         56 return;
68             }
69             }
70              
71             sub daemon_detach {
72 11     11 1 47 my ($self, %options) = @_;
73              
74 11 100       650 return unless $self->is_daemon; # return if parent ...
75              
76 6         58 $self->_get_options( %options );
77             # now we are in the daemon ...
78              
79 6 50       472 (POSIX::setsid) # set session id
80             || confess "Cannot detach from controlling process";
81              
82 6 50       406 unless ( $self->no_double_fork ) {
83 6         244 $SIG{'HUP'} = 'IGNORE';
84 6 100       4994 fork && exit;
85             }
86              
87 3         175 chdir '/'; # change to root directory
88 3         51 umask 0; # clear the file creation mask
89              
90 3 50       623 unless ( $self->dont_close_all_files ) {
91             # get the max number of possible file descriptors
92 3         136 my $openmax = POSIX::sysconf( &POSIX::_SC_OPEN_MAX );
93 3 50 33     142 $openmax = 64 if !defined($openmax) || $openmax < 0;
94              
95             # close them all
96 3         643847 POSIX::close($_) foreach (0 .. $openmax);
97             }
98              
99             # fixup STDIN ...
100              
101 3 50       208 open(STDIN, "+>/dev/null")
102             or confess "Could not redirect STDOUT to /dev/null";
103              
104             # fixup STDOUT ...
105              
106 3 100       46 if (my $stdout_file = $ENV{MX_DAEMON_STDOUT}) {
107 2 50       212 open STDOUT, ">", $stdout_file
108             or confess "Could not redirect STDOUT to $stdout_file : $!";
109             }
110             else {
111 1 50       17 open(STDOUT, "+>&STDIN")
112             or confess "Could not redirect STDOUT to /dev/null";
113             }
114              
115             # fixup STDERR ...
116              
117 3 100       54 if (my $stderr_file = $ENV{MX_DAEMON_STDERR}) {
118 2 50       96 open STDERR, ">", $stderr_file
119             or confess "Could not redirect STDERR to $stderr_file : $!";
120             }
121             else {
122 1 50       8 open(STDERR, "+>&STDIN")
123             or confess "Could not redirect STDERR to /dev/null"; ;
124             }
125              
126             # do a little house cleaning ...
127              
128             # Avoid 'stdin reopened for output'
129             # warning with newer perls
130 3         34 open( NULL, '/dev/null' );
131 3         6 <NULL> if (0);
132              
133             # return success
134 3         71 return 1;
135             }
136              
137             sub daemonize {
138 11     11 1 3433 my ($self, %options) = @_;
139 11         94 $self->daemon_fork(%options);
140 11         1860 $self->daemon_detach(%options);
141             }
142              
143             1;
144              
145             __END__
146              
147             =pod
148              
149             =encoding UTF-8
150              
151             =head1 NAME
152              
153             MooseX::Daemonize::Core - A Role with the core daemonization features
154              
155             =head1 VERSION
156              
157             version 0.21
158              
159             =head1 SYNOPSIS
160              
161             package My::Daemon;
162             use Moose;
163              
164             with 'MooseX::Daemonize::Core';
165              
166             sub start {
167             my $self = shift;
168             # daemonize me ...
169             $self->daemonize;
170             # return from the parent,...
171             return unless $self->is_daemon;
172             # but continue on in the child (daemon)
173             }
174              
175             =head1 DESCRIPTION
176              
177             This is the basic daemonization Role, it provides a few methods (see
178             below) and the minimum features needed to properly daemonize your code.
179              
180             =head2 Important Notes
181              
182             None of the methods in this role will exit the parent process for you,
183             it only forks and detaches your child (daemon) process. It is your
184             responsibility to exit the parent process in some way.
185              
186             There is no PID or PID file management in this role, that is your
187             responsibility (see some of the other roles in this distro for that).
188              
189             =head1 ATTRIBUTES
190              
191             =over
192              
193             =item I<is_daemon (is => rw, isa => Bool)>
194              
195             This attribute is used to signal if we are within the
196             daemon process or not.
197              
198             =item I<no_double_fork (is => rw, isa => Bool)>
199              
200             Setting this attribute to true will cause this method to not perform the
201             typical double-fork, which is extra added protection from your process
202             accidentally acquiring a controlling terminal. More information can be
203             found above, and by Googling "double fork daemonize".
204              
205             If you the double-fork behavior off, you might want to enable the
206             I<ignore_zombies>.
207              
208             =item I<ignore_zombies (is => rw, isa => Bool)>
209              
210             Setting this attribute to a true value will result in setting the C<$SIG{CHLD}>
211             handler to C<IGNORE>. This tells perl to clean up zombie processes. By
212             default, and for the most part you don't I<need> it, only when you turn off
213             the double fork behavior (with the I<no_double_fork> attribute)
214             do you sometimes want this behavior.
215              
216             =item I<dont_close_all_files (is => rw, isa => Bool)>
217              
218             Setting this attribute to true will cause it to skip closing all the
219             filehandles. This is useful if you are opening things like sockets
220             and such in the pre-fork.
221              
222             =back
223              
224             =head1 METHODS
225              
226             =over
227              
228             =item B<daemon_fork (?%options)>
229              
230             This forks off the child process to be daemonized. Just as with
231             the built in fork, it returns the child pid to the parent process,
232             0 to the child process. It will also set the is_daemon flag
233             appropriately.
234              
235             The C<%options> argument remains for backwards compatibility, but
236             it is suggested that you use the attributes listed above instead.
237              
238             =item B<daemon_detach (?%options)>
239              
240             This detaches the new child process from the terminal by doing
241             the following things.
242              
243             The C<%options> argument remains for backwards compatibility, but
244             it is suggested that you use the attributes listed above instead.
245              
246             =over 4
247              
248             =item Becomes a session leader
249              
250             This detaches the program from the controlling terminal, it is
251             accomplished by calling C<POSIX::setsid>.
252              
253             =item Performing the double-fork
254              
255             See below for information on how to change this part of the process.
256              
257             =item Changes the current working directory to "/"
258              
259             This is standard daemon behavior, if you want a different working
260             directory then simply change it later in your daemons code.
261              
262             =item Clears the file creation mask.
263              
264             =item Closes all open file descriptors.
265              
266             See the I<dont_close_all_files> attribute for information on how to
267             change this part of the process.
268              
269             =item Reopen STDERR, STDOUT & STDIN to /dev/null
270              
271             This behavior can be controlled slightly though the C<MX_DAEMON_STDERR>
272             and C<MX_DAEMON_STDOUT> environment variables. It will look for a filename
273             in either of these variables and redirect C<STDOUT> and/or C<STDERR> to those
274             files. This is useful for debugging and/or testing purposes.
275              
276             B<NOTE>
277              
278             If called from within the parent process (the C<is_daemon> flag is set to
279             false), this method will simply return and do nothing.
280              
281             =item B<daemonize (?%options)>
282              
283             This will simply call C<daemon_fork> followed by C<daemon_detach>.
284              
285             The C<%options> argument remains for backwards compatibility, but
286             it is suggested that you use the attributes listed above instead.
287              
288             =item meta()
289              
290             The C<meta()> method from L<Class::MOP::Class>
291              
292             =back
293              
294             =back
295              
296             =head1 STUFF YOU SHOULD READ
297              
298             =over 4
299              
300             =item Note about double fork
301              
302             Taken from L<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012>
303             in a comment entitled I<The second fork _is_ necessary by Jonathan Bartlett>,
304             it is not the definitive statement on the issue, but it's clear and well
305             written enough so I decided to reproduce it here.
306              
307             The first fork accomplishes two things - allow the shell to return,
308             and allow you to do a setsid().
309              
310             The setsid() removes yourself from your controlling terminal. You
311             see, before, you were still listed as a job of your previous process,
312             and therefore the user might accidentally send you a signal. setsid()
313             gives you a new session, and removes the existing controlling terminal.
314              
315             The problem is, you are now a session leader. As a session leader, if
316             you open a file descriptor that is a terminal, it will become your
317             controlling terminal (oops!). Therefore, the second fork makes you NOT
318             be a session leader. Only session leaders can acquire a controlling
319             terminal, so you can open up any file you wish without worrying that
320             it will make you a controlling terminal.
321              
322             So - first fork - allow shell to return, and permit you to call setsid()
323              
324             Second fork - prevent you from accidentally reacquiring a controlling
325             terminal.
326              
327             That said, you don't always want this to be the behavior, so you are
328             free to specify otherwise using the I<no_double_fork> attribute.
329              
330             =item Note about zombies
331              
332             Doing the double fork (see above) tends to get rid of your zombies since
333             by the time you have double forked your daemon process is then owned by
334             the init process. However, sometimes the double-fork is more than you
335             really need, and you want to keep your daemon processes a little closer
336             to you. In this case you have to watch out for zombies, you can avoid then
337             by just setting the I<ignore_zombies> attribute (see above).
338              
339             =back
340              
341             =head1 ENVIRONMENT VARIABLES
342              
343             These variables are best just used for debugging and/or testing, but
344             not used for actual logging. For that, you should reopen C<STDOUT>/C<STDERR> on
345             your own.
346              
347             =over 4
348              
349             =item B<MX_DAEMON_STDOUT>
350              
351             A filename to redirect the daemon C<STDOUT> to.
352              
353             =item B<MX_DAEMON_STDERR>
354              
355             A filename to redirect the daemon C<STDERR> to.
356              
357             =back
358              
359             =head1 DEPENDENCIES
360              
361             L<Moose::Role>, L<POSIX>
362              
363             =head1 INCOMPATIBILITIES
364              
365             =head1 SEE ALSO
366              
367             L<Proc::Daemon>
368              
369             This code is based B<HEAVILY> on L<Proc::Daemon>, we originally
370             depended on it, but we needed some more flexibility, so instead
371             we just stole the code.
372              
373             =head1 COPYRIGHT AND LICENCE
374              
375             Portions heavily borrowed from L<Proc::Daemon> which is copyright Earl Hood.
376              
377             =head1 SUPPORT
378              
379             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Daemonize>
380             (or L<bug-MooseX-Daemonize@rt.cpan.org|mailto:bug-MooseX-Daemonize@rt.cpan.org>).
381              
382             There is also a mailing list available for users of this distribution, at
383             L<http://lists.perl.org/list/moose.html>.
384              
385             There is also an irc channel available for users of this distribution, at
386             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
387              
388             =head1 AUTHORS
389              
390             =over 4
391              
392             =item *
393              
394             Stevan Little <stevan.little@iinteractive.com>
395              
396             =item *
397              
398             Chris Prather <chris@prather.org>
399              
400             =back
401              
402             =head1 COPYRIGHT AND LICENCE
403              
404             This software is copyright (c) 2007 by Chris Prather.
405              
406             This is free software; you can redistribute it and/or modify it under
407             the same terms as the Perl 5 programming language system itself.
408              
409             =cut