about summary refs log tree commit homepage
path: root/lib/PublicInbox
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox')
-rw-r--r--lib/PublicInbox/Admin.pm3
-rw-r--r--lib/PublicInbox/Git.pm4
-rw-r--r--lib/PublicInbox/GitHTTPBackend.pm2
-rw-r--r--lib/PublicInbox/Import.pm2
-rw-r--r--lib/PublicInbox/SolverGit.pm2
-rw-r--r--lib/PublicInbox/Spawn.pm42
-rw-r--r--lib/PublicInbox/SpawnPP.pm18
-rw-r--r--lib/PublicInbox/TestCommon.pm2
-rw-r--r--lib/PublicInbox/V2Writable.pm2
-rw-r--r--lib/PublicInbox/Xapcmd.pm2
10 files changed, 40 insertions, 39 deletions
diff --git a/lib/PublicInbox/Admin.pm b/lib/PublicInbox/Admin.pm
index 32a9f65e..5a3554cf 100644
--- a/lib/PublicInbox/Admin.pm
+++ b/lib/PublicInbox/Admin.pm
@@ -241,8 +241,7 @@ sub progress_prepare ($) {
         if ($opt->{quiet}) {
                 open my $null, '>', '/dev/null' or
                         die "failed to open /dev/null: $!\n";
-                $opt->{1} = fileno($null); # suitable for spawn() redirect
-                $opt->{-dev_null} = $null;
+                $opt->{1} = $null; # suitable for spawn() redirect
         } else {
                 $opt->{verbose} ||= 1;
                 $opt->{-progress} = sub { print STDERR @_ };
diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm
index af3a5712..8d587469 100644
--- a/lib/PublicInbox/Git.pm
+++ b/lib/PublicInbox/Git.pm
@@ -114,12 +114,12 @@ sub _bidi_pipe {
 
         my @cmd = (qw(git), "--git-dir=$self->{git_dir}",
                         qw(-c core.abbrev=40 cat-file), $batch);
-        my $redir = { 0 => fileno($out_r), 1 => fileno($in_w) };
+        my $redir = { 0 => $out_r, 1 => $in_w };
         if ($err) {
                 my $id = "git.$self->{git_dir}$batch.err";
                 my $fh = tmpfile($id) or fail($self, "tmpfile($id): $!");
                 $self->{$err} = $fh;
-                $redir->{2} = fileno($fh);
+                $redir->{2} = $fh;
         }
         my $p = spawn(\@cmd, undef, $redir);
         defined $p or fail($self, "spawn failed: $!");
diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm
index b7640d42..8dd27a75 100644
--- a/lib/PublicInbox/GitHTTPBackend.pm
+++ b/lib/PublicInbox/GitHTTPBackend.pm
@@ -164,7 +164,7 @@ sub input_prepare {
                 err($env, "error seeking temporary file: $!");
                 return;
         }
-        { 0 => fileno($in), -hold => $in };
+        { 0 => $in };
 }
 
 sub parse_cgi_headers {
diff --git a/lib/PublicInbox/Import.pm b/lib/PublicInbox/Import.pm
index 46de09c4..34f7d122 100644
--- a/lib/PublicInbox/Import.pm
+++ b/lib/PublicInbox/Import.pm
@@ -66,7 +66,7 @@ sub gfi_start {
         my $git_dir = $git->{git_dir};
         my @cmd = ('git', "--git-dir=$git_dir", qw(fast-import
                         --quiet --done --date-format=raw));
-        my $rdr = { 0 => fileno($out_r), 1 => fileno($in_w) };
+        my $rdr = { 0 => $out_r, 1 => $in_w };
         my $pid = spawn(\@cmd, undef, $rdr);
         die "spawn fast-import failed: $!" unless defined $pid;
         $out_w->autoflush(1);
diff --git a/lib/PublicInbox/SolverGit.pm b/lib/PublicInbox/SolverGit.pm
index 17a43060..03666646 100644
--- a/lib/PublicInbox/SolverGit.pm
+++ b/lib/PublicInbox/SolverGit.pm
@@ -259,7 +259,7 @@ sub prepare_index ($) {
         sysseek($in, 0, 0) or die "seek: $!";
 
         dbg($self, 'preparing index');
-        my $rdr = { 0 => fileno($in), -hold => $in };
+        my $rdr = { 0 => $in };
         my $cmd = [ qw(git update-index -z --index-info) ];
         my $qsp = PublicInbox::Qspawn->new($cmd, $self->{git_env}, $rdr);
         $path_a = git_quote($path_a);
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index c64812dd..6d42d5bc 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -79,20 +79,14 @@ static void xerr(const char *msg)
         _exit(1);
 }
 
-#define REDIR(var,fd) do { \
-        if (var != fd && dup2(var, fd) < 0) \
-                xerr("error redirecting std"#var ": "); \
-} while (0)
-
 /*
- * unstable internal API.  This was easy to implement but does not
- * support arbitrary redirects.  It'll be updated depending on
+ * unstable internal API.  It'll be updated depending on
  * whatever we'll need in the future.
  * Be sure to update PublicInbox::SpawnPP if this changes
  */
-int pi_fork_exec(int in, int out, int err,
-                        SV *file, SV *cmdref, SV *envref, SV *rlimref)
+int pi_fork_exec(SV *redirref, SV *file, SV *cmdref, SV *envref, SV *rlimref)
 {
+        AV *redir = (AV *)SvRV(redirref);
         AV *cmd = (AV *)SvRV(cmdref);
         AV *env = (AV *)SvRV(envref);
         AV *rlim = (AV *)SvRV(rlimref);
@@ -112,11 +106,16 @@ int pi_fork_exec(int in, int out, int err,
         pid = vfork();
         if (pid == 0) {
                 int sig;
-                I32 i, max;
-
-                REDIR(in, 0);
-                REDIR(out, 1);
-                REDIR(err, 2);
+                I32 i, child_fd, max = av_len(redir);
+
+                for (child_fd = 0; child_fd <= max; child_fd++) {
+                        SV **parent = av_fetch(redir, child_fd, 0);
+                        int parent_fd = SvIV(*parent);
+                        if (parent_fd == child_fd)
+                                continue;
+                        if (dup2(parent_fd, child_fd) < 0)
+                                xerr("dup2");
+                }
                 for (sig = 1; sig < NSIG; sig++)
                         signal(sig, SIG_DFL); /* ignore errors on signals */
 
@@ -196,9 +195,16 @@ sub spawn ($;$$) {
         while (my ($k, $v) = each %env) {
                 push @env, "$k=$v";
         }
-        my $in = $opts->{0} || 0;
-        my $out = $opts->{1} || 1;
-        my $err = $opts->{2} || 2;
+        my $redir = [];
+        for my $child_fd (0..2) {
+                my $parent_fd = $opts->{$child_fd};
+                if (defined($parent_fd) && $parent_fd !~ /\A[0-9]+\z/) {
+                        defined(my $fd = fileno($parent_fd)) or
+                                        die "$parent_fd not an IO GLOB? $!";
+                        $parent_fd = $fd;
+                }
+                $redir->[$child_fd] = $parent_fd // $child_fd;
+        }
         my $rlim = [];
 
         foreach my $l (RLIMITS()) {
@@ -210,7 +216,7 @@ sub spawn ($;$$) {
                 }
                 push @$rlim, $r, @$v;
         }
-        my $pid = pi_fork_exec($in, $out, $err, $f, $cmd, \@env, $rlim);
+        my $pid = pi_fork_exec($redir, $f, $cmd, \@env, $rlim);
         $pid < 0 ? undef : $pid;
 }
 
diff --git a/lib/PublicInbox/SpawnPP.pm b/lib/PublicInbox/SpawnPP.pm
index 29b13371..2ac02c56 100644
--- a/lib/PublicInbox/SpawnPP.pm
+++ b/lib/PublicInbox/SpawnPP.pm
@@ -9,8 +9,8 @@ use warnings;
 use POSIX qw(dup2 :signal_h);
 
 # Pure Perl implementation for folks that do not use Inline::C
-sub pi_fork_exec ($$$$$$) {
-        my ($in, $out, $err, $f, $cmd, $env, $rlim) = @_;
+sub pi_fork_exec ($$$$$) {
+        my ($redir, $f, $cmd, $env, $rlim) = @_;
         my $old = POSIX::SigSet->new();
         my $set = POSIX::SigSet->new();
         $set->fillset or die "fillset failed: $!";
@@ -27,16 +27,12 @@ sub pi_fork_exec ($$$$$$) {
                         BSD::Resource::setrlimit($r, $soft, $hard) or
                           warn "failed to set $r=[$soft,$hard]\n";
                 }
-                if ($in != 0) {
-                        dup2($in, 0) or die "dup2 failed for stdin: $!";
+                for my $child_fd (0..$#$redir) {
+                        my $parent_fd = $redir->[$child_fd];
+                        next if $parent_fd == $child_fd;
+                        dup2($parent_fd, $child_fd) or
+                                die "dup2($parent_fd, $child_fd): $!\n";
                 }
-                if ($out != 1) {
-                        dup2($out, 1) or die "dup2 failed for stdout: $!";
-                }
-                if ($err != 2) {
-                        dup2($err, 2) or die "dup2 failed for stderr: $!";
-                }
-
                 if ($ENV{MOD_PERL}) {
                         exec which('env'), '-i', @$env, @$cmd;
                         die "exec env -i ... $cmd->[0] failed: $!\n";
diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm
index b0b1f4d9..532cbee6 100644
--- a/lib/PublicInbox/TestCommon.pm
+++ b/lib/PublicInbox/TestCommon.pm
@@ -194,7 +194,7 @@ sub run_script ($;$$) {
                 next unless ref($redir);
                 open my $fh, '+>', undef or die "open: $!";
                 $fhref->[$fd] = $fh;
-                $spawn_opt->{$fd} = fileno($fh);
+                $spawn_opt->{$fd} = $fh;
                 next if $fd > 0;
                 $fh->autoflush(1);
                 print $fh $$redir or die "print: $!";
diff --git a/lib/PublicInbox/V2Writable.pm b/lib/PublicInbox/V2Writable.pm
index 77b3bde4..c614e20c 100644
--- a/lib/PublicInbox/V2Writable.pm
+++ b/lib/PublicInbox/V2Writable.pm
@@ -473,7 +473,7 @@ sub git_hash_raw ($$) {
 
         my ($r, $w);
         pipe($r, $w) or die "failed to create pipe: $!";
-        my $rdr = { 0 => fileno($tmp_fh), 1 => fileno($w) };
+        my $rdr = { 0 => $tmp_fh, 1 => $w };
         my $git_dir = $self->{-inbox}->git->{git_dir};
         my $cmd = ['git', "--git-dir=$git_dir", qw(hash-object --stdin)];
         my $pid = spawn($cmd, undef, $rdr);
diff --git a/lib/PublicInbox/Xapcmd.pm b/lib/PublicInbox/Xapcmd.pm
index 9f897dad..544242a3 100644
--- a/lib/PublicInbox/Xapcmd.pm
+++ b/lib/PublicInbox/Xapcmd.pm
@@ -286,7 +286,7 @@ sub compact ($$) {
                 defined(my $dfd = $opt->{$fd}) or next;
                 $rdr->{$fd} = $dfd;
         }
-        $rdr->{1} = fileno($w) if $pr && pipe($r, $w);
+        $rdr->{1} = $w if $pr && pipe($r, $w);
 
         # we rely on --no-renumber to keep docids synched to NNTP
         my $cmd = [ $XAPIAN_COMPACT, '--no-renumber' ];