File Coverage

blib/lib/App/DistSync/Lock.pm
Criterion Covered Total %
statement 12 79 15.1
branch 0 42 0.0
condition 0 23 0.0
subroutine 4 9 44.4
pod 4 4 100.0
total 20 157 12.7


line stmt bran cond sub pod time code
1             package App::DistSync::Lock; # $Id: Lock.pm 5 2014-10-08 16:24:59Z abalama $
2 1     1   55564 use strict;
  1         2  
  1         45  
3            
4             =head1 NAME
5            
6             App::DistSync::Lock - Lock File Manipulation
7            
8             =head1 VERSION
9            
10             Version 1.00
11            
12             =head1 SYNOPSIS
13            
14             use File::Pid;
15            
16             my $lock = new App::DistSync::Lock(
17             file => '/some/file.lock',
18             hold => 3600,
19             pid => $$,
20             );
21            
22             if ( my $pid = $lock->running ) {
23             die "Already running: $num\n";
24             }
25            
26             =head1 DESCRIPTION
27            
28             This module manages a lock file. It will create a lock file,
29             query the process within to discover if it's still running, and remove
30             the lock file. This module based on L and L.
31            
32             =head2 new
33            
34             my $lock = new App::DistSync::Lock;
35            
36             my $lock = new App::DistSync::Lock(
37             file => '/var/run/daemon.pid',
38             hold => 3600,
39             pid => $$,
40             );
41            
42            
43             This constructor takes three optional paramters.
44            
45             C - The name of the lock file to work on. If not specified, a lock
46             file located in current directory will be created that matches
47             C.
48            
49             C - Max amount of seconds before breaking lock (0 for never, default is 3600)
50            
51             C - The pid to write to a new lockfile. If not specified, C<$$> is
52             used when the lock file doesn't exist. When the lock file does exist, the
53             pid inside it is used.
54            
55             =head2 running
56            
57             my $pid = $lock->running;
58             die "Service already running: $pid\n" if $pid;
59            
60             Checks to see if the pricess identified in the lock file is still
61             running. If the process is still running, the pid is returned. Otherwise
62             C or 0 is returned.
63            
64             =head2 status
65            
66             my $status = $lock->status;
67            
68             Returns current status
69            
70             =head2 error
71            
72             my $error = $lock->error;
73            
74             Returns current error message
75            
76             =head1 HISTORY
77            
78             See C file
79            
80             =head1 TO DO
81            
82             See C file
83            
84             =head1 BUGS
85            
86             * none noted
87            
88             =head1 SEE ALSO
89            
90             C, L, L
91            
92             =head1 AUTHOR
93            
94             Serz Minus (Lepenkov Sergey) L Eminus@mail333.comE
95            
96             =head1 COPYRIGHT
97            
98             Copyright (C) 1998-2014 D&D Corporation. All Rights Reserved
99            
100             =head1 LICENSE
101            
102             This program is free software: you can redistribute it and/or modify
103             it under the terms of the GNU General Public License as published by
104             the Free Software Foundation, either version 3 of the License, or
105             (at your option) any later version.
106            
107             This program is distributed in the hope that it will be useful,
108             but WITHOUT ANY WARRANTY; without even the implied warranty of
109             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110             GNU General Public License for more details.
111            
112             See C file
113            
114             =cut
115            
116 1     1   4 use vars qw/$VERSION/;
  1         2  
  1         54  
117             $VERSION = '1.00';
118            
119 1     1   10 use File::Basename qw/basename/;
  1         2  
  1         59  
120 1     1   5 use Carp;
  1         2  
  1         641  
