about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2014-04-30 20:13:54 +0000
committerEric Wong <e@80x24.org>2014-04-30 20:13:54 +0000
commitf286304f47685f6530462439b95951e2af86051f (patch)
tree2516f357b7a74470f9aaa86339b3f1306f5133fe /lib
parenta83cc9e2a3029a9d284fbd3e24b23dc4dd3a9313 (diff)
downloadpublic-inbox-f286304f47685f6530462439b95951e2af86051f.tar.gz
IPC::Open* does not work well under mod_perl (probably because
it does funky things with stdout/stderr).  So use the POSIX
dup2 functions instead, which work reliably on all POSIX-like
platforms.
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/GitCatFile.pm35
1 files changed, 29 insertions, 6 deletions
diff --git a/lib/PublicInbox/GitCatFile.pm b/lib/PublicInbox/GitCatFile.pm
index b3d9bfb7..b75389e2 100644
--- a/lib/PublicInbox/GitCatFile.pm
+++ b/lib/PublicInbox/GitCatFile.pm
@@ -6,23 +6,46 @@
 package PublicInbox::GitCatFile;
 use strict;
 use warnings;
-use IPC::Open2 qw(open2);
+use Fcntl qw(F_GETFD F_SETFD FD_CLOEXEC);
+use POSIX qw(dup2);
+require IO::Handle;
 
 sub new {
         my ($class, $git_dir) = @_;
         bless { git_dir => $git_dir }, $class;
 }
 
+sub set_cloexec {
+        my ($fh) = @_;
+        my $flags = fcntl($fh, F_GETFD, 0) or die "fcntl(F_GETFD): $!\n";
+        fcntl($fh, F_SETFD, $flags | FD_CLOEXEC) or die "fcntl(F_SETFD): $!\n";
+}
+
 sub _cat_file_begin {
         my ($self) = @_;
         return if $self->{pid};
-        my ($in, $out);
-        my $pid = open2($in, $out, 'git', "--git-dir=$self->{git_dir}",
-                        qw(cat-file --batch));
+        my ($in_r, $in_w, $out_r, $out_w);
+
+        pipe($in_r, $in_w) or die "pipe failed: $!\n";
+        set_cloexec($_) foreach ($in_r, $in_w);
+        pipe($out_r, $out_w) or die "pipe failed: $!\n";
+        set_cloexec($_) foreach ($out_r, $out_w);
+
+        my @cmd = ('git', "--git-dir=$self->{git_dir}", qw(cat-file --batch));
+        my $pid = fork;
+        defined $pid or die "fork failed: $!\n";
+        if ($pid == 0) {
+                dup2(fileno($out_r), 0) or die "redirect stdin failed: $!\n";
+                dup2(fileno($in_w), 1) or die "redirect stdout failed: $!\n";
+                exec(@cmd) or die 'exec `' . join(' '). "' failed: $!\n";
+        }
+        close $out_r or die "close failed: $!\n";
+        close $in_w or die "close failed: $!\n";
 
+        $out_w->autoflush(1);
+        $self->{in} = $in_r;
+        $self->{out} = $out_w;
         $self->{pid} = $pid;
-        $self->{in} = $in;
-        $self->{out} = $out;
 }
 
 sub cat_file {