summary refs log tree commit diff
path: root/nixos/modules/system/activation
diff options
context:
space:
mode:
authorJanne Heß <janne@hess.ooo>2022-02-17 12:46:00 +0100
committerJanne Heß <janne@hess.ooo>2022-02-17 12:49:45 +0100
commit3617ecb67f447f50f79ccd9b1bdaa5e151749ec7 (patch)
tree7f957678213d39d8fd8712c84f379ef32cb46bda /nixos/modules/system/activation
parentb516e55d9d1509063d6ceea8ffa817f9f352c500 (diff)
downloadnixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar.gz
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar.bz2
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar.lz
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar.xz
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.tar.zst
nixpkgs-3617ecb67f447f50f79ccd9b1bdaa5e151749ec7.zip
nixos/switch-to-configuration: Fix backslashes in unit names
systemd needs this so special characters (like the ones in wireguard
units that appear because they are part of base64) can be escaped using
the \x syntax.

Root of the issue is that `glob()` handles the backslash internally
which is obviously not what we want here.

Also add a test case and fix some perlcritic issues in the subroutine.
Diffstat (limited to 'nixos/modules/system/activation')
-rw-r--r--nixos/modules/system/activation/switch-to-configuration.pl25
1 files changed, 15 insertions, 10 deletions
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 68333d43a5d..a8fe14c58f0 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -173,13 +173,18 @@ sub parseSystemdIni {
 #
 # If a directory with the same basename ending in .d exists next to the unit file, it will be
 # assumed to contain override files which will be parsed as well and handled properly.
-sub parseUnit {
-    my ($unitPath) = @_;
+sub parse_unit {
+    my ($unit_path) = @_;
 
     # Parse the main unit and all overrides
-    my %unitData;
-    parseSystemdIni(\%unitData, $_) for glob("${unitPath}{,.d/*.conf}");
-    return %unitData;
+    my %unit_data;
+    # Replace \ with \\ so glob() still works with units that have a \ in them
+    # Valid characters in unit names are ASCII letters, digits, ":", "-", "_", ".", and "\"
+    $unit_path =~ s/\\/\\\\/gmsx;
+    foreach (glob "${unit_path}{,.d/*.conf}") {
+        parseSystemdIni(\%unit_data, "$_")
+    }
+    return %unit_data;
 }
 
 # Checks whether a specified boolean in a systemd unit is true
@@ -310,7 +315,7 @@ sub handleModifiedUnit {
         # Revert of the attempt: https://github.com/NixOS/nixpkgs/pull/147609
         # More details: https://github.com/NixOS/nixpkgs/issues/74899#issuecomment-981142430
     } else {
-        my %unitInfo = $newUnitInfo ? %{$newUnitInfo} : parseUnit($newUnitFile);
+        my %unitInfo = $newUnitInfo ? %{$newUnitInfo} : parse_unit($newUnitFile);
         if (parseSystemdBool(\%unitInfo, "Service", "X-ReloadIfChanged", 0) and not $unitsToRestart->{$unit} and not $unitsToStop->{$unit}) {
             $unitsToReload->{$unit} = 1;
             recordUnit($reloadListFile, $unit);
@@ -412,12 +417,12 @@ while (my ($unit, $state) = each %{$activePrev}) {
 
     if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
         if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") {
-            my %unitInfo = parseUnit($prevUnitFile);
+            my %unitInfo = parse_unit($prevUnitFile);
             $unitsToStop{$unit} = 1 if parseSystemdBool(\%unitInfo, "Unit", "X-StopOnRemoval", 1);
         }
 
         elsif ($unit =~ /\.target$/) {
-            my %unitInfo = parseUnit($newUnitFile);
+            my %unitInfo = parse_unit($newUnitFile);
 
             # Cause all active target units to be restarted below.
             # This should start most changed units we stop here as
@@ -451,8 +456,8 @@ while (my ($unit, $state) = each %{$activePrev}) {
         }
 
         else {
-            my %old_unit_info = parseUnit($prevUnitFile);
-            my %new_unit_info = parseUnit($newUnitFile);
+            my %old_unit_info = parse_unit($prevUnitFile);
+            my %new_unit_info = parse_unit($newUnitFile);
             my $diff = compare_units(\%old_unit_info, \%new_unit_info);
             if ($diff eq 1) {
                 handleModifiedUnit($unit, $baseName, $newUnitFile, \%new_unit_info, $activePrev, \%unitsToStop, \%unitsToStart, \%unitsToReload, \%unitsToRestart, \%unitsToSkip);