From 160fbaf41aa7bc606a3436e3528a7e8687c938e1 Mon Sep 17 00:00:00 2001 From: Corey Hickey Date: Thu, 19 Oct 2023 15:35:58 -0700 Subject: [PATCH] apply override_rc deterministically When applying conf.d overrides to _enable_ restarts for services that already have matching entries in the default override_rc, we can use a form like: $nrconf{override_rc}->{qr(^dbus)} = 1; $nrconf{override_rc}->{qr(^getty@.+\.servic)} = 1; For proper behavior, we need to provide a regex that is _exactly_ the same as the one in the default override_rc; needrestart matches against regexes in order and stops on the first match. What if there is a typo, though? Note the "servic" typo in the example above; this is a valid regex, but it's not quite the same as the one in the default override_rc. Currently, if there are two matching regexes, the one that takes effect is random, with a 50% probability for each. This is due to behavior in relatively modern perl. Perl versions >= 5.18 evaluate hashes in an order that randomly differs from run to run. https://perldoc.perl.org/perl5180delta To provide deterministic behavior, sort the keys first. That way, the first matching regex will always win, and the intended override will either always work or never work. --- ex/needrestart.conf | 1 + needrestart | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ex/needrestart.conf b/ex/needrestart.conf index 52ba38d..a92fc9b 100644 --- a/ex/needrestart.conf +++ b/ex/needrestart.conf @@ -68,6 +68,7 @@ $nrconf{blacklist} = [ #]; # Override service default selection (hash of regex). +# Regexes are checked in lexical order; the first matching regex will be used. $nrconf{override_rc} = { # DBus qr(^dbus) => 0, diff --git a/needrestart b/needrestart index bcec62b..1cd486e 100755 --- a/needrestart +++ b/needrestart @@ -1016,6 +1016,8 @@ if(defined($opt_l) && !$uid) { } } + my @sorted_override_rc_keys = sort keys %{$nrconf{override_rc}}; + foreach my $rc (sort { lc($a) cmp lc($b) } keys %restart) { # always combine restarts in one systemctl command local $nrconf{systemctl_combine} = 1 unless($opt_r eq 'l'); @@ -1033,7 +1035,7 @@ if(defined($opt_l) && !$uid) { # don't restart greylisted services... my $restart = !$nrconf{defno}; - foreach my $re (keys %{$nrconf{override_rc}}) { + foreach my $re (@sorted_override_rc_keys) { next unless($rc =~ /$re/); $restart = $nrconf{override_rc}->{$re};