diff --git a/miniserv.pl b/miniserv.pl index 21b32b84d..8cd462de8 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -139,22 +139,15 @@ if (-l $perl_path) { # Check vital config options &update_vital_config(); -# Check if already running via the PID file -if (open(PIDFILE, $config{'pidfile'})) { +# Check if already running via the PID file. In foreground mode, systemd or +# the socket bind owns duplicate-start detection. +if (!$config{'nofork'} && !$nofork_argv && open(PIDFILE, $config{'pidfile'})) { my $already = ; close(PIDFILE); chomp($already); $already =~ s/^\s+|\s+$//g; if ($already =~ /^\d+$/ && $already != $$ && kill(0, $already)) { - my $active = &pid_is_miniserv_for_config($already, $config_file); - if (defined($active) && !$active) { - warn "Ignoring stale Webmin PID file $config{'pidfile'} ". - "for unrelated PID $already\n"; - unlink($config{'pidfile'}); - } - else { - die "Webmin is already running with PID $already\n"; - } + die "Webmin is already running with PID $already\n"; } } @@ -5191,56 +5184,6 @@ close($fh); return $rv; } -# read_process_cmdline(pid) -# Returns a process command line from /proc, or undef if unavailable. -sub read_process_cmdline -{ -my ($pid) = @_; -return undef if (!$pid || $pid !~ /^\d+$/); -return &read_any_file("/proc/$pid/cmdline"); -} - -# same_config_file(file1, file2) -# Returns 1 if two config paths refer to the same file. -sub same_config_file -{ -my ($file1, $file2) = @_; -return 0 if (!$file1 || !$file2); -return 1 if ($file1 eq $file2); -my @stat1 = stat($file1); -my @stat2 = stat($file2); -return @stat1 && @stat2 && $stat1[0] == $stat2[0] && - $stat1[1] == $stat2[1]; -} - -# pid_is_miniserv_for_config(pid, config-file) -# Returns 1 if pid appears to be miniserv for this config, 0 if it is a -# different process, or undef if this platform cannot tell. -sub pid_is_miniserv_for_config -{ -my ($pid, $config_file) = @_; -my $cmdline = &read_process_cmdline($pid); -return undef if (!defined($cmdline)); -return 0 if ($cmdline eq ""); -my @args = split(/\0/, $cmdline); -my $script_idx; -for(my $i=0; $i<@args; $i++) { - if ($args[$i] =~ /(?:^|\/)miniserv\.pl$/) { - $script_idx = $i; - last; - } - } -return 0 if (!defined($script_idx)); -my $config_arg; -for(my $i=$script_idx+1; $i<@args; $i++) { - next if ($args[$i] =~ /^-/); - $config_arg = $args[$i]; - last; - } -return defined($config_arg) ? - (&same_config_file($config_arg, $config_file) ? 1 : 0) : undef; -} - # update_vital_config() # Updates %config with defaults, and dies if something vital is missing sub update_vital_config diff --git a/t/miniserv.t b/t/miniserv.t index 05c4fcd97..59a690352 100644 --- a/t/miniserv.t +++ b/t/miniserv.t @@ -1282,70 +1282,6 @@ subtest 'read_any_file' => sub { 'open failure returns undef'); }; -# pid_is_miniserv_for_config — avoids stale pidfiles with reused PIDs -subtest 'pid_is_miniserv_for_config' => sub { - my $config = '/etc/webmin/miniserv.conf'; - my $pid = $$; - - { - no warnings 'redefine'; - local *miniserv::read_process_cmdline = sub { - return join("\0", '/usr/sbin/dovecot', '-F'); - }; - is(miniserv::pid_is_miniserv_for_config($pid, $config), 0, - 'live unrelated PID is not treated as active miniserv'); - } - - { - no warnings 'redefine'; - local *miniserv::read_process_cmdline = sub { - return join("\0", '/usr/bin/perl', - '/usr/libexec/webmin/miniserv.pl', - '--nofork', $config); - }; - is(miniserv::pid_is_miniserv_for_config($pid, $config), 1, - 'matching miniserv config is treated as active'); - } - - { - require File::Temp; - my ($fh, $real_config) = File::Temp::tempfile(UNLINK => 1); - close($fh); - my $link_config = "$real_config.link"; - SKIP: { - symlink($real_config, $link_config) || - skip 'symlinks are unavailable', 1; - no warnings 'redefine'; - local *miniserv::read_process_cmdline = sub { - return join("\0", '/usr/bin/perl', - '/usr/libexec/webmin/miniserv.pl', - $link_config); - }; - is(miniserv::pid_is_miniserv_for_config($pid, $real_config), 1, - 'symlinked config path is matched by inode'); - unlink($link_config); - } - } - - { - no warnings 'redefine'; - local *miniserv::read_process_cmdline = sub { - return join("\0", '/usr/bin/perl', - '/usr/libexec/usermin/miniserv.pl', - '--nofork', '/etc/usermin/miniserv.conf'); - }; - is(miniserv::pid_is_miniserv_for_config($pid, $config), 0, - 'different miniserv config is not treated as active'); - } - - { - no warnings 'redefine'; - local *miniserv::read_process_cmdline = sub { return undef; }; - is(miniserv::pid_is_miniserv_for_config($pid, $config), undef, - 'unreadable process command line keeps conservative behavior'); - } -}; - # read_mime_types — populates %mime from file + addtype_* config subtest 'read_mime_types' => sub { no warnings 'once';