File Coverage

blib/lib/Acme/Ghost/FilePid.pm
Criterion Covered Total %
statement 80 85 94.1
branch 32 46 69.5
condition 12 21 57.1
subroutine 15 15 100.0
pod 8 8 100.0
total 147 175 84.0


line stmt bran cond sub pod time code
1             package Acme::Ghost::FilePid;
2 4     4   642380 use strict;
  4         7  
  4         167  
3 4     4   1092 use utf8;
  4         629  
  4         49  
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             Acme::Ghost::FilePid - The Pid File simple interface
10              
11             =head1 SYNOPSIS
12              
13             use Acme::Ghost::FilePid;
14              
15             my $fp = Acme::Ghost::FilePid->new (
16             file => '/some/file.pid',
17             );
18              
19             if ( my $num = $fp->running ) {
20             die "Already running: $num";
21             } else {
22             $fp->save;
23             # . . .
24             $fp->remove;
25             }
26              
27             ... or with autoremove:
28              
29             my $fp = Acme::Ghost::FilePid->new (
30             file => '/some/file.pid',
31             autoremove => 1,
32             );
33             die "Already running" if $fp->running;
34             $fp->save;
35             # . . .
36              
37             ... or with autosave and autoremove
38              
39             my $fp = Acme::Ghost::FilePid->new (
40             file => '/some/file.pid',
41             auto => 1,
42             );
43             die "Already running" if $fp->running;
44             # . . .
45              
46             =head1 DESCRIPTION
47              
48             This software manages a pid file for you. It will create a pid file,
49             query the process within to discover if it's still running, and remove
50             the pid file.
51              
52             =head2 new
53              
54             my $fp = Acme::Ghost::FilePid->new;
55              
56             my $fp = Acme::Ghost::FilePid->new(
57             file => '/var/run/daemon.pid',
58             );
59              
60             my $fp = Acme::Ghost::FilePid->new(
61             file => '/var/run/daemon.pid',
62             pid => '145',
63             autoremove => 1,
64             );
65              
66             This constructor takes three optional paramters.
67              
68             C - The name of the pid file to work on. If not specified, a pid
69             file located in C. So, for example, if C<$0> is F<~/bin/sig.pl>,
70             the pid file will be F.
71              
72             C - The pid to write to a new pidfile. If not specified, C<$$> is
73             used when the pid file doesn't exist. When the pid file does exist, the
74             pid inside it is used.
75              
76             C - Auto-remove flag. If this flag specified as true, then
77             will be removed the pid file automatically on DESTROY phase. Default: false
78              
79             C - Auto-save flag. If this flag specified as true, then
80             will be saved the pid file automatically while instance create. Default: false
81              
82             C - this flag forced sets C and C flags. Default: false
83              
84             =head2 file
85              
86             $fp->file("/var/run/file.pid");
87             my $pidfile = $fp->file;
88              
89             Accessor/mutator for the filename used as the pid file.
90              
91             =head2 load
92              
93             $fp->load;
94              
95             Load owner pid from file.
96             On success, the object is returned. On failure, C is
97             returned.
98              
99             =head2 owner
100              
101             $fp->owner(123);
102             my $owner = $fp->owner;
103              
104             Accessor/mutator for the pid being saved to the pid file.
105              
106             =head2 pid
107              
108             $fp->pid(123);
109             my $pid = $fp->pid;
110              
111             Accessor/mutator for the pid being saved to the pid file.
112              
113             =head2 remove
114              
115             $fp->remove;
116              
117             Removes the pid file from disk. Returns true on success, false on
118             failure.
119              
120             =head2 running
121              
122             my $pid = $fp->running;
123             die "Service already running: $pid" if $pid;
124              
125             Checks to see if the pricess identified in the pid file is still
126             running. If the process is still running, the pid is returned. Otherwise
127             C is returned.
128              
129             =head2 save
130              
131             $fp->save;
132              
133             Writes the pid file to disk, inserting the pid inside the file.
134             On success, the object is returned. On failure, C is
135             returned.
136              
137             =head1 HISTORY
138              
139             See C file
140              
141             =head1 TO DO
142              
143             See C file
144              
145             =head1 SEE ALSO
146              
147             L
148              
149             =head1 AUTHOR
150              
151             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
152              
153             =head1 COPYRIGHT
154              
155             Copyright (C) 1998-2026 D&D Corporation
156              
157             =head1 LICENSE
158              
159             This program is distributed under the terms of the Artistic License Version 2.0
160              
161             See the C file or L for details
162              
163             =cut
164              
165 4     4   388 use Carp qw/croak/;
  4         9  
  4         359  