121            
122             sub new {
123 0     0 1   my $class = shift;
124 0           my $stamp = time;
125 0           my ($name) = basename($0);
126            
127 0           my $self = bless({@_,
128             status => 0,
129             error => "",
130             stamp => $stamp,
131             name => $name,
132             run => 0,
133             }, $class);
134            
135 0   0       $self->{file} ||= 'MANIFEST.LOCK';
136 0           my $file = $self->{file};
137            
138 0 0 0       if (exists($self->{pid}) && defined($self->{pid})) {
139 0 0         croak("Incorrect pid specified") unless $self->{pid} =~ /^[0-9]{1,11}$/;
140             } else {
141 0           $self->{pid} = $$;
142             }
143 0           my $pid = $self->{pid};
144            
145 0 0 0       if (exists($self->{hold}) && defined($self->{hold})) {
146 0 0         croak("Incorrect hold specified") unless $self->{hold} =~ /^[0-9]{1,11}$/;
147             } else {
148 0           $self->{hold} = 3600;
149             }
150 0           my $hold = $self->{hold};
151            
152             # Current string
153 0           my $str = sprintf("%d#%d#%s", $pid, $stamp, $name);
154            
155             # Check existing file
156 0           local *RD_LOCK_FILE;
157 0 0 0       if ($file && -e $file) {
158 0 0         unless (open(RD_LOCK_FILE, "<", $file)) {
159 0           $self->{error} = sprintf("Can't open file %s to read: %s", $file, $!);
160 0           return $self;
161             }
162 0           my $l;
163 0           chomp($l = );
164 0 0         $l = "" unless defined $l;
165 0 0         unless (close RD_LOCK_FILE) {
166 0           $self->{error} = sprintf("Can't close file %s: %s", $file, $!);
167 0           return $self;
168             }
169 0 0         if ($l eq $str) {
170             # This procces == Checking process
171 0           $self->{error} = "Process already exists";
172 0           return $self;
173             } else {
174 0           my ($r_pid, $r_stamp, $r_name) = split(/#/, $l);
175 0 0 0       if ($r_pid && $self->running($r_pid)) {
176 0           $self->{run} = $r_pid;
177             # If file too old to be considered stale?
178 0 0 0       if (($hold > 0) && (($stamp - $r_stamp) > $hold)) {
179 0 0         unless (unlink $file) {
180 0           $self->{error} = sprintf("Can't unlink file %s: %s", $file, $!);
181 0           return $self;
182             }
183             } else {
184 0           $self->{error} = "Process #$r_pid already running";
185 0           return $self;
186             }
187             }
188             }
189             }
190            
191             # Create new file
192 0           local *MY_LOCK_FILE;
193 0 0         unless (open(MY_LOCK_FILE, ">", $file)) {
194 0           $self->{error} = sprintf("Can't open file %s to write: %s", $file, $!);
195 0           return $self;
196             }
197 0 0         unless (print MY_LOCK_FILE sprintf("%s\n", $str)) {
198 0           $self->{error} = sprintf("Can't print to file %s: %s", $file, $!);
199 0           return $self;
200             }
201 0 0         unless (close MY_LOCK_FILE) {
202 0           $self->{error} = sprintf("Can't close file %s: %s", $file, $!);
203 0           return $self;
204             }
205            
206 0           $self->{status} = 1;
207 0           return $self;
208             }
209             sub error {
210 0     0 1   my $self = shift;
211             #my $s = shift;
212             #$self->{error} = $s if defined $s;
213 0           return $self->{error};
214             }
215             sub status {
216 0     0 1   my $self = shift;
217             #my $s = shift;
218             #$self->{status} = $s if defined $s;
219 0           return $self->{status};
220             }
221             sub running {
222 0     0 1   my $self = shift;
223 0           my $pid = shift;
224 0 0         $pid = $self->{run} unless defined $pid;
225 0 0         return 0 unless $pid;
226 0 0         unless ($pid =~ /^[0-9]{1,11}$/) {
227 0           carp("Incorrect pid specified");
228 0           return 0;
229             }
230 0 0         return kill(0, $pid)
231             ? $pid
232             : 0;
233             }
234            
235             sub DESTROY {
236 0     0     my $self = shift;
237 0           my $file = $self->{file};
238 0           my $status = $self->{status};
239 0 0 0       return unless $file && $status && -e $file;
      0        
240 0 0         unlink $file or carp(sprintf("Can't unlink file %s: %s", $file, $!));
241             }
242            
243             1;