From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 8F20F1F9F9 for ; Sun, 24 Nov 2019 00:22:40 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 08/17] daemon: use sigprocmask to block signals at startup Date: Sun, 24 Nov 2019 00:22:28 +0000 Message-Id: <20191124002237.15713-9-e@80x24.org> In-Reply-To: <20191124002237.15713-1-e@80x24.org> References: <20191124002237.15713-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: `$SIG{FOO} = "IGNORE"' will cause the daemon to miss signals entirely. Instead, we can use sigprocmask to block signal delivery until we have our signal handlers setup. This closes a race where a PID file can be written for an init script and a signal to be dropped via "IGNORE". --- lib/PublicInbox/Daemon.pm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index b3743f5c..e830a98f 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -8,7 +8,7 @@ use warnings; use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; use IO::Handle; use IO::Socket; -use POSIX qw(WNOHANG); +use POSIX qw(WNOHANG :signal_h); use Socket qw(IPPROTO_TCP SOL_SOCKET); sub SO_ACCEPTFILTER () { 0x1000 } use Cwd qw/abs_path/; @@ -19,7 +19,7 @@ require PublicInbox::EvCleanup; require PublicInbox::Listener; require PublicInbox::ParentPipe; my @CMD; -my $set_user; +my ($set_user, $oldset); my (@cfg_listen, $stdout, $stderr, $group, $user, $pid_file, $daemonize); my $worker_processes = 1; my @listeners; @@ -76,9 +76,11 @@ sub accept_tls_opt ($) { sub daemon_prepare ($) { my ($default_listen) = @_; + $oldset = POSIX::SigSet->new(); + my $newset = POSIX::SigSet->new(); + $newset->fillset or die "fillset: $!"; + sigprocmask(SIG_SETMASK, $newset, $oldset) or die "sigprocmask: $!"; @CMD = ($0, @ARGV); - $SIG{HUP} = $SIG{USR1} = $SIG{USR2} = $SIG{PIPE} = - $SIG{TTIN} = $SIG{TTOU} = $SIG{WINCH} = 'IGNORE'; my %opts = ( 'l|listen=s' => \@cfg_listen, '1|stdout=s' => \$stdout, @@ -482,6 +484,7 @@ sub master_loop { syswrite($w, '.'); }; } + sigprocmask(SIG_SETMASK, $oldset) or die "sigprocmask: $!"; reopen_logs(); # main loop my $quit = 0; @@ -616,6 +619,7 @@ sub daemon_loop ($$$$) { # this calls epoll_create: PublicInbox::Listener->new($_, $tls_cb || $post_accept) } @listeners; + sigprocmask(SIG_SETMASK, $oldset) or die "sigprocmask: $!"; PublicInbox::DS->EventLoop; $parent_pipe = undef; }