use File::Path qw(mkpath);
use File::Spec;
our $quit = \&CORE::exit;
-my $recv_cmd;
+my ($recv_cmd, $send_cmd);
my $GLP = Getopt::Long::Parser->new;
$GLP->configure(qw(gnu_getopt no_ignore_case auto_abbrev));
my $GLP_PASS = Getopt::Long::Parser->new;
my $sig = ($code & 127);
$code >>= 8 unless $sig;
if (my $sock = $self->{sock}) {
- say $sock "exit=$code";
+ my $fds = [ map { fileno($_) } @$self{0..2} ];
+ $send_cmd->($sock, $fds, "exit=$code\n", 0);
} else { # for oneshot
$quit->($code);
}
chomp(my $pager = <$fh> // '');
close($fh) or warn "`git var PAGER' error: \$?=$?";
return if $pager eq 'cat' || $pager eq '';
- $env->{LESS} //= 'FRX';
- $env->{LV} //= '-c';
- $env->{COLUMNS} //= 80; # TODO TIOCGWINSZ
- $env->{MORE} //= 'FRX' if $^O eq 'freebsd';
+ # TODO TIOCGWINSZ
+ my %new_env = (LESS => 'FRX', LV => '-c', COLUMNS => 80);
+ $new_env{MORE} = 'FRX' if $^O eq 'freebsd';
pipe(my ($r, $wpager)) or return warn "pipe: $!";
my $rdr = { 0 => $r, 1 => $self->{1}, 2 => $self->{2} };
+ my $pid;
+ if (my $sock = $self->{sock}) { # lei(1) process runs it
+ delete @new_env{keys %$env}; # only set iff unset
+ my $buf = "exec 1\0".$pager;
+ while (my ($k, $v) = each %new_env) { $buf .= "\0$k=$v" };
+ my $fds = [ map { fileno($_) } @$rdr{0..2} ];
+ $send_cmd->($sock, $fds, $buf .= "\n", 0);
+ } else {
+ $pid = spawn([$pager], $env, $rdr);
+ }
$self->{1} = $wpager;
$self->{2} = $wpager if -t $self->{2};
- my $pid = spawn([$pager], $env, $rdr);
$env->{GIT_PAGER_IN_USE} = 'true'; # we may spawn git
[ $pid, @$rdr{1, 2} ];
}
local $oldset = PublicInbox::DS::block_signals();
if ($nfd == 1) {
require PublicInbox::CmdIPC1;
+ $send_cmd = PublicInbox::CmdIPC1->can('send_cmd1');
$recv_cmd = PublicInbox::CmdIPC1->can('recv_cmd1');
} elsif ($nfd == 4) {
+ $send_cmd = PublicInbox::Spawn->can('send_cmd4');
$recv_cmd = PublicInbox::Spawn->can('recv_cmd4') // do {
require PublicInbox::CmdIPC4;
+ $send_cmd = PublicInbox::CmdIPC4->can('send_cmd4');
PublicInbox::CmdIPC4->can('recv_cmd4');
};
}
# my $wcb = PublicInbox::LeiToMail->write_cb($out, $self);
$self->{mset_opt} = \%mset_opt;
$lxs->do_query($self, \@srcs);
- if ($pid_old12) {
+ if ($pid_old12) { # [ pid, stdout, stderr ]
+ my $pid = $pid_old12->[0];
$self->{$_} = $pid_old12->[$_] for (1, 2);
- dwaitpid($pid_old12->[0], undef, $self->{sock});
+ dwaitpid($pid, undef, $self->{sock}) if $pid;
}
}
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;
+ $recv_cmd = PublicInbox::CmdIPC1->can('recv_cmd1');
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 {
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
warn $@ if $@;