!@ARGV or fail "bad usage: no non-option arguments permitted";
-#---------- main program ----------
-
-chdir $cachedir or fail "chdir $cachedir: $!";
+#---------- utility functions ----------
-our ($service,$specpath,$spechost,$subdir);
-our ($tmpd,$gitd,$lock);
-our ($fetch,$url);
+sub lockfile ($$) {
+ my ($fh, $fn, $flockmode) = @_;
+ for (;;) {
+ close $fh;
+ open $fh, '+>', $fn or fail "open/create $fn for lock: $!";
+ if (!flock $fh, $lockmode) {
+ if ($lockmode & LOCK_NB and $! == EWOULDBLOCK) {
+ return 0; # ok then
+ }
+ fail "lock $fn".
+ (($flockmode & ~LOCK_NB) == LOCK_SH ? " (shared)" : "").
+ ": $!";
+ }
+ stat $fh or fail "stat opened $fn: $!";
+ my $fh_ino = ((stat _)[1]);
+ if (!stat $fn) {
+ $! == ENOENT or fail "stat $fn: $!";
+ next;
+ }
+ my $fn_ino = ((stat _)[1]);
+ return 1 if $fn_ino == $fh_ino;
+ # oh dear
+ }
+}
sub xread {
my $length = shift;
return $buffer;
}
+#---------- main program ----------
+
+chdir $cachedir or fail "chdir $cachedir: $!";
+
+our ($service,$specpath,$spechost,$subdir);
+our ($tmpd,$gitd,$lock);
+our ($fetch,$url);
+
sub servinfo ($) {
my ($msg) = @_;
logm 'info', "service `$specpath': $msg";
}
sub clonefetch () {
- open LOCK, "+>", $lock or fail "open/create $lock: $!";
- flock LOCK, LOCK_EX or fail "lock exclusive $lock: $!";
+ lockfile \*LOCK, $lock, LOCK_EX;
- my $exists = stat $gitd;
- $exists or $!==ENOENT or fail "stat $gitd: $!";
+ my $exists = lstat $gitd;
+ $exists or $!==ENOENT or fail "lstat $gitd: $!";
our $fetchfail = '';
}
servinfo "sharing";
- flock LOCK, LOCK_UN or fail "unlock $lock: $!";
- flock LOCK, LOCK_SH or fail "lock shared $lock: $!";
- # actually, just relocking as shared would have the same semantics
- # but it's best to be explicit
+ lockfile \*LOCK, $lock, LOCK_SH; # NB releases and relocks
if (chdir $gitd) {
return 1;
sub housekeeping () {
foreach $lock (<[a-z]*\\.lock>) {
if (!lstat $lock) {
- $! == ENOENT or fail "housekeeping: $lock: stat: $!";
+ $! == ENOENT or fail "housekeeping: $lock: lstat: $!";
next;
}
if (-M _ <= $treeexpiredays) {
sub housekeepingcheck ($$) {
my ($dofork, $force) = @_;
- open HLOCK, "+>", "Housekeeping.lock"
or fail "open/create Housekeeping.lock: $!";
if (!$force) {
- if (flock HLOCK, LOCK_EX|LOCK_NB) {
+ if (!lockfile \*HLOCK, "Housekeeping.lock", LOCK_EX|LOCK_NB) {
logm 'debug', "housekeeping lock taken, not running";
close HLOCK;
return 0;
if ($force) {
logm 'info', "housekeeping forced";
} elsif (!lstat "Housekeeping.stamp") {
- $! == ENOENT or fail "stat housekeeping.stamp: $!";
+ $! == ENOENT or fail "lstat Housekeeping.stamp: $!";
logm 'info', "housekeeping stamp missing, will run";
} elsif (-M _ <= $housekeepingthreshdays) {
logm 'debug', "housekeeping done recently";