chiark / gitweb /
git-cache-proxy: Use open-coded fork/exec for git gc
[chiark-utils.git] / scripts / git-cache-proxy
index 7dd6f3ec531d53553633905a2c491bd8ffb43645..ec5ff7f2e81aa9c4fd67069e537479e812f5f60c 100755 (executable)
@@ -19,6 +19,9 @@
 #    fetch=no             just use what is in the cache
 #    fetch=try            use what is in the cache if the fetch/clone fails
 #    timeout=<seconds>    length of time to allow for fetch/clone
+#    housekeeping-interval-days=<integer>  } housekeeping tuning parameters
+#    tree-expire-days=<integer>            }
+#    gc-interval-days=<integer>            }
 
 # example inetd.conf line:
 #  9419 stream tcp nowait git-cache /usr/bin/git-cache-proxy git-cache-proxy
@@ -142,6 +145,8 @@ sub fail ($) {
     exit 0;
 }
 
+$SIG{ALRM} = sub { fail "timeout" };
+
 sub gitfail ($) {
     my ($msg) = @_;
     close LOCK;
@@ -248,7 +253,6 @@ sub servinfo ($) {
 }
 
 sub readcommand () {
-    $SIG{ALRM} = sub { fail "timeout" };
     alarm 30;
 
     my $hex_len = xread 4;
@@ -317,6 +321,19 @@ sub clonefetch () {
 
     if ($fetch) {
 
+       my $rbits = '';
+       vec($rbits,0,1) = 1;
+       my $ebits = $rbits;
+       my $r=select $rbits,undef,$ebits,0;
+       $r>=0 or fail "select recheck STDOUT failed: $!";
+       if ($r) {
+           servinfo 'client disconnected (stdin unexpectedly'.
+               (vec($rbits,0,1) ? ' readable' : '').
+               (vec($ebits,0,1) ? ' exception' : '').
+               ')';
+           exit 0;
+       }
+
        our @cmd;
 
        if (!$exists) {
@@ -430,12 +447,19 @@ sub housekeeping () {
            $mode_action = sub {
                my $gclog = "$subdir/gc.log";
                unlink $gclog or $!==ENOENT or hkfail "remove $gclog: $!";
-               my $r = system qw(sh -ec),
-                   'cd "$1"; shift; exec "$@"', 'x', "$subdir\\.git",
-                   qw(git gc --quiet);
-               if ($r) {
+               my $child = fork // hkfail "fork (for $subdir): $!";
+               if (!$child) {
+                   if (!chdir "$subdir\\.git") {
+                       exit 0 if $!==ENOENT;
+                       die "for gc: chdir $subdir: $!\n";
+                   }
+                   exec qw(git gc --quiet);
+                   die "exec git gc (for $subdir): $!\n";
+               }
+               waitpid($child, 0) == $child or hkfail "waitpid failed! $!";
+               if ($?) {
                    logm 'err',
                      "housekeeping: subdirs $subdir: gc failed (status $r)";
"housekeeping: subdirs $subdir: gc failed (wait status $?)";
                } else {
                    update_gcstamp("$subdir\\.git");
                    logm 'debug',