App-plockf
view release on metacpan or search on metacpan
#
# Author: Slaven Rezic
#
# Copyright (C) 2016,2017 Slaven Rezic. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Mail: slaven@rezic.de
# WWW: http://www.rezic.de/eserte/
#
use strict;
use Errno;
use Fcntl ();
use Getopt::Long;
use vars qw($VERSION);
$VERSION = "0.04";
# sysexits(3) constants
use constant EX_USAGE => 64;
use constant EX_UNAVAILABLE => 69;
use constant EX_SOFTWARE => 70;
use constant EX_OSERR => 71;
use constant EX_CANTCREAT => 73;
use constant EX_TEMPFAIL => 75;
sub set_impl ();
sub handle_error ($);
sub progname ();
sub usage (;$) {
my $msg = shift;
if ($msg) {
warn $msg, "\n";
}
warn "usage: " . progname . " [-kns] [-t seconds] file command [arguments]\n";
exit EX_USAGE;
}
my $timeout;
my $keep;
my $silent;
my $nocreat;
Getopt::Long::Configure('require_order');
GetOptions(
'help|h|?' => sub { usage },
'k' => \$keep,
'n' => \$nocreat,
's' => \$silent,
't=f' => \$timeout,
'v|version' => sub {
print "plockf version $VERSION\n";
exit 0;
},
);
if (defined $timeout && $timeout < 0) {
usage "Timeout must be positive";
}
my $lock_file = shift
or usage "Lock file is not specified";
my $cmd = shift
or usage "Command is not specified";
set_impl;
my $timed_out;
my $alarm;
if (defined $timeout && $timeout > 0) {
$SIG{ALRM} = sub { $timed_out = 1 };
if ($timeout !~ m{^\d+$} && eval { require Time::HiRes; Time::HiRes->VERSION(1.9716); Time::HiRes->import('ualarm'); 1 }) { # do we need and can we do floating point timeouts?
$alarm = \&Time::HiRes::alarm;
} else {
if ($timeout < 1) { $timeout = 1 }
$alarm = sub { alarm($_[0]) };
}
$alarm->($timeout);
}
my $lock_fh = acquire_lock(0);
while (!$lock_fh && !$timed_out && (!defined $timeout || $timeout > 0)) {
if ($^O eq 'MSWin32') {
# systems where alarm() does not work with blocking syscalls
wait_for_lock_nonblocking();
$lock_fh = acquire_lock(0);
} elsif ($keep) {
$lock_fh = acquire_lock(1);
} else {
wait_for_lock();
$lock_fh = acquire_lock(0);
}
}
if ($alarm) {
$alarm->(0);
}
if (!$lock_fh) {
handle_error EX_TEMPFAIL;
}
my $do_cleanup = !$keep;
$SIG{TERM} = sub { exit }; # would run END block
system { $cmd } $cmd, @ARGV;
if ($? == -1) {
warn progname . ": calling '$cmd @ARGV' failed: $!\n";
exit EX_OSERR;
} elsif ($? & 127) {
exit EX_SOFTWARE;
} else {
my $exit_code = $? >> 8;
exit $exit_code;
}
END {
( run in 0.950 second using v1.01-cache-2.11-cpan-39bf76dae61 )