at 24.11-pre 7.2 kB view raw
1{ config, lib, pkgs, utils, ... }: 2with utils; 3with systemdUtils.unitOptions; 4with lib; 5 6let 7 cfg = config.systemd.user; 8 9 systemd = config.systemd.package; 10 11 inherit 12 (systemdUtils.lib) 13 makeUnit 14 generateUnits 15 targetToUnit 16 serviceToUnit 17 sliceToUnit 18 socketToUnit 19 timerToUnit 20 pathToUnit; 21 22 upstreamUserUnits = [ 23 "app.slice" 24 "background.slice" 25 "basic.target" 26 "bluetooth.target" 27 "default.target" 28 "exit.target" 29 "graphical-session-pre.target" 30 "graphical-session.target" 31 "paths.target" 32 "printer.target" 33 "session.slice" 34 "shutdown.target" 35 "smartcard.target" 36 "sockets.target" 37 "sound.target" 38 "systemd-exit.service" 39 "timers.target" 40 "xdg-desktop-autostart.target" 41 ] ++ config.systemd.additionalUpstreamUserUnits; 42 43 writeTmpfiles = { rules, user ? null }: 44 let 45 suffix = optionalString (user != null) "-${user}"; 46 in 47 pkgs.writeTextFile { 48 name = "nixos-user-tmpfiles.d${suffix}"; 49 destination = "/etc/xdg/user-tmpfiles.d/00-nixos${suffix}.conf"; 50 text = '' 51 # This file is created automatically and should not be modified. 52 # Please change the options systemd.user.tmpfiles instead. 53 ${concatStringsSep "\n" rules} 54 ''; 55 }; 56in { 57 options = { 58 systemd.user.extraConfig = mkOption { 59 default = ""; 60 type = types.lines; 61 example = "DefaultCPUAccounting=yes"; 62 description = '' 63 Extra config options for systemd user instances. See {manpage}`systemd-user.conf(5)` for 64 available options. 65 ''; 66 }; 67 68 systemd.user.units = mkOption { 69 description = "Definition of systemd per-user units."; 70 default = {}; 71 type = systemdUtils.types.units; 72 }; 73 74 systemd.user.paths = mkOption { 75 default = {}; 76 type = systemdUtils.types.paths; 77 description = "Definition of systemd per-user path units."; 78 }; 79 80 systemd.user.services = mkOption { 81 default = {}; 82 type = systemdUtils.types.services; 83 description = "Definition of systemd per-user service units."; 84 }; 85 86 systemd.user.slices = mkOption { 87 default = {}; 88 type = systemdUtils.types.slices; 89 description = "Definition of systemd per-user slice units."; 90 }; 91 92 systemd.user.sockets = mkOption { 93 default = {}; 94 type = systemdUtils.types.sockets; 95 description = "Definition of systemd per-user socket units."; 96 }; 97 98 systemd.user.targets = mkOption { 99 default = {}; 100 type = systemdUtils.types.targets; 101 description = "Definition of systemd per-user target units."; 102 }; 103 104 systemd.user.timers = mkOption { 105 default = {}; 106 type = systemdUtils.types.timers; 107 description = "Definition of systemd per-user timer units."; 108 }; 109 110 systemd.user.tmpfiles = { 111 rules = mkOption { 112 type = types.listOf types.str; 113 default = []; 114 example = [ "D %C - - - 7d" ]; 115 description = '' 116 Global user rules for creation, deletion and cleaning of volatile and 117 temporary files automatically. See 118 {manpage}`tmpfiles.d(5)` 119 for the exact format. 120 ''; 121 }; 122 123 users = mkOption { 124 description = '' 125 Per-user rules for creation, deletion and cleaning of volatile and 126 temporary files automatically. 127 ''; 128 default = {}; 129 type = types.attrsOf (types.submodule { 130 options = { 131 rules = mkOption { 132 type = types.listOf types.str; 133 default = []; 134 example = [ "D %C - - - 7d" ]; 135 description = '' 136 Per-user rules for creation, deletion and cleaning of volatile and 137 temporary files automatically. See 138 {manpage}`tmpfiles.d(5)` 139 for the exact format. 140 ''; 141 }; 142 }; 143 }); 144 }; 145 }; 146 147 systemd.additionalUpstreamUserUnits = mkOption { 148 default = []; 149 type = types.listOf types.str; 150 example = []; 151 description = '' 152 Additional units shipped with systemd that should be enabled for per-user systemd instances. 153 ''; 154 internal = true; 155 }; 156 }; 157 158 config = { 159 systemd.additionalUpstreamSystemUnits = [ 160 "user.slice" 161 ]; 162 163 environment.etc = { 164 "systemd/user".source = generateUnits { 165 type = "user"; 166 inherit (cfg) units; 167 upstreamUnits = upstreamUserUnits; 168 upstreamWants = []; 169 }; 170 171 "systemd/user.conf".text = '' 172 [Manager] 173 ${cfg.extraConfig} 174 ''; 175 }; 176 177 systemd.user.units = 178 mapAttrs' (n: v: nameValuePair "${n}.path" (pathToUnit v)) cfg.paths 179 // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit v)) cfg.services 180 // mapAttrs' (n: v: nameValuePair "${n}.slice" (sliceToUnit v)) cfg.slices 181 // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit v)) cfg.sockets 182 // mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit v)) cfg.targets 183 // mapAttrs' (n: v: nameValuePair "${n}.timer" (timerToUnit v)) cfg.timers; 184 185 # Generate timer units for all services that have a ‘startAt’ value. 186 systemd.user.timers = 187 mapAttrs (name: service: { 188 wantedBy = ["timers.target"]; 189 timerConfig.OnCalendar = service.startAt; 190 }) 191 (filterAttrs (name: service: service.startAt != []) cfg.services); 192 193 # Provide the systemd-user PAM service, required to run systemd 194 # user instances. 195 security.pam.services.systemd-user = 196 { # Ensure that pam_systemd gets included. This is special-cased 197 # in systemd to provide XDG_RUNTIME_DIR. 198 startSession = true; 199 # Disable pam_mount in systemd-user to prevent it from being called 200 # multiple times during login, because it will prevent pam_mount from 201 # unmounting the previously mounted volumes. 202 pamMount = false; 203 }; 204 205 # Some overrides to upstream units. 206 systemd.services."user@".restartIfChanged = false; 207 systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions. 208 209 # enable systemd user tmpfiles 210 systemd.user.services.systemd-tmpfiles-setup.wantedBy = 211 optional 212 (cfg.tmpfiles.rules != [] || any (cfg': cfg'.rules != []) (attrValues cfg.tmpfiles.users)) 213 "basic.target"; 214 215 # /run/current-system/sw/etc/xdg is in systemd's $XDG_CONFIG_DIRS so we can 216 # write the tmpfiles.d rules for everyone there 217 environment.systemPackages = 218 optional 219 (cfg.tmpfiles.rules != []) 220 (writeTmpfiles { inherit (cfg.tmpfiles) rules; }); 221 222 # /etc/profiles/per-user/$USER/etc/xdg is in systemd's $XDG_CONFIG_DIRS so 223 # we can write a single user's tmpfiles.d rules there 224 users.users = 225 mapAttrs 226 (user: cfg': { 227 packages = optional (cfg'.rules != []) (writeTmpfiles { 228 inherit (cfg') rules; 229 inherit user; 230 }); 231 }) 232 cfg.tmpfiles.users; 233 234 system.userActivationScripts.tmpfiles = '' 235 ${config.systemd.package}/bin/systemd-tmpfiles --user --create --remove 236 ''; 237 }; 238}