PublicInbox::LeiQuery::curl_opt() ],
'ls-external' => [ '[FILTER]', 'list publicinbox|extindex locations',
qw(format|f=s z|0 globoff|g invert-match|v local remote), @c_opt ],
+'ls-label' => [ '', 'list labels', qw(z|0 stats:s), @c_opt ],
'forget-external' => [ 'LOCATION...|--prune',
'exclude further results from a publicinbox|extindex',
qw(prune), @c_opt ],
x_it($self, 13);
}
-sub lei_atfork_child {
+sub _lei_atfork_child {
my ($self, $persist) = @_;
# we need to explicitly close things which are on stack
if ($persist) {
+ chdir '/' or die "chdir(/): $!";
my @io = delete @$self{qw(0 1 2 sock)};
unless ($self->{oneshot}) {
close($_) for @io;
}
+ if (my $cfg = $self->{cfg}) {
+ delete $cfg->{-lei_store};
+ }
} else { # worker, Net::NNTP (Net::Cmd) uses STDERR directly
open STDERR, '+>&='.fileno($self->{2}) or warn "open $!";
delete $self->{0};
}
- delete @$self{qw(cnv mark imp)};
for (delete @$self{qw(3 old_1 au_done)}) {
close($_) if defined($_);
}
$current_lei = $persist ? undef : $self; # for SIG{__WARN__}
}
+sub _delete_pkt_op { # OnDestroy callback to prevent leaks on die
+ my ($self) = @_;
+ if (my $op = delete $self->{pkt_op_c}) { # in case of die
+ $op->close; # PublicInbox::PktOp::close
+ }
+ my $unclosed_after_die = delete($self->{pkt_op_p}) or return;
+ close $unclosed_after_die;
+}
+
+sub pkt_op_pair {
+ my ($self, $ops) = @_;
+ require PublicInbox::OnDestroy;
+ require PublicInbox::PktOp;
+ my $end = PublicInbox::OnDestroy->new($$, \&_delete_pkt_op, $self);
+ @$self{qw(pkt_op_c pkt_op_p)} = PublicInbox::PktOp->pair($ops);
+ $end;
+}
+
sub workers_start {
my ($lei, $wq, $ident, $jobs, $ops) = @_;
$ops = {
($ops ? %$ops : ()),
};
$ops->{''} //= [ \&dclose, $lei ];
- require PublicInbox::PktOp;
- ($lei->{pkt_op_c}, $lei->{pkt_op_p}) = PublicInbox::PktOp->pair($ops);
+ my $end = $lei->pkt_op_pair($ops);
$wq->wq_workers_start($ident, $jobs, $lei->oldset, { lei => $lei });
delete $lei->{pkt_op_p};
my $op = delete $lei->{pkt_op_c};
+ @$end = ();
$lei->event_step_init;
# oneshot needs $op, daemon-mode uses DS->EventLoop to handle $op
$lei->{oneshot} ? $op : undef;
next if $d eq ''; # same as git(1)
chdir $d or return fail($self, "cd $d: $!");
}
+ if (delete $self->{3}) { # update cwd for rel2abs
+ opendir my $dh, '.' or
+ return fail($self, "opendir . $!");
+ $self->{3} = $dh;
+ }
}
$cb->($self, @argv);
} elsif (grep(/\A-/, $cmd, @argv)) { # --help or -h only
bless $cfg, 'PublicInbox::Config';
$cfg->{-st} = $cur_st;
$cfg->{'-f'} = $f;
- if ($sto && File::Spec->canonpath($sto_dir) eq
- File::Spec->canonpath($cfg->{'leistore.dir'})) {
+ if ($sto && File::Spec->canonpath($sto_dir // store_path($self))
+ eq File::Spec->canonpath($cfg->{'leistore.dir'} //
+ store_path($self))) {
$cfg->{-lei_store} = $sto;
}
+ if (scalar(keys %PATH2CFG) > 5) {
+ # FIXME: use inotify/EVFILT_VNODE to detect unlinked configs
+ for my $k (keys %PATH2CFG) {
+ delete($PATH2CFG{$k}) unless -f $k
+ }
+ }
$self->{cfg} = $PATH2CFG{$f} = $cfg;
}
my $cfg = _lei_cfg($self, $creat);
$cfg->{-lei_store} //= do {
require PublicInbox::LeiStore;
- my $dir = $cfg->{'leistore.dir'};
- $dir //= $creat ? store_path($self) : return;
+ my $dir = $cfg->{'leistore.dir'} // store_path($self);
+ return unless $creat || -d $dir;
PublicInbox::LeiStore->new($dir, { creat => $creat });
};
}
return send($sock, 'timed out waiting to recv FDs', MSG_EOR);
# (4096 * 33) >MAX_ARG_STRLEN
my @fds = $recv_cmd->($sock, my $buf, 4096 * 33) or return; # EOF
- if (scalar(@fds) == 4) {
- for my $i (0..3) {
- my $fd = shift(@fds);
- open($self->{$i}, '+<&=', $fd) and next;
- send($sock, "open(+<&=$fd) (FD=$i): $!", MSG_EOR);
- }
- } elsif (!defined($fds[0])) {
+ if (!defined($fds[0])) {
warn(my $msg = "recv_cmd failed: $!");
return send($sock, $msg, MSG_EOR);
} else {
- return;
+ my $i = 0;
+ for my $fd (@fds) {
+ open($self->{$i++}, '+<&=', $fd) and next;
+ send($sock, "open(+<&=$fd) (FD=$i): $!", MSG_EOR);
+ }
+ return if scalar(@fds) != 4;
}
$self->{2}->autoflush(1); # keep stdout buffered until x_it|DESTROY
# $ENV_STR = join('', map { "\0$_=$ENV{$_}" } keys %ENV);