diff --git a/modules/system/boot/systemd-unit-options.nix b/modules/system/boot/systemd-unit-options.nix index 239c837c6767..5707fb6f87e9 100644 --- a/modules/system/boot/systemd-unit-options.nix +++ b/modules/system/boot/systemd-unit-options.nix @@ -6,6 +6,17 @@ rec { unitOptions = { + enable = mkOption { + default = true; + types = types.bool; + description = '' + If set to false, this unit will be a symlink to + /dev/null. This is primarily useful to prevent specific + template instances (e.g. serial-getty@ttyS0) + from being started. + ''; + }; + description = mkOption { default = ""; types = types.uniq types.string; diff --git a/modules/system/boot/systemd.nix b/modules/system/boot/systemd.nix index dc0c2ba4504b..aa0b679ea2f5 100644 --- a/modules/system/boot/systemd.nix +++ b/modules/system/boot/systemd.nix @@ -10,7 +10,14 @@ let systemd = pkgs.systemd; makeUnit = name: unit: - pkgs.writeTextFile { name = "unit"; inherit (unit) text; destination = "/${name}"; }; + pkgs.runCommand "unit" { inherit (unit) text; } + (if unit.enable then '' + mkdir -p $out + echo -n "$text" > $out/${name} + '' else '' + mkdir -p $out + ln -s /dev/null $out/${name} + ''); upstreamUnits = [ # Targets. @@ -205,7 +212,7 @@ let as)); targetToUnit = name: def: - { inherit (def) wantedBy; + { inherit (def) wantedBy enable; text = '' [Unit] @@ -214,7 +221,7 @@ let }; serviceToUnit = name: def: - { inherit (def) wantedBy; + { inherit (def) wantedBy enable; text = '' [Unit] @@ -258,7 +265,7 @@ let }; socketToUnit = name: def: - { inherit (def) wantedBy; + { inherit (def) wantedBy enable; text = '' [Unit] @@ -333,6 +340,16 @@ in types = types.uniq types.string; description = "Text of this systemd unit."; }; + enable = mkOption { + default = true; + types = types.bool; + description = '' + If set to false, this unit will be a symlink to + /dev/null. This is primarily useful to prevent specific + template instances (e.g. serial-getty@ttyS0) + from being started. + ''; + }; wantedBy = mkOption { default = []; types = types.listOf types.string; diff --git a/modules/testing/test-instrumentation.nix b/modules/testing/test-instrumentation.nix index efce3153c88e..222a10a00435 100644 --- a/modules/testing/test-instrumentation.nix +++ b/modules/testing/test-instrumentation.nix @@ -13,9 +13,8 @@ let kernel = config.boot.kernelPackages.kernel; in boot.systemd.services.backdoor = { wantedBy = [ "multi-user.target" ]; - requires = [ "dev-hvc0.device" ]; - after = [ "dev-hvc0.device" ]; - + requires = [ "dev-hvc0.device" "dev-ttyS0.device" ]; + after = [ "dev-hvc0.device" "dev-ttyS0.device" ]; script = '' export USER=root @@ -27,10 +26,15 @@ let kernel = config.boot.kernelPackages.kernel; in echo "connecting to host..." >&2 stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion echo - PS1= /bin/sh + PS1= exec /bin/sh ''; }; + # Prevent agetty from being instantiated on ttyS0, since it + # interferes with the backdoor (writes to ttyS0 will randomly fail + # with EIO). + boot.systemd.services."serial-getty@ttyS0".enable = false; + boot.initrd.postDeviceCommands = '' # Using acpi_pm as a clock source causes the guest clock to diff --git a/tests/nat.nix b/tests/nat.nix index e2f01e71b263..7b03739a9bc4 100644 --- a/tests/nat.nix +++ b/tests/nat.nix @@ -40,6 +40,7 @@ startAll; # The router should have access to the server. + $server->waitForUnit("network.target"); $server->waitForUnit("httpd"); $router->waitForUnit("network.target"); $router->succeed("curl --fail http://server/ >&2"); @@ -68,7 +69,7 @@ $client->fail("ping -c 1 server >&2"); # And make sure that restarting the NAT job works. - $router->succeed("start nat"); + $router->succeed("systemctl start nat"); $client->succeed("curl --fail http://server/ >&2"); $client->succeed("ping -c 1 server >&2"); '';