166 4     4   26 use File::Spec;
  4         11  
  4         209  
167 4     4   25 use File::Basename qw//;
  4         8  
  4         79  
168 4     4   1988 use IO::File qw//;
  4         40932  
  4         4317  
169              
170             sub new {
171 8     8 1 1007668 my $class = shift;
172 8 50       202 my $args = @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {};
  0 50       0  
173 8         153 my $self = bless {%$args}, $class;
174 8 100 100     76 $self->{autoremove} ||= $args->{auto} ? 1 : 0;
175 8 100 66     98 $self->{autosave} ||= $args->{auto} ? 1 : 0;;
176 8   33     29 $self->{file} //= File::Spec->catfile(File::Spec->tmpdir(), sprintf("%s.pid", File::Basename::basename($0)));
177 8   33     201 $self->{pid} ||= $$; # Current PID
178 8   50     80 $self->{owner} ||= 0; # Owner PID
179 8         19 $self->{is_running} = -1; # Unknown (is as running)
180 8 100       25 if ($self->{autosave}) {
181 2 50       8 return $self->running ? $self : $self->save;
182             }
183 6         49 return $self->load;
184             }
185              
186             sub file {
187 31     31 1 52 my $self = shift;
188 31 50       130 if (scalar(@_) >= 1) {
189 0         0 $self->{file} = shift;
190 0         0 return $self;
191             }
192 31         98 return $self->{file};
193             }
194             sub pid {
195 12     12 1 54 my $self = shift;
196 12 50       34 if (scalar(@_) >= 1) {
197 0         0 $self->{pid} = shift;
198 0         0 return $self;
199             }
200 12         104 return $self->{pid};
201             }
202             sub owner {
203 37     37 1 71 my $self = shift;
204 37 100       92 if (scalar(@_) >= 1) {
205 23         52 $self->{owner} = shift;
206 23         50 return $self;
207             }
208 14         170 return $self->{owner};
209             }
210             sub running {
211 11     11 1 70 my $self = shift;
212 11   100     42 my $owner = $self->load->owner || 0; # Get PID from file
213 11 50       210 my $r = kill(0, $owner) ? $owner : undef;
214 11 100       31 $self->{is_running} = $r ? 1 : 0;
215 11         87 return $r; # Is running?
216             }
217             sub remove {
218 7     7 1 14 my $self = shift;
219 7         22 my $file = $self->file;
220 7 50       173 return $self unless -e $file;
221 7         962 unlink $file;
222 7         42 $self->owner(0); # Set owner PID to 0
223 7         481 return $self;
224             }
225             sub save {
226 7     7 1 42 my $self = shift;
227 7         24 my $file = $self->file;
228 7   33     29 my $pid = $self->pid || $$;
229 7         32 $self->owner($pid); # Set owner PID as current PID
230              
231             # Save PID to file
232 7         71 my $fh = IO::File->new($file, "w");
233 7 50       2197 croak qq/Can't open file "$file": $!/ unless defined $fh;
234 7 50       131 $fh->write("$pid\n") or croak qq/Can't write to file "$file": $!/;
235 7         991 undef $fh; # automatically closes the file
236              
237             # Returns self
238 7         58 return $self;
239             }
240             sub load {
241 17     17 1 31 my $self = shift;
242 17         61 my $file = $self->file;
243 17 100       614 return $self unless -e $file;
244              
245             # Read file
246 9         46 my $ret = my $content = '';
247 9         81 my $fh = IO::File->new($file, "r");
248 9 50       1243 croak qq/Can't open file "$file": $!/ unless defined $fh;
249 9         58 while ($ret = $fh->read(my $buf, 255)) { $content .= $buf }
  9         442  
250 9 50       110 croak qq/Can't read from file "$file": $!/ unless defined $ret;
251 9         132 undef $fh; # automatically closes the file
252              
253             # Set loaded PID as owner
254 9         23 chomp $content;
255 9 50 50     135 $self->owner(($content || 0) * 1) if $content =~ /^\d+$/;
256              
257             # Returns object
258 9         31 return $self;
259             }
260             sub DESTROY {
261 8     8   13824 my $self = shift;
262 8 50       33 return unless $self;
263 8 100       32 return unless $self->{autoremove};
264 6 100       39 return $self->remove unless $self->{is_running};
265 5 50       19 return unless $self->{owner};
266 5 100       197 $self->remove if $self->{owner} == $self->{pid};
267             }
268              
269             1;
270              
271             __END__