+ return 0;
+}
+
+sub hkfail ($) { my ($msg) = @_; fail "housekeeping: $msg"; }
+
+sub housekeeping () {
+ logm 'info', "housekeeping started";
+ foreach $lock (<[a-z]*\\.lock>) {
+ my $subdir = $lock; $subdir =~ s/\\.lock$//;
+ if (!lstat $lock) {
+ $! == ENOENT or hkfail "$lock: lstat: $!";
+ next;
+ }
+ if (-M _ <= $treeexpiredays) {
+ logm 'debug', "housekeeping: subdirs $subdir: touched recently";
+ next;
+ }
+ if (!lockfile \*LOCK, $lock, LOCK_EX|LOCK_NB) {
+ logm 'info', "housekeeping: subdirs $subdir: lock busy, skipping";
+ next;
+ }
+ logm 'info', "housekeeping: subdirs $subdir: cleaning";
+ my $ok = 1;
+ foreach my $suffix (qw(tmp git)) {
+ my $dir = "${subdir}\\.$suffix";
+ my $errs;
+ remove_tree($dir, { safe=>1, error=>\$errs });
+ if (stat $dir) {
+ $ok = 0;
+ logm 'warning', "housekeeping: $dir: problems with".
+ " deletion prevent cleanup:";
+ foreach my $err (@$errs) {
+ logm 'info', "problem deleting: $err->[0]: $err->[1]";
+ }
+ }
+ }
+ if ($ok) {
+ unlink $lock or hkfail "remove $lock: $!";
+ }
+ }
+ open HS, ">", "Housekeeping.stamp" or hkfail "touch Housekeeping.stamp: $!";
+ close HS or hkfail "close Housekeeping.stamp: $!";
+ logm 'info', "housekeeping finished";