File Coverage

blib/lib/System/Daemon.pm
Criterion Covered Total %
statement 83 104 79.8
branch 28 58 48.2
condition 4 11 36.3
subroutine 15 16 93.7
pod 6 8 75.0
total 136 197 69.0


line stmt bran cond sub pod time code
1             package System::Daemon;
2              
3 3     3   1761 use strict;
  3         3  
  3         114  
4 3     3   15 use warnings;
  3         3  
  3         96  
5              
6 3     3   36 use POSIX;
  3         6  
  3         24  
7 3     3   8760 use Carp;
  3         6  
  3         276  
8 3     3   24 use Fcntl ':flock';
  3         6  
  3         552  
9 3     3   2028 use System::Daemon::Utils;
  3         6  
  3         147  
10              
11 3     3   27 use constant NEW_SUFFIX => ".new";
  3         6  
  3         4443  
12              
13             our $VERSION = 0.14;
14             our $AUTHOR = 'justnoxx';
15             our $ABSTRACT = "Swiss-knife for daemonization";
16              
17             our $DEBUG = 0;
18              
19             sub new {
20 3     3 1 192 my ($class, %params) = @_;
21 3         9 my $self = {};
22 3         12 $self->{daemon_data}->{daemonize} = 1;
23              
24 3 50       21 if ($params{user}) {
25 0         0 $self->{daemon_data}->{user} = $params{user};
26             }
27              
28 3 50       12 if ($params{group}) {
29 0         0 $self->{daemon_data}->{group} = $params{group};
30             }
31            
32 3 50       33 if ($params{pidfile}) {
33 3         12 $self->{pidfile} = $params{pidfile};
34             }
35              
36 3 50       9 if ($params{new}) {
37 0         0 $self->{new} = 1;
38             }
39              
40 3 50       15 if ($params{mkdir}) {
41 0         0 $self->{daemon_data}->{mkdir} = 1;
42             }
43              
44 3 50       9 if ($params{procname}) {
45 0         0 $self->{daemon_data}->{procname} = $params{procname};
46             }
47            
48 3 50       12 if (exists $params{daemonize}) {
49 0         0 $self->{daemon_data}->{daemonize} = $params{daemonize};
50             }
51            
52 3 50       18 if ($params{cleanup_on_destroy}) {
53 0         0 $self->{daemon_data}->{cleanup_on_destroy} = 1;
54             }
55              
56 3         9 bless $self, $class;
57 3         15 return $self;
58             }
59              
60             sub pidfile {
61 16     16 0 32 my $self = shift;
62              
63 16 50       51 return unless $self->{pidfile};
64              
65 16 50       294 $self->{new} ? $self->{pidfile}.NEW_SUFFIX : $self->{pidfile};
66             }
67              
68             sub daemonize {
69 3     3 1 21 my $self = shift;
70              
71 3 50       27 unless ($self->{daemon_data}->{daemonize}) {
72 0         0 carp "Daemonization disabled";
73 0         0 return 1;
74             }
75              
76 3         6 my $dd = $self->{daemon_data};
77              
78 3         12 my $process_object = System::Daemon::Utils::process_object();
79              
80             # wrapper context
81 3         3208956 System::Daemon::Utils::daemon();
82            
83             # let's validate user and group
84 1 50 33     45 if ($dd->{user} || $dd->{group}) {
85             System::Daemon::Utils::validate_user_and_group(
86             user => $dd->{user},
87             group => $dd->{group},
88 0 0       0 ) or do {
89 0         0 croak "Bad user or group";
90             };
91             }
92              
93 1 50       32 if ($self->pidfile) {
94 1         11 System::Daemon::Utils::validate_pid_path($self->pidfile, $dd->{mkdir});
95             }
96 1 50       10 System::Daemon::Utils::make_sandbox($self->pidfile, $dd) if $dd->{mkdir};
97             # daemon context
98 1 50       8 if ($self->pidfile) {
99 1 50       11 croak "Can't overwrite pid file of my alive instance" unless $self->ok_pid();
100 1 50       5 if ($self->pidfile) {
101 1         21 open my $LOCK, $self->pidfile;
102 1         15 my $got_lock = flock($LOCK, LOCK_EX | LOCK_NB);
103 1         11 $self->{_lock} = $LOCK;
104 1 50       9 unless ($got_lock) {
105 0         0 warn "Can't get lock ".$self->pidfile."\n";
106 0         0 exit 1;
107             }
108             }
109 1         15 $self->{original_pid} = $$;
110             System::Daemon::Utils::write_pid($self->pidfile, undef,
111             user => $dd->{user},
112             group => $dd->{group}
113 1         4 );
114             }
115            
116 1 50 33     17 if ($dd->{user} || $dd->{group}) {
117             System::Daemon::Utils::apply_rights(
118             user => $dd->{user},
119             group => $dd->{group}
120 0         0 );
121             }
122              
123 1 50       5 if ($dd->{procname}) {
124 0         0 $0 = $dd->{procname};
125             }
126              
127 1 50       3 if ($dd->{cleanup_on_destroy}) {
128             *{System::Daemon::DESTROY} = sub {
129 0     0   0 my $obj = shift;
130 0         0 $obj->cleanup();
131 0         0 };
132             }
133              
134 1         7 System::Daemon::Utils::suppress();
135 1         31 return 1;
136             }
137              
138              
139             sub exit {
140 1     1 1 1168 my ($self, $code) = @_;
141              
142 1         4 $self->finish();
143              
144 1   50     25 $code ||= 0;
145 1         17 exit $code;
146             }
147              
148              
149             sub ok_pid {
150 1     1 0 4 my ($self, $pidfile) = @_;
151              
152 1   33     14 $pidfile ||= $self->pidfile;
153              
154 1 50       4 return 1 unless $pidfile;
155              
156 1 50       5 unless (System::Daemon::Utils::pid_init($self->pidfile)) {
157 0         0 croak "Can't init pidfile";
158             }
159              
160 1         5 my $pid;
161 1 50       7 unless ($pid = System::Daemon::Utils::read_pid($pidfile)) {
162 1         13 return 1;
163             }
164              
165 0         0 return 1;
166             }
167              
168              
169             sub cleanup {
170 1     1 1 753 my ($self) = @_;
171              
172 1         10 return $self->finish();
173             }
174              
175              
176             sub finish {
177 2     2 1 5 my ($self) = @_;
178              
179 2         10 my $pid = System::Daemon::Utils::read_pid($self->pidfile); # pid missing OR changed
180 2 100       13 if ($pid ne $self->{original_pid}) {
181 1         6 undef $self->{new};
182             }
183              
184 2 50       12 if ($self->pidfile) {
185 2 50       8 if (-e $self->pidfile.NEW_SUFFIX) {
186 0 0       0 rename $self->pidfile.NEW_SUFFIX, $self->pidfile or confess "rename ".$self->pidfile.NEW_SUFFIX.", ".$self->pidfile;
187             }
188             else {
189 2         12 System::Daemon::Utils::delete_pidfile($self->pidfile);
190             }
191             }
192             }
193              
194              
195             sub process_object {
196 1     1 1 45 my ($self) = @_;
197              
198 1         6 return System::Daemon::Utils::process_object();
199             }
200              
201             1;
202              
203             __END__