Unverified Commit c92e6127 authored by Vladimír Čunát's avatar Vladimír Čunát Committed by GitHub
Browse files

staging-nixos merge for 2025-11-12 (#460995)

parents 6142482b ccea08b7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -397,6 +397,8 @@ and [release notes for v18](https://goteleport.com/docs/changelog/#1800-070325).
  - In all other cases, you'll need to set this option to `true` yourself.
  - `boot.isNspawnContainer` being `true` implies [](#opt-boot.isContainer) being `true`.

- `users.users.*.linger` now defaults to `null` rather than `false`, meaning NixOS will not attempt to enable or disable lingering for that user account, instead allowing for imperative control over lingering using the `loginctl` commands. In practice, this is unlikely to make a difference for most people, as new users are created without lingering configured. There is a new, related option, `users.manageLingering`, which can be used to prevent NixOS attempting to manage lingering entirely.

- Due to [deprecation of gnome-session X11 support](https://blogs.gnome.org/alatiera/2025/06/08/the-x11-session-removal/), `services.desktopManager.pantheon` now defaults to pantheon-wayland session. The X11 session has been removed, see [this issue](https://github.com/elementary/session-settings/issues/91) for details.

- `bcachefs` file systems will now use the out-of-tree module for supported kernels. The in-tree module has been removed, and users will need to switch to kernels that support the out-of-tree module.
+74 −26
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ let
    any
    attrNames
    attrValues
    boolToString
    concatMap
    concatMapStringsSep
    concatStrings
@@ -43,6 +44,7 @@ let
    stringLength
    trace
    types
    versionOlder
    xor
    ;

@@ -455,16 +457,21 @@ let
        };

        linger = mkOption {
          type = types.bool;
          default = false;
          type = types.nullOr types.bool;
          example = true;
          default = null;
          description = ''
            Whether to enable lingering for this user. If true, systemd user
            units will start at boot, rather than starting at login and stopping
            at logout. This is the declarative equivalent of running
            `loginctl enable-linger` for this user.

            If false, user units will not be started until the user logs in, and
            may be stopped on logout depending on the settings in `logind.conf`.
            Whether to enable or disable lingering for this user.  Without
            lingering, user units will not be started until the user logs in,
            and may be stopped on logout depending on the settings in
            `logind.conf`.

            By default, NixOS will not manage lingering, new users will default
            to not lingering, and lingering can be configured imperatively using
            `loginctl enable-linger` or `loginctl disable-linger`. Setting
            this option to `true` or `false` is the declarative equivalent of
            running `loginctl enable-linger` or `loginctl disable-linger`
            respectively.
          '';
        };
      };
@@ -661,8 +668,6 @@ let
      shells = mapAttrsToList (_: u: u.shell) cfg.users;
    in
    filter types.shellPackage.check shells;

  lingeringUsers = map (u: u.name) (attrValues (flip filterAttrs cfg.users (n: u: u.linger)));
in
{
  imports = [
@@ -710,6 +715,13 @@ in
      '';
    };

    users.manageLingering = mkOption {
      type = types.bool;
      default = true;
      description = "Whether to manage whether users linger or not.";
      example = false;
    };

    users.users = mkOption {
      default = { };
      type = with types; attrsOf (submodule userOpts);
@@ -894,32 +906,52 @@ in
        else
          ""; # keep around for backwards compatibility

      systemd.services.linger-users = lib.mkIf ((length lingeringUsers) > 0) {
      systemd.services.linger-users = lib.mkIf cfg.manageLingering {
        wantedBy = [ "multi-user.target" ];
        after = [ "systemd-logind.service" ];
        requires = [ "systemd-logind.service" ];

        script =
          let
            lingerDir = "/var/lib/systemd/linger";
            lingeringUsersFile = builtins.toFile "lingering-users" (
              concatStrings (map (s: "${s}\n") (sort (a: b: a < b) lingeringUsers))
            ); # this sorting is important for `comm` to work correctly
            lingeringUsers = filterAttrs (n: v: v.linger == true) cfg.users;
            nonLingeringUsers = filterAttrs (n: v: v.linger == false) cfg.users;
            lingeringUserNames = mapAttrsToList (n: v: v.name) lingeringUsers;
            nonLingeringUserNames = mapAttrsToList (n: v: v.name) nonLingeringUsers;
          in
          ''
            mkdir -vp ${lingerDir}
            cd ${lingerDir}
            for user in $(ls); do
              if ! id "$user" >/dev/null; then
                echo "Removing linger for missing user $user"
                rm --force -- "$user"
            ${lib.strings.toShellVars { inherit lingeringUserNames nonLingeringUserNames; }}

            user_configured () {
                # Use `id` to check if the user exists rather than checking the
                # NixOS configuration, as it may be that the user has been
                # manually configured, which is permitted if users.mutableUsers
                # is true (the default).
                id "$1" >/dev/null
            }

            shopt -s dotglob nullglob
            for user in *; do
                if ! user_configured "$user"; then
                    # systemd has this user configured to linger despite them not
                    # existing.
                    echo "Removing linger for missing user $user" >&2
                    rm -- "$user"
                fi
            done
            ls | sort | comm -3 -1 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl disable-linger
            ls | sort | comm -3 -2 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl  enable-linger

            if (( ''${#nonLingeringUserNames[*]} > 0 )); then
                ${config.systemd.package}/bin/loginctl disable-linger "''${nonLingeringUserNames[@]}"
            fi
            if (( ''${#lingeringUserNames[*]} > 0 )); then
                ${config.systemd.package}/bin/loginctl enable-linger "''${lingeringUserNames[@]}"
            fi
          '';

        serviceConfig.Type = "oneshot";
        serviceConfig = {
          Type = "oneshot";
          StateDirectory = "systemd/linger";
          WorkingDirectory = "/var/lib/systemd/linger";
        };
      };

      # Warn about user accounts with deprecated password hashing schemes
@@ -1163,6 +1195,22 @@ in
                users.groups.${user.name} = {};
              '';
            }
            {
              assertion = user.linger != null -> cfg.manageLingering;
              message = ''
                users.manageLingering is set to false, but
                users.users.${user.name}.linger is configured.

                If you want NixOS to manage whether user accounts linger or
                not, you must set users.manageLingering to true.  This is the
                default setting.

                If you do not want NixOS to manage whether user accounts linger
                or not, you must set users.users.${user.name}.linger to null.
                This is the default setting provided system.stateVersion is at
                least "25.11".
              '';
            }
          ]
          ++ (map
            (shell: {
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
  boot.kexec.enable = lib.mkDefault false;
  # Relies on bash scripts
  powerManagement.enable = lib.mkDefault false;
  users.manageLingering = lib.mkDefault false;
  # Relies on the gzip command which depends on bash
  services.logrotate.enable = lib.mkDefault false;

+1 −0
Original line number Diff line number Diff line
@@ -1522,6 +1522,7 @@ in
  systemd-sysusers-password-option-override-ordering = runTest ./systemd-sysusers-password-option-override-ordering.nix;
  systemd-timesyncd-nscd-dnssec = runTest ./systemd-timesyncd-nscd-dnssec.nix;
  systemd-user-linger = runTest ./systemd-user-linger.nix;
  systemd-user-linger-purge = runTest ./systemd-user-linger-purge.nix;
  systemd-user-tmpfiles-rules = runTest ./systemd-user-tmpfiles-rules.nix;
  systemd-userdbd = runTest ./systemd-userdbd.nix;
  systemtap = handleTest ./systemtap.nix { };
+37 −0
Original line number Diff line number Diff line
# This test checks #418101, where lingering users would not be cleared up if
# the configuration is updated to remove lingering from all users.
rec {
  name = "systemd-user-linger-purge";

  nodes.machine = {
    users.users = {
      bob = {
        isNormalUser = true;
        linger = false;
        uid = 1001;
      };
    };
  };

  testScript =
    let
      uidStrings = builtins.mapAttrs (k: v: builtins.toString v.uid) nodes.machine.users.users;
    in
    ''
      machine.fail("test -e /var/lib/systemd/linger/bob")
      machine.fail("systemctl status user-${uidStrings.bob}.slice")

      with subtest("missing users have linger purged"):
          machine.succeed("touch /var/lib/systemd/linger/alice")
          machine.systemctl("restart linger-users")
          machine.succeed("test ! -e /var/lib/systemd/linger/alice")

      with subtest("mutable users can linger"):
          machine.succeed("useradd alice")
          machine.succeed("test ! -e /var/lib/systemd/linger/alice")
          machine.succeed("loginctl enable-linger alice")
          machine.succeed("test -e /var/lib/systemd/linger/alice")
          machine.systemctl("restart linger-users")
          machine.succeed("test -e /var/lib/systemd/linger/alice")
    '';
}
Loading