File Coverage

blib/lib/RSH/LockFile.pm
Criterion Covered Total %
statement 62 77 80.5
branch 15 24 62.5
condition 2 3 66.6
subroutine 10 13 76.9
pod 0 7 0.0
total 89 124 71.7


line stmt bran cond sub pod time code
1             # ------------------------------------------------------------------------------
2             # Copyright © 2003 by Matt Luker. All rights reserved.
3             #
4             # Revision:
5             #
6             # $Header$
7             #
8             # ------------------------------------------------------------------------------
9              
10             # LockFile.pm - implements locking via a lock file (NFS safe).
11             #
12             # @author Matt Luker
13             # @version $Revision: 3248 $
14              
15             # LockFile.pm - implements locking via a lock file (NFS safe).
16             #
17             # Copyright (C) 2003, Matt Luker
18             #
19             # This library is free software; you can redistribute it and/or modify
20             # it under the same terms as Perl itself.
21              
22             # If you have any questions about this software,
23             # or need to report a bug, please contact me.
24             #
25             # Matt Luker
26             # Port Angeles, WA
27             # kostya@redstarhackers.com
28             #
29             # TTGOG
30              
31             package RSH::LockFile;
32              
33 3     3   76786 use 5.008;
  3         11  
  3         111  
34 3     3   16 use strict;
  3         4  
  3         118  
35 3     3   14 use warnings;
  3         6  
  3         907  
36              
37             require Exporter;
38              
39             our @ISA = qw(Exporter);
40              
41             # Items to export into callers namespace by default. Note: do not export
42             # names by default without a very good reason. Use EXPORT_OK instead.
43             # Do not simply export all your public functions/methods/constants.
44              
45             our @EXPORT_OK = qw(
46             );
47              
48             our @EXPORT = qw(
49            
50             );
51              
52 3     3   1479 use RSH::FileUtil qw(get_filehandle);
  3         9  
  3         236  
53 3     3   959 use RSH::Exception;
  3         7  
  3         328  
54 3     3   2210 use Net::Domain qw(hostname hostfqdn hostdomain);
  3         24029  
  3         5400  
