-
Notifications
You must be signed in to change notification settings - Fork 44
/
flock.pl
executable file
·105 lines (89 loc) · 3.15 KB
/
flock.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/perl -T
#
# Author: Hari Sekhon
# Date: 2012-02-02 13:24:30 +0000 (Thu, 02 Feb 2012)
#
# https://github.com/HariSekhon/DevOps-Perl-tools
#
# License: see accompanying Hari Sekhon LICENSE file
#
# If you're using my code you're welcome to connect with me on LinkedIn
# and optionally send me feedback to help improve or steer this or other code I publish
#
# https://www.linkedin.com/in/HariSekhon
#
$DESCRIPTION = "Arbitrary locking utility
Gains an exclusive lock and executes the given command, then releases the lock
Aborts without executing the command if the lock is already in use to prevent commands clashing";
$VERSION = "1.2.1";
use strict;
use warnings;
use File::Basename;
use Getopt::Long qw(:config bundling);
use Fcntl ':flock';
BEGIN {
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
$ENV{'PATH'} = '/bin:/usr/bin';
$| = 1;
}
my $progname = basename $0;
my $command;
my $default_timeout = 10;
my $help;
my $lockfile;
my $max_timeout = 3600;
my $timeout = $default_timeout;
my $verbose = 0;
my $version;
sub vlog{
print "@_\n" if $verbose;
}
sub usage {
print STDERR "@_\n\n" if @_;
print STDERR "$main::DESCRIPTION\n\n" if $main::DESCRIPTION;
print STDERR "usage: $progname [ options ]
-c --command Command to run if lock succeeds
-l --lockfile Lockfile to use. This will be created if it doesn't exist, will not be overwritten or appended to and will not be removed for safety
-t --timeout Timeout in secs (default $default_timeout)
-v --verbose Verbose mode
-V --version Print version and exit
-h --help --usage Print this help
\n";
exit 3;
}
GetOptions (
"c|cmd|command=s" => \$command,
"l|lock|lockfile=s" => \$lockfile,
"h|help|usage" => \$help,
"t|timeout=i" => \$timeout,
"v|verbose+" => \$verbose,
"V|version" => \$version,
) or usage;
defined($help) and usage;
defined($version) and die "$progname version $main::VERSION\n";
defined($command) || usage "command not specified";
defined($lockfile) || usage "lockfile not specified";
# Allow all chars for cmd since this is the point of the code
$command =~ /^(.+)$/;
$command = $1;
$lockfile =~ /^([\/\w\s_\.\*\+-]+)$/ or die "Invalid lockfile specified, did not match regex\n";
$lockfile = $1;
$timeout =~ /^\d+$/ || usage "timeout value must be a positive integer\n";
($timeout >= 1 && $timeout <= $max_timeout) || usage "timeout value must be between 1 - $max_timeout secs\n";
vlog "verbose mode on";
$SIG{ALRM} = sub {
die "timed out after $timeout seconds\n";
};
vlog "setting timeout to $timeout secs\n";
alarm($timeout);
my $tmpfh;
if(-f $lockfile){
vlog "opening lock file '$lockfile'\n";
open $tmpfh, "<", $lockfile or die "Error: failed to open lock file '$lockfile': $!\n";
} else {
vlog "creating lock file '$lockfile'\n";
open $tmpfh, "+>", $lockfile or die "Error: failed to create lock file '$lockfile': $!\n";
}
flock($tmpfh, LOCK_EX | LOCK_NB) or die "Failed to aquire a lock on lock file '$lockfile', another process must be running, aborting\n";
system($command);
exit $? >> 8;