X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FLEI.pm;h=6a5c32b3a4fb9b22c3ab82dcac05c49b56754595;hb=43c43f785aa53607a0dd050989da5d7fd0dcfff4;hp=0be417ebae524338af023c519d412e4909417782;hpb=767f310dcd887066c7263cfe6093f7529ffe631c;p=public-inbox.git diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 0be417eb..6a5c32b3 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -145,6 +145,7 @@ our %CMD = ( # sorted in order of importance/use: 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 ], @@ -449,19 +450,22 @@ sub note_sigpipe { # triggers sigpipe_handler 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($_); } @@ -479,6 +483,24 @@ sub lei_atfork_child { $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 = { @@ -489,11 +511,11 @@ sub workers_start { ($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; @@ -637,6 +659,11 @@ sub dispatch { 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 @@ -675,10 +702,17 @@ sub _lei_cfg ($;$) { 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; } @@ -687,8 +721,8 @@ sub _lei_store ($;$) { 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 }); }; } @@ -955,17 +989,16 @@ sub accept_dispatch { # Listener {post_accept} callback 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);