diff options
Diffstat (limited to 'nixos/modules/config')
-rw-r--r-- | nixos/modules/config/console.nix | 7 | ||||
-rw-r--r-- | nixos/modules/config/fanout.nix | 49 | ||||
-rw-r--r-- | nixos/modules/config/gnu.nix | 43 | ||||
-rw-r--r-- | nixos/modules/config/iproute2.nix | 17 | ||||
-rw-r--r-- | nixos/modules/config/mysql.nix | 4 | ||||
-rw-r--r-- | nixos/modules/config/nix-channel.nix | 10 | ||||
-rw-r--r-- | nixos/modules/config/qt.nix | 165 | ||||
-rw-r--r-- | nixos/modules/config/stevenblack.nix | 4 | ||||
-rw-r--r-- | nixos/modules/config/system-path.nix | 19 | ||||
-rw-r--r-- | nixos/modules/config/terminfo.nix | 5 | ||||
-rw-r--r-- | nixos/modules/config/users-groups.nix | 81 |
11 files changed, 251 insertions, 153 deletions
diff --git a/nixos/modules/config/console.nix b/nixos/modules/config/console.nix index 1e8bb78f302..0a931c6918f 100644 --- a/nixos/modules/config/console.nix +++ b/nixos/modules/config/console.nix @@ -127,8 +127,8 @@ in ${optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT) "-I${config.environment.sessionVariables.XKB_CONFIG_ROOT}" } \ - -model '${xkbModel}' -layout '${layout}' \ - -option '${xkbOptions}' -variant '${xkbVariant}' > "$out" + -model '${xkb.model}' -layout '${xkb.layout}' \ + -option '${xkb.options}' -variant '${xkb.variant}' > "$out" ''); } @@ -168,6 +168,9 @@ in # ...but only the keymaps if we don't "/etc/kbd/keymaps" = lib.mkIf (!cfg.earlySetup) { source = "${consoleEnv config.boot.initrd.systemd.package.kbd}/share/keymaps"; }; }; + boot.initrd.systemd.additionalUpstreamUnits = [ + "systemd-vconsole-setup.service" + ]; boot.initrd.systemd.storePaths = [ "${config.boot.initrd.systemd.package}/lib/systemd/systemd-vconsole-setup" "${config.boot.initrd.systemd.package.kbd}/bin/setfont" diff --git a/nixos/modules/config/fanout.nix b/nixos/modules/config/fanout.nix new file mode 100644 index 00000000000..60ee145f19a --- /dev/null +++ b/nixos/modules/config/fanout.nix @@ -0,0 +1,49 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.fanout; + mknodCmds = n: lib.lists.imap0 (i: s: + "mknod /dev/fanout${builtins.toString i} c $MAJOR ${builtins.toString i}" + ) (lib.lists.replicate n ""); +in +{ + options.services.fanout = { + enable = lib.mkEnableOption (lib.mdDoc "fanout"); + fanoutDevices = lib.mkOption { + type = lib.types.int; + default = 1; + description = "Number of /dev/fanout devices"; + }; + bufferSize = lib.mkOption { + type = lib.types.int; + default = 16384; + description = "Size of /dev/fanout buffer in bytes"; + }; + }; + + config = lib.mkIf cfg.enable { + boot.extraModulePackages = [ config.boot.kernelPackages.fanout.out ]; + + boot.kernelModules = [ "fanout" ]; + + boot.extraModprobeConfig = '' + options fanout buffersize=${builtins.toString cfg.bufferSize} + ''; + + systemd.services.fanout = { + description = "Bring up /dev/fanout devices"; + script = '' + MAJOR=$(${pkgs.gnugrep}/bin/grep fanout /proc/devices | ${pkgs.gawk}/bin/awk '{print $1}') + ${lib.strings.concatLines (mknodCmds cfg.fanoutDevices)} + ''; + + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + RemainAfterExit = "yes"; + Restart = "no"; + }; + }; + }; +} diff --git a/nixos/modules/config/gnu.nix b/nixos/modules/config/gnu.nix deleted file mode 100644 index a47d299b226..00000000000 --- a/nixos/modules/config/gnu.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - options = { - gnu = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc '' - When enabled, GNU software is chosen by default whenever a there is - a choice between GNU and non-GNU software (e.g., GNU lsh - vs. OpenSSH). - ''; - }; - }; - - config = lib.mkIf config.gnu { - - environment.systemPackages = with pkgs; - # TODO: Adjust `requiredPackages' from `system-path.nix'. - # TODO: Add Inetutils once it has the new `ifconfig'. - [ parted - #fdisk # XXX: GNU fdisk currently fails to build and it's redundant - # with the `parted' command. - nano zile - texinfo # for the stand-alone Info reader - ] - ++ lib.optional (!stdenv.isAarch32) grub2; - - - # GNU GRUB, where available. - boot.loader.grub.enable = !pkgs.stdenv.isAarch32; - - # GNU lsh. - services.openssh.enable = false; - services.lshd.enable = true; - programs.ssh.startAgent = false; - services.xserver.startGnuPGAgent = true; - - # TODO: GNU dico. - # TODO: GNU Inetutils' inetd. - # TODO: GNU Pies. - }; -} diff --git a/nixos/modules/config/iproute2.nix b/nixos/modules/config/iproute2.nix index 8f49e7dbf7d..78bd07d680e 100644 --- a/nixos/modules/config/iproute2.nix +++ b/nixos/modules/config/iproute2.nix @@ -7,7 +7,7 @@ let in { options.networking.iproute2 = { - enable = mkEnableOption (lib.mdDoc "copy IP route configuration files"); + enable = mkEnableOption (lib.mdDoc "copying IP route configuration files"); rttablesExtraConfig = mkOption { type = types.lines; default = ""; @@ -18,15 +18,10 @@ in }; config = mkIf cfg.enable { - environment.etc."iproute2/bpf_pinning" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/bpf_pinning"; }; - environment.etc."iproute2/ematch_map" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/ematch_map"; }; - environment.etc."iproute2/group" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/group"; }; - environment.etc."iproute2/nl_protos" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/nl_protos"; }; - environment.etc."iproute2/rt_dsfield" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/rt_dsfield"; }; - environment.etc."iproute2/rt_protos" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/rt_protos"; }; - environment.etc."iproute2/rt_realms" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/rt_realms"; }; - environment.etc."iproute2/rt_scopes" = { mode = "0644"; text = fileContents "${pkgs.iproute2}/etc/iproute2/rt_scopes"; }; - environment.etc."iproute2/rt_tables" = { mode = "0644"; text = (fileContents "${pkgs.iproute2}/etc/iproute2/rt_tables") - + (optionalString (cfg.rttablesExtraConfig != "") "\n\n${cfg.rttablesExtraConfig}"); }; + environment.etc."iproute2/rt_tables" = { + mode = "0644"; + text = (fileContents "${pkgs.iproute2}/lib/iproute2/rt_tables") + + (optionalString (cfg.rttablesExtraConfig != "") "\n\n${cfg.rttablesExtraConfig}"); + }; }; } diff --git a/nixos/modules/config/mysql.nix b/nixos/modules/config/mysql.nix index 2f13c56f2ae..95c9ba76663 100644 --- a/nixos/modules/config/mysql.nix +++ b/nixos/modules/config/mysql.nix @@ -429,11 +429,11 @@ in ''; }; - # Activation script to append the password from the password file + # preStart script to append the password from the password file # to the configuration files. It also fixes the owner of the # libnss-mysql-root.cfg because it is changed to root after the # password is appended. - system.activationScripts.mysql-auth-passwords = '' + systemd.services.mysql.preStart = '' if [[ -r ${cfg.passwordFile} ]]; then org_umask=$(umask) umask 0077 diff --git a/nixos/modules/config/nix-channel.nix b/nixos/modules/config/nix-channel.nix index 3f8e088ede9..a7ca7a5c74a 100644 --- a/nixos/modules/config/nix-channel.nix +++ b/nixos/modules/config/nix-channel.nix @@ -97,12 +97,8 @@ in nix.settings.nix-path = mkIf (! cfg.channel.enable) (mkDefault ""); - system.activationScripts.nix-channel = mkIf cfg.channel.enable - (stringAfter [ "etc" "users" ] '' - # Subscribe the root user to the NixOS channel by default. - if [ ! -e "/root/.nix-channels" ]; then - echo "${config.system.defaultChannel} nixos" > "/root/.nix-channels" - fi - ''); + systemd.tmpfiles.rules = lib.mkIf cfg.channel.enable [ + ''f /root/.nix-channels - - - - ${config.system.defaultChannel} nixos\n'' + ]; }; } diff --git a/nixos/modules/config/qt.nix b/nixos/modules/config/qt.nix index 2b09281e467..f82b7ab85a8 100644 --- a/nixos/modules/config/qt.nix +++ b/nixos/modules/config/qt.nix @@ -1,121 +1,154 @@ { config, lib, pkgs, ... }: -with lib; - let - cfg = config.qt; - isQGnome = cfg.platformTheme == "gnome" && builtins.elem cfg.style ["adwaita" "adwaita-dark"]; - isQtStyle = cfg.platformTheme == "gtk2" && !(builtins.elem cfg.style ["adwaita" "adwaita-dark"]); - isQt5ct = cfg.platformTheme == "qt5ct"; - isLxqt = cfg.platformTheme == "lxqt"; - isKde = cfg.platformTheme == "kde"; - - packages = - if isQGnome then [ - pkgs.qgnomeplatform - pkgs.adwaita-qt - pkgs.qgnomeplatform-qt6 - pkgs.adwaita-qt6 - ] - else if isQtStyle then [ pkgs.libsForQt5.qtstyleplugins pkgs.qt6Packages.qt6gtk2 ] - else if isQt5ct then [ pkgs.libsForQt5.qt5ct pkgs.qt6Packages.qt6ct ] - else if isLxqt then [ pkgs.lxqt.lxqt-qtplugin pkgs.lxqt.lxqt-config ] - else if isKde then [ pkgs.libsForQt5.plasma-integration pkgs.libsForQt5.systemsettings ] - else throw "`qt.platformTheme` ${cfg.platformTheme} and `qt.style` ${cfg.style} are not compatible."; + platformPackages = with pkgs; { + gnome = [ qgnomeplatform qgnomeplatform-qt6 ]; + gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ]; + kde = [ libsForQt5.plasma-integration libsForQt5.systemsettings ]; + lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ]; + qt5ct = [ libsForQt5.qt5ct qt6Packages.qt6ct ]; + }; + + stylePackages = with pkgs; { + bb10bright = [ libsForQt5.qtstyleplugins ]; + bb10dark = [ libsForQt5.qtstyleplugins ]; + cde = [ libsForQt5.qtstyleplugins ]; + cleanlooks = [ libsForQt5.qtstyleplugins ]; + gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ]; + motif = [ libsForQt5.qtstyleplugins ]; + plastique = [ libsForQt5.qtstyleplugins ]; -in + adwaita = [ adwaita-qt adwaita-qt6 ]; + adwaita-dark = [ adwaita-qt adwaita-qt6 ]; + adwaita-highcontrast = [ adwaita-qt adwaita-qt6 ]; + adwaita-highcontrastinverse = [ adwaita-qt adwaita-qt6 ]; + + breeze = [ libsForQt5.breeze-qt5 ]; + kvantum = [ libsForQt5.qtstyleplugin-kvantum qt6Packages.qtstyleplugin-kvantum ]; + }; +in { - meta.maintainers = [ maintainers.romildo ]; + meta.maintainers = with lib.maintainers; [ romildo thiagokokada ]; imports = [ - (mkRenamedOptionModule ["qt5" "enable" ] ["qt" "enable" ]) - (mkRenamedOptionModule ["qt5" "platformTheme" ] ["qt" "platformTheme" ]) - (mkRenamedOptionModule ["qt5" "style" ] ["qt" "style" ]) + (lib.mkRenamedOptionModule [ "qt5" "enable" ] [ "qt" "enable" ]) + (lib.mkRenamedOptionModule [ "qt5" "platformTheme" ] [ "qt" "platformTheme" ]) + (lib.mkRenamedOptionModule [ "qt5" "style" ] [ "qt" "style" ]) ]; options = { qt = { + enable = lib.mkEnableOption "" // { + description = lib.mdDoc '' + Whether to enable Qt configuration, including theming. - enable = mkEnableOption (lib.mdDoc "Qt theming configuration"); + Enabling this option is necessary for Qt plugins to work in the + installed profiles (e.g.: `nix-env -i` or `environment.systemPackages`). + ''; + }; - platformTheme = mkOption { - type = types.enum [ - "gtk2" - "gnome" - "lxqt" - "qt5ct" - "kde" - ]; + platformTheme = lib.mkOption { + type = with lib.types; nullOr (enum (lib.attrNames platformPackages)); + default = null; example = "gnome"; relatedPackages = [ "qgnomeplatform" "qgnomeplatform-qt6" - ["libsForQt5" "qtstyleplugins"] - ["libsForQt5" "qt5ct"] - ["lxqt" "lxqt-qtplugin"] - ["libsForQt5" "plasma-integration"] + [ "libsForQt5" "plasma-integration" ] + [ "libsForQt5" "qt5ct" ] + [ "libsForQt5" "qtstyleplugins" ] + [ "libsForQt5" "systemsettings" ] + [ "lxqt" "lxqt-config" ] + [ "lxqt" "lxqt-qtplugin" ] + [ "qt6Packages" "qt6ct" ] + [ "qt6Packages" "qt6gtk2" ] ]; description = lib.mdDoc '' Selects the platform theme to use for Qt applications. The options are - - `gtk`: Use GTK theme with [qtstyleplugins](https://github.com/qt/qtstyleplugins) - `gnome`: Use GNOME theme with [qgnomeplatform](https://github.com/FedoraQt/QGnomePlatform) + - `gtk2`: Use GTK theme with [qtstyleplugins](https://github.com/qt/qtstyleplugins) + - `kde`: Use Qt settings from Plasma. - `lxqt`: Use LXQt style set using the [lxqt-config-appearance](https://github.com/lxqt/lxqt-config) application. - `qt5ct`: Use Qt style set using the [qt5ct](https://sourceforge.net/projects/qt5ct/) - application. - - `kde`: Use Qt settings from Plasma. + and [qt6ct](https://github.com/trialuser02/qt6ct) applications. ''; }; - style = mkOption { - type = types.enum [ - "adwaita" - "adwaita-dark" - "cleanlooks" - "gtk2" - "motif" - "plastique" - ]; + style = lib.mkOption { + type = with lib.types; nullOr (enum (lib.attrNames stylePackages)); + default = null; example = "adwaita"; relatedPackages = [ "adwaita-qt" "adwaita-qt6" - ["libsForQt5" "qtstyleplugins"] - ["qt6Packages" "qt6gtk2"] + [ "libsForQt5" "breeze-qt5" ] + [ "libsForQt5" "qtstyleplugin-kvantum" ] + [ "libsForQt5" "qtstyleplugins" ] + [ "qt6Packages" "qt6gtk2" ] + [ "qt6Packages" "qtstyleplugin-kvantum" ] ]; description = lib.mdDoc '' Selects the style to use for Qt applications. The options are - - `adwaita`, `adwaita-dark`: Use Adwaita Qt style with + - `adwaita`, `adwaita-dark`, `adwaita-highcontrast`, `adawaita-highcontrastinverse`: + Use Adwaita Qt style with [adwaita](https://github.com/FedoraQt/adwaita-qt) - - `cleanlooks`, `gtk2`, `motif`, `plastique`: Use styles from + - `breeze`: Use the Breeze style from + [breeze](https://github.com/KDE/breeze) + - `bb10bright`, `bb10dark`, `cleanlooks`, `gtk2`, `motif`, `plastique`: + Use styles from [qtstyleplugins](https://github.com/qt/qtstyleplugins) + - `kvantum`: Use styles from + [kvantum](https://github.com/tsujan/Kvantum) ''; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + assertions = + let + gnomeStyles = [ + "adwaita" + "adwaita-dark" + "adwaita-highcontrast" + "adwaita-highcontrastinverse" + "breeze" + ]; + in + [ + { + assertion = cfg.platformTheme == "gnome" -> (builtins.elem cfg.style gnomeStyles); + message = '' + `qt.platformTheme` "gnome" must have `qt.style` set to a theme that supports both Qt and Gtk, + for example: ${lib.concatStringsSep ", " gnomeStyles}. + ''; + } + ]; environment.variables = { - QT_QPA_PLATFORMTHEME = cfg.platformTheme; - QT_STYLE_OVERRIDE = mkIf (! (isQt5ct || isLxqt || isKde)) cfg.style; + QT_QPA_PLATFORMTHEME = lib.mkIf (cfg.platformTheme != null) cfg.platformTheme; + QT_STYLE_OVERRIDE = lib.mkIf (cfg.style != null) cfg.style; }; - environment.profileRelativeSessionVariables = let - qtVersions = with pkgs; [ qt5 qt6 ]; - in { - QT_PLUGIN_PATH = map (qt: "/${qt.qtbase.qtPluginPrefix}") qtVersions; - QML2_IMPORT_PATH = map (qt: "/${qt.qtbase.qtQmlPrefix}") qtVersions; - }; - - environment.systemPackages = packages; + environment.profileRelativeSessionVariables = + let + qtVersions = with pkgs; [ qt5 qt6 ]; + in + { + QT_PLUGIN_PATH = map (qt: "/${qt.qtbase.qtPluginPrefix}") qtVersions; + QML2_IMPORT_PATH = map (qt: "/${qt.qtbase.qtQmlPrefix}") qtVersions; + }; + environment.systemPackages = + lib.optionals (cfg.platformTheme != null) (platformPackages.${cfg.platformTheme}) + ++ lib.optionals (cfg.style != null) (stylePackages.${cfg.style}); }; } diff --git a/nixos/modules/config/stevenblack.nix b/nixos/modules/config/stevenblack.nix index 07a0aa339a5..7e623516984 100644 --- a/nixos/modules/config/stevenblack.nix +++ b/nixos/modules/config/stevenblack.nix @@ -15,7 +15,7 @@ let in { options.networking.stevenblack = { - enable = mkEnableOption (mdDoc "Enable the stevenblack hosts file blocklist"); + enable = mkEnableOption (mdDoc "the stevenblack hosts file blocklist"); block = mkOption { type = types.listOf (types.enum [ "fakenews" "gambling" "porn" "social" ]); @@ -30,5 +30,5 @@ in ++ optionals (activatedHosts == [ ]) [ "${pkgs.stevenblack-blocklist}/hosts" ]; }; - meta.maintainers = [ maintainers.fortuneteller2k maintainers.artturin ]; + meta.maintainers = [ maintainers.moni maintainers.artturin ]; } diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index e8bbeac4f72..71274ea8999 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -42,8 +42,7 @@ let ]; defaultPackageNames = - [ "nano" - "perl" + [ "perl" "rsync" "strace" ]; @@ -90,12 +89,6 @@ in for a running system, entries can be removed for a more minimal NixOS installation. - Note: If `pkgs.nano` is removed from this list, - make sure another editor is installed and the - `EDITOR` environment variable is set to it. - Environment variables can be set using - {option}`environment.variables`. - Like with systemPackages, packages are installed to {file}`/run/current-system/sw`. They are automatically available to all users, and are @@ -116,8 +109,14 @@ in extraOutputsToInstall = mkOption { type = types.listOf types.str; default = [ ]; - example = [ "doc" "info" "devdoc" ]; - description = lib.mdDoc "List of additional package outputs to be symlinked into {file}`/run/current-system/sw`."; + example = [ "dev" "info" ]; + description = lib.mdDoc '' + Entries listed here will be appended to the `meta.outputsToInstall` attribute for each package in `environment.systemPackages`, and the files from the corresponding derivation outputs symlinked into {file}`/run/current-system/sw`. + + For example, this can be used to install the `dev` and `info` outputs for all packages in the system environment, if they are available. + + To use specific outputs instead of configuring them globally, select the corresponding attribute on the package derivation, e.g. `libxml2.dev` or `coreutils.info`. + ''; }; extraSetup = mkOption { diff --git a/nixos/modules/config/terminfo.nix b/nixos/modules/config/terminfo.nix index d1dbc4e0d05..ebd1aaea8f0 100644 --- a/nixos/modules/config/terminfo.nix +++ b/nixos/modules/config/terminfo.nix @@ -16,10 +16,7 @@ with lib; }; security.sudo.keepTerminfo = mkOption { - default = config.security.sudo.package.pname != "sudo-rs"; - defaultText = literalMD '' - `true` unless using `sudo-rs` - ''; + default = true; type = types.bool; description = lib.mdDoc '' Whether to preserve the `TERMINFO` and `TERMINFO_DIRS` diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 785084209b0..39aac9fb821 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -153,7 +153,7 @@ let {file}`pam_mount.conf.xml`. Useful attributes might include `path`, `options`, `fstype`, and `server`. - See <http://pam-mount.sourceforge.net/pam_mount.conf.5.html> + See <https://pam-mount.sourceforge.net/pam_mount.conf.5.html> for more information. ''; }; @@ -172,6 +172,17 @@ let ''; }; + ignoreShellProgramCheck = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + By default, nixos will check that programs.SHELL.enable is set to + true if the user has a custom shell specified. If that behavior isn't + required and there are custom overrides in place to make sure that the + shell is functional, set this to true. + ''; + }; + subUidRanges = mkOption { type = with types; listOf (submodule subordinateUidRange); default = []; @@ -330,6 +341,20 @@ let administrator before being able to use the system again. ''; }; + + linger = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + 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`. + ''; + }; }; config = mkMerge @@ -449,6 +474,8 @@ let gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.groups) "gid"; sdInitrdUidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) config.boot.initrd.systemd.users) "uid"; sdInitrdGidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) config.boot.initrd.systemd.groups) "gid"; + groupNames = lib.mapAttrsToList (n: g: g.name) cfg.groups; + usersWithoutExistingGroup = lib.filterAttrs (n: u: !lib.elem u.group groupNames) cfg.users; spec = pkgs.writeText "users-groups.json" (builtins.toJSON { inherit (cfg) mutableUsers; @@ -579,6 +606,14 @@ in { defaultText = literalExpression "config.users.users.\${name}.group"; default = cfg.users.${name}.group; }; + options.shell = mkOption { + type = types.passwdEntry types.path; + description = '' + The path to the user's shell in initrd. + ''; + default = "${pkgs.shadow}/bin/nologin"; + defaultText = literalExpression "\${pkgs.shadow}/bin/nologin"; + }; })); }; @@ -661,6 +696,20 @@ in { ''; }; + system.activationScripts.update-lingering = let + lingerDir = "/var/lib/systemd/linger"; + lingeringUsers = map (u: u.name) (attrValues (flip filterAttrs cfg.users (n: u: u.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 + in stringAfter [ "users" ] '' + if [ -e ${lingerDir} ] ; then + cd ${lingerDir} + ls ${lingerDir} | sort | comm -3 -1 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl disable-linger + ls ${lingerDir} | sort | comm -3 -2 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl enable-linger + fi + ''; + # Warn about user accounts with deprecated password hashing schemes system.activationScripts.hashes = { deps = [ "users" ]; @@ -700,7 +749,8 @@ in { environment.profiles = [ "$HOME/.nix-profile" - "\${XDG_STATE_HOME:-$HOME/.local/state}/nix/profile" + "\${XDG_STATE_HOME}/nix/profile" + "$HOME/.local/state/nix/profile" "/etc/profiles/per-user/$USER" ]; @@ -708,17 +758,20 @@ in { boot.initrd.systemd = lib.mkIf config.boot.initrd.systemd.enable { contents = { "/etc/passwd".text = '' - ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: { uid, group }: let + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: { uid, group, shell }: let g = config.boot.initrd.systemd.groups.${group}; - in "${n}:x:${toString uid}:${toString g.gid}::/var/empty:") config.boot.initrd.systemd.users)} + in "${n}:x:${toString uid}:${toString g.gid}::/var/empty:${shell}") config.boot.initrd.systemd.users)} ''; "/etc/group".text = '' ${lib.concatStringsSep "\n" (lib.mapAttrsToList (n: { gid }: "${n}:x:${toString gid}:") config.boot.initrd.systemd.groups)} ''; + "/etc/shells".text = lib.concatStringsSep "\n" (lib.unique (lib.mapAttrsToList (_: u: u.shell) config.boot.initrd.systemd.users)) + "\n"; }; + storePaths = [ "${pkgs.shadow}/bin/nologin" ]; + users = { - root = {}; + root = { shell = lib.mkDefault "/bin/bash"; }; nobody = {}; }; @@ -750,6 +803,18 @@ in { { assertion = !cfg.enforceIdUniqueness || (sdInitrdUidsAreUnique && sdInitrdGidsAreUnique); message = "systemd initrd UIDs and GIDs must be unique!"; } + { assertion = usersWithoutExistingGroup == {}; + message = + let + errUsers = lib.attrNames usersWithoutExistingGroup; + missingGroups = lib.unique (lib.mapAttrsToList (n: u: u.group) usersWithoutExistingGroup); + mkConfigHint = group: "users.groups.${group} = {};"; + in '' + The following users have a primary group that is undefined: ${lib.concatStringsSep " " errUsers} + Hint: Add this to your NixOS configuration: + ${lib.concatStringsSep "\n " (map mkConfigHint missingGroups)} + ''; + } { # If mutableUsers is false, to prevent users creating a # configuration that locks them out of the system, ensure that # there is at least one "privileged" account that has a @@ -810,13 +875,17 @@ in { ''; } ] ++ (map (shell: { - assertion = (user.shell == pkgs.${shell}) -> (config.programs.${shell}.enable == true); + assertion = !user.ignoreShellProgramCheck -> (user.shell == pkgs.${shell}) -> (config.programs.${shell}.enable == true); message = '' users.users.${user.name}.shell is set to ${shell}, but programs.${shell}.enable is not true. This will cause the ${shell} shell to lack the basic nix directories in its PATH and might make logging in as that user impossible. You can fix it with: programs.${shell}.enable = true; + + If you know what you're doing and you are fine with the behavior, + set users.users.${user.name}.ignoreShellProgramCheck = true; + instead. ''; }) [ "fish" |