When a service gains a `.socket` unit, the socket is not yet active, so
the `active_cur.contains_key(socket)` check is false and the service is
queued in `units_to_start`. That races with the socket unit being started
by `sockets.target`, producing "Socket service already active, refusing"
or "no socket activation file descriptors found" errors.
Treat the service as socket-activated whenever the socket is absent now
but present in the new configuration, leaving it to be activated on demand
by the newly started socket rather than started directly.
Fixes: https://github.com/NixOS/nixpkgs/pull/510391#issuecomment-4273511176
Assisted-by: Claude:claude-opus-4-8
A per-connection instance spawned by an Accept=yes socket (e.g.
foo@1234.service) has an implicit socket of foo.socket, but the implicit
name was derived from the template base name including the trailing "@",
yielding foo@.socket. That never matches an active unit, so such running
instances were treated as non-socket-activated and the activation script
tried to start them directly on a configuration switch. That fails
because there is no connection socket to pass, sending the instance into
a restart loop.
Strip the trailing "@" so the implicit socket resolves correctly; the
running instances are then stopped and their socket restarted, leaving
systemd to spawn fresh instances for new connections.
Resolves: https://github.com/NixOS/nixpkgs/issues/533205
Assisted-by: Claude:claude-opus-4-8
The previous `if ! ( ... )` wrapper put the check body in a context
where bash ignores `set -e`, so a failing command in the middle of a
check would not abort it and the switch would proceed. Run the
subshell outside any conditional and capture $? explicitly instead.
stc-ng starts every active target (including default.target) and then
explicitly restarts nixos-activation.service. As a Type=oneshot without
RemainAfterExit the unit is inactive after login, so the default.target
start job re-runs it via Wants=, and the explicit restart runs it again
(or, depending on ordering, SIGTERMs the currently running script and re-runs it).
Set RemainAfterExit=yes so target starts are a no-op for an already-run
activation, and restartIfChanged=false so the unit-diff pass leaves it
alone when the script changes. The explicit restart in stc-ng remains
the single trigger per switch. Print that restart so it is visible in
the switch output, and drop it from the "NOT restarting" list.
Extend the user-activation-scripts test to assert the activation is
only run once, and never killed.
The previous "FragmentPath not under /etc" deny-list swept up units that
were never managed by a per-user manager (e.g. dbus-broker, whose
FragmentPath systemd reports under /run/current-system/sw/share via
systemd.packages) and missed nothing it should have caught, but for the
wrong reason.
Make the intent explicit. A unit is a migration candidate iff it is
active, the new generation defines it in /etc/systemd/user, and either
* its FragmentPath is under $XDG_CONFIG_HOME/systemd/user (the
home-manager case; ~/.config shadows /etc, so we must wait for
sd-switch to remove the copy), or
* its FragmentPath is anywhere else outside /etc and the previous
generation did not have it in /etc (package-shipped units found via
$XDG_DATA_HOME / $XDG_DATA_DIRS, e.g. ~/.nix-profile/share; /etc
outranks these so it wins on daemon-reload).
The "previous generation did not have it" guard keeps units that have
always been in /etc, but whose FragmentPath systemd reports elsewhere, out
of the candidate set, and the existing now_etc check verifies /etc
actually won before acting. Compare FragmentPath by parent directory
instead of string prefix while here.
Covered by a new switch-test case that seeds a unit in
~/.local/share/systemd/user.
The post-activation pass added in 5cc82c4922 to handle units migrating
from a per-user manager (home-manager) to NixOS unconditionally restarts
or starts any candidate. dbus-broker.service explicitly opts out of
restarts via reloadIfChanged because restarting the session bus kills
running clients; the second pass ignored that and restarted it anyway.
Apply the same X-ReloadIfChanged / X-RestartIfChanged / RefuseManualStop /
RefuseManualStart / X-OnlyManualStart checks that handle_modified_unit
performs, so a migrated unit is reloaded, skipped, restarted or started
as its directives require.
Covered by new switch-test specialisations for reloadIfChanged and
restartIfChanged = false.
Simulate a home-manager-style unit in ~/.config/systemd/user and verify
switch-to-configuration takes it over after the per-user activation
drops it (both stopped and left-running variants), and leaves it alone
while still shadowed.
Add a lingering test user plus specialisations covering stop-start,
stopIfChanged=false, reloadIfChanged, reloadTriggers, and removal for
systemd.user.services so the new user-scope diff/restart path in
switch-to-configuration-ng is exercised.
The check ran `realpath /run/current-system` under errexit, so a
missing current-system symlink aborted the script.
Drop the realpath calls (the -f test and jq already follow symlinks)
and use a static store path for the empty fallback instead of mktemp/trap.
Also exempt dry-activate, which makes no state changes and was being
blocked from showing its diff, and let jq fail loudly on malformed
inhibitor JSON instead of silently treating it as empty.
Mount options changing for the same mountpoint means we perform a unit
reload as opposed to a unit restart. If a mount unit is not active (for
example, with a mount unit that is failing), then we need to start the
unit instead. Since we do some of the work that the fstab generator
already does, we parse /etc/fstab and derive mount unit names that we
should start ourselves. We cannot expect those units to be present in
/etc/systemd/system, however, which we currently do in order to
determine whether we should _not_ start the inactive unit.
Improvements:
1. Turn the nix value into an attrset so that every inhibitor has a name
that we can match between generations
2. Write the attrset to a file as JSON
3. When checking, we load the JSON files from both the current and the
new generation into a jq pipeline and match up the keys.
We output a dict with a value for every key that is present in both
generations with a different value.
4. Build in error handling for different corner cases (missing files,
non-JSON content)
Shuffle:
The definitions are now combined into a single option. Since they have
no interdependencies, that's ok, but you may notice this trivial change
by a changed hash, and analyzing with nix-diff.
Deprecation:
Use the option `system.systemBuilderCommands` instead.
Format all Nix files using the officially approved formatter,
making the CI check introduced in the previous commit succeed:
nix-build ci -A fmt.check
This is the next step of the of the [implementation](https://github.com/NixOS/nixfmt/issues/153)
of the accepted [RFC 166](https://github.com/NixOS/rfcs/pull/166).
This commit will lead to merge conflicts for a number of PRs,
up to an estimated ~1100 (~33%) among the PRs with activity in the past 2
months, but that should be lower than what it would be without the previous
[partial treewide format](https://github.com/NixOS/nixpkgs/pull/322537).
Merge conflicts caused by this commit can now automatically be resolved while rebasing using the
[auto-rebase script](8616af08d9/maintainers/scripts/auto-rebase).
If you run into any problems regarding any of this, please reach out to the
[formatting team](https://nixos.org/community/teams/formatting/) by
pinging @NixOS/nix-formatting.
This allows for instance to reject switching into a configuration, while
still allowing to reboot into that same configuration.
This can be useful for instance to reject switching to a configuration
with a new systemd major version, but setting that same configuration as
the new boot default with `switch-to-configuration boot` is fine.
A couple of improvements:
1. Avoid the generally discouraged apply argument to options, as it has
quite weird semantics
2. Avoid issues when a user calls a preSwitchCheck `script`, which
would've been silently overridden by the existing implementation.
Reliance on a special attribute name like that is bound to lead to a
very-hard-to-debug problem for someone at some point
3. Use writeShellApplication so that the preSwitchChecks are checked by
shellcheck and and so that they run with basic bash guardrails
4. Fix shellcheck issue (testing the value of $?)
5. Add a positive preSwitchCheck to the nixos test, to make sure that
that works as intended
The newer runTest handler uses a single nixpkgs instance to eval all the
specialisations, reducing the memory usage and eval time of the test
drastically compared to handleTest which creates a new nixpkgs instance
for every specialisation.
Add an option for shell script fragments that are ran before switching
to a new NixOS system configuration (pre installation of bootloader or
system activation). Also add a new subcommand for
switch-to-configuration called "check" that will cause the program to
always exit after checks are ran.
Previously, the base system had grub in `systemPackages` but the
specialisations did not. This is because of a few factors:
- Grub was enabled in the nixos config
- Specialisations set `grub.device = "nodev"` (see: system/activation/no-clone.nix)
- Grub is added to `systemPackages` depending on whether `devices == ["nodev"]`
This meant that switching between the base system and a specialisation
always changed `system-path.drv`, which is a reload trigger for
dbus. With grub disabled in this test, this no longer happens.
This adds an implementation of switch-to-configuration that allows for
closer interaction with the lifecycle of systemd units by using DBus
APIs directly instead of using systemctl. It is disabled by default, but
can be enabled by specifying `{ system.switch = { enable = false; enableNg = true; }; }`.
We should sometimes restart the units rather than reloading them so the
changes are actually applied. / and /nix are explicitly excluded because
there was some very old issue where these were unmounted. I don't think
this will affect many people since most people use fstab mounts instead
but I plan to adapt this behavior for fstab mounts as well in the future
(once I wrote a test for the fstab thingies).