55              
56             # We don't want to call hostfqdn a ton of times. The machine name shouldn't change much
57             # (if at all). Using an "our" variable should do the trick. That way it is
58             # initialized once per machine/script.
59             our $FQDN = hostfqdn;
60              
61             # ******************** PUBLIC Class Methods ********************
62              
63             # remove_lock
64             #
65             # Maintenance method to remove stale locks. In theory, you should rarely, if ever,
66             # call this method. If you call this method a lot, you have a bug or a logic problem.
67             # Lock files should not be left lying around.
68             #
69             sub remove_lock {
70 0     0 0 0 my $filename = shift;
71              
72 0 0       0 if (not defined($filename)) { return 0; }
  0         0  
73              
74             # Otherwise ...
75 0         0 my $lock_file = "$filename.lock";
76 0 0       0 if (-e $lock_file) {
77 0         0 my $rc = unlink($lock_file);
78 0         0 return ($rc != 0);
79             }
80 0         0 else { return 1; }
81             }
82              
83              
84             # ******************** CONSTRUCTOR Methods ********************
85              
86             sub new {
87 5     5 0 38 my $class = shift;
88 5         16 my $filename = shift;
89 5         16 my %args = @_;
90            
91 5 50       32 if (not defined($filename)) { die "Cannot create lock file without filename." }
  0         0  
92              
93             # Otherwise ...
94 5         12 my $self = {};
95              
96 5         22 $self->{filename} = $filename;
97 5 100 66     43 if (defined($args{net_fs_safe}) and ($args{net_fs_safe} eq '1')) {
98 1         4 $self->{net_fs_safe} = 1;
99             }
100             else {
101 4         15 $self->{net_fs_safe} = 0;
102             }
103 5         681 $self->{locked} = 0;
104            
105 5         134 bless $self, $class;
106              
107 5         23 return $self;
108             }
109              
110             # ******************** PUBLIC Instance Methods ********************
111              
112             # ******************** Accessor Methods ********************
113              
114             # filename
115             #
116             # Read-only accessor for filename attribute.
117             #
118             sub filename {
119 0     0 0 0 my $self = shift;
120              
121 0         0 return $self->{filename};
122             }
123              
124             # filename
125             #
126             # Read-only accessor for filename attribute.
127             #
128             sub lock_filename {
129 19     19 0 5994 my $self = shift;
130              
131 19         1700 return $self->{filename} .".lock";
132             }
133              
134             # locked
135             #
136             # Read-only accessor for locked flag.
137             #
138             sub locked {
139 0     0 0 0 my $self = shift;
140              
141 0         0 return $self->{locked};
142             }
143              
144             # ******************** Function Methods ********************
145              
146             # lock
147             #
148             # Creates a lock file or dies spectacularly.
149             #
150             sub lock {
151 7     7 0 4616 my $self = shift;
152 7         29 my %args = @_;
153              
154 7         27 my $filename = $self->lock_filename;
155 7         24 $args{exclusive} = 1;
156 7         13 eval {
157 7         55 my $fh = get_filehandle($filename, 'WRITE', %args);
158             # if (defined($args{no_follow}) && ($args{no_follow} eq '1')) {
159             # # Do not follow symlinks--useful for the paranoid in cases of
160             # # sensitive data that should not be moved.
161             # #
162             # # Since a lock file is created in the same directory as the file, this
163             # # would immediately flag a problem where the config file's location
164             # # has been dupped via a symlink to some bogus data somewhere else.
165             # eval {
166             # $fh = new FileHandle $filename, O_CREAT | O_EXCL | O_NOFOLLOW | O_RDWR;
167             # };
168             # if ($@) {
169             # # catches O_NOFOLLOW not being defined--i.e. on filesystems that have
170             # # no concept of symlinks or following. Paranoid or not, if it isn't
171             # # supported we have to just make do
172             # $fh = new FileHandle $filename, O_CREAT | O_EXCL | O_RDWR;
173             # }
174             # } else {
175             # # Just get a file handle and don't worry about whether we are following
176             # # symlinks
177             # $fh = new FileHandle $filename, O_CREAT | O_EXCL | O_RDWR;
178             # }
179              
180 7 100       43 if (not defined($fh)) { die "Unable to create lock file."; }
  2         35  
181 5 100       30 if ($self->{net_fs_safe}) {
182 1         13 print $fh $FQDN, "-", $$;
183             }
184             else {
185 4         188 print $fh $$;
186             }
187 5         37 $fh->close;
188 5         626 $self->{locked} = 1;
189             };
190 7 100       749 if ($@) { die new RSH::Exception message => $@; }
  2         23  
191             }
192              
193             # unlock
194             #
195             # Removes a lock file or dies spectacularly.
196             #
197             sub unlock {
198 5     5 0 2555 my $self = shift;
199              
200 5         20 my $filename = $self->{filename} .".lock";
201              
202 5 50       236 if (-e $filename) {
203             # only try to remove the lock if it is there
204             # TODO should toss a warning?
205 5         10 eval {
206 5         187 open FH, "<". $filename;
207              
208 5         120 my $id_val = <FH>;
209              
210 5         67 close FH;
211              
212 5         20 my $id = $$;
213 5 100       24 if ($self->{net_fs_safe}) {
214 1         6 $id = "$FQDN-$$";
215             }
216 5 50       22 if ($id_val eq $id) {
217 5 50       445 unlink($filename) or die new RSH::Exception message => "Unable to remove lock file for ". $self->filename;
218 5         21 $self->{locked} = 0;
219             } else {
220 0         0 die new RSH::Exception message => "Do not own lock file for ". $self->filename ."; unlock failed.";
221             }
222             };
223 5 50       19 if ($@) { die new RSH::Exception message => $@; }
  0         0  
224             }
225            
226             # you get here and it is unlocked ...
227 5         67 $self->{locked} = 1;
228             }
229              
230              
231             # #################### LockFile.pm ENDS ####################
232             1;
233              
234             # ------------------------------------------------------------------------------
235             #
236             # $Log$
237             # Revision 1.3 2003/10/22 20:51:02 kostya
238             # Removed OS-specifc assumptions or code
239             #
240             # Revision 1.2 2003/10/15 01:07:00 kostya
241             # documentation and license updates--everything is Artistic.
242             #
243             # Revision 1.1.1.1 2003/10/13 01:38:04 kostya
244             # First import
245             #
246             #
247             # ------------------------------------------------------------------------------