use Socket qw(AF_UNIX SOCK_STREAM pack_sockaddr_un);
use PublicInbox::CmdIPC4;
my $narg = 4;
+my $recv_cmd = PublicInbox::CmdIPC4->can('recv_cmd4');
my $send_cmd = PublicInbox::CmdIPC4->can('send_cmd4') // do {
- require PublicInbox::CmdIPC1; # 2nd choice
- $narg = 1;
- PublicInbox::CmdIPC1->can('send_cmd1');
-} // do {
require PublicInbox::Spawn; # takes ~50ms even if built *sigh*
$narg = 4;
+ $recv_cmd = PublicInbox::Spawn->can('recv_cmd4');
PublicInbox::Spawn->can('send_cmd4');
};
+sub exec_cmd {
+ my ($fds, $argc, @argv) = @_;
+ my %env = map { split(/=/, $_, 2) } splice(@argv, $argc);
+ my @m = (*STDIN{IO}, '<&=', *STDOUT{IO}, '>&=',
+ *STDERR{IO}, '>&=');
+ for my $fd (@$fds) {
+ my ($old_io, $mode) = splice(@m, 0, 2);
+ open($old_io, $mode, $fd) or die "open $mode$fd: $!";
+ }
+ %ENV = (%ENV, %env);
+ exec(@argv);
+ die "exec: @argv: $!";
+}
+
my ($sock, $pwd);
if ($send_cmd && eval {
my $path = do {
$pwd = $cwd;
}
1;
-}) { # (Socket::MsgHdr|IO::FDPass|Inline::C), $sock, $pwd are all available:
+}) { # (Socket::MsgHdr|Inline::C), $sock, $pwd are all available:
local $ENV{PWD} = $pwd;
- my $buf = join("\0", $$, scalar(@ARGV), @ARGV);
+ my $buf = join("\0", scalar(@ARGV), @ARGV);
while (my ($k, $v) = each %ENV) { $buf .= "\0$k=$v" }
$buf .= "\0\0";
select $sock;
$| = 1; # unbuffer selected $sock
$send_cmd->($sock, [ 0, 1, 2 ], $buf, 0);
- while ($buf = <$sock>) {
- $buf =~ /\Aexit=([0-9]+)\n\z/ and exit($1 + 0);
- die $buf;
+ while (my (@fds) = $recv_cmd->($sock, $buf, 4096 * 33)) {
+ if ($buf =~ /\Aexit=([0-9]+)\n\z/) {
+ exit($1);
+ } elsif ($buf =~ /\Aexec (.+)\n\z/) {
+ exec_cmd(\@fds, split(/\0/, $1));
+ } else {
+ die $buf;
+ }
}
-} else { # for systems lacking Socket::MsgHdr, IO::FDPass or Inline::C
+} else { # for systems lacking Socket::MsgHdr or Inline::C
warn $@ if $@;
require PublicInbox::LEI;
PublicInbox::LEI::oneshot(__PACKAGE__);