X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FLEI.pm;h=b68e526bf365e056b8044a5fc89ff7527ca75a93;hb=ef45dcc37abfdf467597f912ec290c4d39218ef6;hp=83534878ee693683b4ab493b60b7765286f762a1;hpb=a1733d3406dfbde52d1468e671edd1d76893f546;p=public-inbox.git diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 83534878..b68e526b 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -12,14 +12,14 @@ use parent qw(PublicInbox::DS PublicInbox::LeiExternal PublicInbox::LeiQuery); use Getopt::Long (); use Socket qw(AF_UNIX SOCK_SEQPACKET MSG_EOR pack_sockaddr_un); -use Errno qw(EPIPE EAGAIN EINTR ECONNREFUSED ENOENT ECONNRESET); +use Errno qw(EPIPE EAGAIN ECONNREFUSED ENOENT ECONNRESET); use Cwd qw(getcwd); use POSIX qw(strftime); use IO::Handle (); use Fcntl qw(SEEK_SET); use PublicInbox::Config; -use PublicInbox::Syscall qw(EPOLLIN EPOLLET); -use PublicInbox::DS qw(now dwaitpid); +use PublicInbox::Syscall qw(EPOLLIN); +use PublicInbox::DS qw(dwaitpid); use PublicInbox::Spawn qw(spawn popen_rd); use PublicInbox::Lock; use PublicInbox::Eml; @@ -77,19 +77,16 @@ sub rel2abs { return $p; } my $pwd = $self->{env}->{PWD}; - my $cwd; if (defined $pwd) { - my $xcwd = $self->{3} // - ($cwd = getcwd() // die "getcwd(PWD=$pwd): $!"); if (my @st_pwd = stat($pwd)) { - my @st_cwd = stat($xcwd) or die "stat($xcwd): $!"; + my @st_cwd = stat($self->{3}) or die "stat({3}): $!"; "@st_pwd[1,0]" eq "@st_cwd[1,0]" or $self->{env}->{PWD} = $pwd = undef; } else { # PWD was invalid $self->{env}->{PWD} = $pwd = undef; } } - $pwd //= $self->{env}->{PWD} = $cwd // getcwd() // die "getcwd: $!"; + $pwd //= $self->{env}->{PWD} = getcwd() // die "getcwd: $!"; File::Spec->rel2abs($p, $pwd); } @@ -181,8 +178,8 @@ our %CMD = ( # sorted in order of importance/use: shared color! mail-sync!), @c_opt, opt_dash('limit|n=i', '[0-9]+') ], 'up' => [ 'OUTPUT...|--all', 'update saved search', - qw(jobs|j=s lock=s@ alert=s@ mua=s verbose|v+ - remote-fudge-time=s all:s), @c_opt ], + qw(jobs|j=s lock=s@ alert=s@ mua=s verbose|v+ exclude=s@ + remote-fudge-time=s all:s remote! local! external!), @c_opt ], 'lcat' => [ '--stdin|MSGID_OR_URL...', 'display local copy of message(s)', 'stdin|', # /|\z/ must be first for lone dash @@ -225,7 +222,7 @@ our %CMD = ( # sorted in order of importance/use: 'ls-search' => [ '[PREFIX]', 'list saved search queries', qw(format|f=s pretty l ascii z|0), @c_opt ], -'forget-search' => [ 'OUTPUT', 'forget a saved search', +'forget-search' => [ 'OUTPUT...', 'forget a saved search', qw(verbose|v+), @c_opt ], 'edit-search' => [ 'OUTPUT', "edit saved search via `git config --edit'", @c_opt ], @@ -513,10 +510,10 @@ sub sigpipe_handler { # handles SIGPIPE from @WQ_KEYS workers } sub fail ($$;$) { - my ($self, $buf, $exit_code) = @_; + my ($self, $msg, $exit_code) = @_; local $current_lei = $self; $self->{failed}++; - warn($buf, "\n") if defined $buf; + warn(substr($msg, -1, 1) eq "\n" ? $msg : "$msg\n") if defined $msg; $self->{pkt_op_p}->pkt_do('fail_handler') if $self->{pkt_op_p}; x_it($self, ($exit_code // 1) << 8); undef; @@ -537,7 +534,7 @@ sub child_error { # passes non-fatal curl exit codes to user my ($self, $child_error, $msg) = @_; # child_error is $? local $current_lei = $self; $child_error ||= 1 << 8; - warn($msg, "\n") if defined $msg; + warn(substr($msg, -1, 1) eq "\n" ? $msg : "$msg\n") if defined $msg; if ($self->{pkt_op_p}) { # to top lei-daemon $self->{pkt_op_p}->pkt_do('child_error', $child_error); } elsif ($self->{sock}) { # to lei(1) client @@ -558,7 +555,8 @@ sub _lei_atfork_child { my ($self, $persist) = @_; # we need to explicitly close things which are on stack if ($persist) { - chdir '/' or die "chdir(/): $!"; + open $self->{3}, '<', '/' or die "open(/) $!"; + fchdir($self); close($_) for (grep(defined, delete @$self{qw(0 1 2 sock)})); if (my $cfg = $self->{cfg}) { delete @$cfg{qw(-lei_store -watches -lei_note_event)}; @@ -568,7 +566,7 @@ sub _lei_atfork_child { STDERR->autoflush(1); POSIX::setpgid(0, $$) // die "setpgid(0, $$): $!"; } - close($_) for (grep(defined, delete @$self{qw(3 old_1 au_done)})); + close($_) for (grep(defined, delete @$self{qw(old_1 au_done)})); delete $self->{-socks}; if (my $op_c = delete $self->{pkt_op_c}) { close(delete $op_c->{sock}); @@ -781,7 +779,7 @@ sub lazy_cb ($$$) { sub dispatch { my ($self, $cmd, @argv) = @_; - fchdir($self) or return; + fchdir($self); local %ENV = %{$self->{env}}; local $current_lei = $self; # for __WARN__ $self->{2}->autoflush(1); # keep stdout buffered until x_it|DESTROY @@ -850,9 +848,7 @@ sub _lei_cfg ($;$) { } 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 - } + delete(@PATH2CFG{grep(!-f, keys %PATH2CFG)}); } $self->{cfg} = $PATH2CFG{$f} = $cfg; refresh_watches($self); @@ -1112,7 +1108,7 @@ sub accept_dispatch { # Listener {post_accept} callback my %env = map { split(/=/, $_, 2) } splice(@argv, $argc); $self->{env} = \%env; eval { dispatch($self, @argv) }; - send($sock, $@, MSG_EOR) if $@; + $self->fail($@) if $@; } sub dclose { @@ -1129,16 +1125,12 @@ sub event_step { local %ENV = %{$self->{env}}; local $current_lei = $self; eval { - my $buf; - while (my @fds = $recv_cmd->($self->{sock}, $buf, 4096)) { - if (scalar(@fds) == 1 && !defined($fds[0])) { - return if $! == EAGAIN; - next if $! == EINTR; - last if $! == ECONNRESET; - die "recvmsg: $!"; - } - for (@fds) { open my $rfh, '+<&=', $_ } + my @fds = $recv_cmd->($self->{sock}, my $buf, 4096); + if (scalar(@fds) == 1 && !defined($fds[0])) { + return if $! == EAGAIN; + die "recvmsg: $!" if $! != ECONNRESET; } + for (@fds) { open my $rfh, '+<&=', $_ } if ($buf eq '') { _drop_wq($self); # EOF, client disconnected dclose($self); @@ -1166,7 +1158,7 @@ sub event_step_init { my $sock = $self->{sock} or return; $self->{-event_init_done} //= do { # persist til $ops done $sock->blocking(0); - $self->SUPER::new($sock, EPOLLIN|EPOLLET); + $self->SUPER::new($sock, EPOLLIN); $sock; }; } @@ -1192,7 +1184,7 @@ sub cfg2lei ($) { open($lei->{0}, '<&', \*STDIN) or die "dup 0: $!"; open($lei->{1}, '>>&', \*STDOUT) or die "dup 1: $!"; open($lei->{2}, '>>&', \*STDERR) or die "dup 2: $!"; - open($lei->{3}, '/') or die "open /: $!"; + open($lei->{3}, '<', '/') or die "open /: $!"; my ($x, $y); socketpair($x, $y, AF_UNIX, SOCK_SEQPACKET, 0) or die "socketpair: $!"; $lei->{sock} = $x; @@ -1206,7 +1198,7 @@ sub dir_idle_handler ($) { # PublicInbox::DirIdle callback my $fn = $ev->fullname; if ($fn =~ m!\A(.+)/(new|cur)/([^/]+)\z!) { # Maildir file my ($mdir, $nc, $bn) = ($1, $2, $3); - $nc = '' if $ev->IN_DELETE; + $nc = '' if $ev->IN_DELETE || $ev->IN_MOVED_FROM; for my $f (keys %{$MDIR2CFGPATH->{$mdir} // {}}) { my $cfg = $PATH2CFG{$f} // next; eval { @@ -1305,10 +1297,11 @@ sub lazy_start { USR2 => \&noop, }; require PublicInbox::DirIdle; - local $dir_idle = PublicInbox::DirIdle->new([$sock_dir], sub { + local $dir_idle = PublicInbox::DirIdle->new(sub { # just rely on wakeup to hit PostLoopCallback set below dir_idle_handler($_[0]) if $_[0]->fullname ne $path; - }, 1); + }); + $dir_idle->add_watches([$sock_dir]); PublicInbox::DS->SetPostLoopCallback(sub { my ($dmap, undef) = @_; if (@st = defined($path) ? stat($path) : ()) { @@ -1322,11 +1315,10 @@ sub lazy_start { $quit->(); } return 1 if defined($path); - my $now = now(); my $n = 0; for my $s (values %$dmap) { $s->can('busy') or next; - if ($s->busy($now)) { + if ($s->busy) { ++$n; } else { $s->close; @@ -1384,7 +1376,7 @@ sub wq_done_wait { # dwaitpid callback sub fchdir { my ($lei) = @_; my $dh = $lei->{3} // die 'BUG: lei->{3} (CWD) gone'; - chdir($dh) || $lei->fail("fchdir: $!"); + chdir($dh) || die "fchdir: $!"; } sub wq_eof { # EOF callback for main daemon