about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/system/boot/systemd/user.nix
blob: 3200a58d73c9cbe306f6a687833a696aa4e40b5f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
{ config, lib, pkgs, utils, ... }:
with utils;
with systemdUtils.unitOptions;
with lib;

let
  cfg = config.systemd.user;

  systemd = config.systemd.package;

  inherit
    (systemdUtils.lib)
    makeUnit
    generateUnits
    targetToUnit
    serviceToUnit
    sliceToUnit
    socketToUnit
    timerToUnit
    pathToUnit;

  upstreamUserUnits = [
    "app.slice"
    "background.slice"
    "basic.target"
    "bluetooth.target"
    "default.target"
    "exit.target"
    "graphical-session-pre.target"
    "graphical-session.target"
    "paths.target"
    "printer.target"
    "session.slice"
    "shutdown.target"
    "smartcard.target"
    "sockets.target"
    "sound.target"
    "systemd-exit.service"
    "timers.target"
    "xdg-desktop-autostart.target"
  ] ++ config.systemd.additionalUpstreamUserUnits;
in {
  options = {
    systemd.user.extraConfig = mkOption {
      default = "";
      type = types.lines;
      example = "DefaultCPUAccounting=yes";
      description = lib.mdDoc ''
        Extra config options for systemd user instances. See man systemd-user.conf for
        available options.
      '';
    };

    systemd.user.units = mkOption {
      description = lib.mdDoc "Definition of systemd per-user units.";
      default = {};
      type = systemdUtils.types.units;
    };

    systemd.user.paths = mkOption {
      default = {};
      type = systemdUtils.types.paths;
      description = lib.mdDoc "Definition of systemd per-user path units.";
    };

    systemd.user.services = mkOption {
      default = {};
      type = systemdUtils.types.services;
      description = lib.mdDoc "Definition of systemd per-user service units.";
    };

    systemd.user.slices = mkOption {
      default = {};
      type = systemdUtils.types.slices;
      description = lib.mdDoc "Definition of systemd per-user slice units.";
    };

    systemd.user.sockets = mkOption {
      default = {};
      type = systemdUtils.types.sockets;
      description = lib.mdDoc "Definition of systemd per-user socket units.";
    };

    systemd.user.targets = mkOption {
      default = {};
      type = systemdUtils.types.targets;
      description = lib.mdDoc "Definition of systemd per-user target units.";
    };

    systemd.user.timers = mkOption {
      default = {};
      type = systemdUtils.types.timers;
      description = lib.mdDoc "Definition of systemd per-user timer units.";
    };

    systemd.additionalUpstreamUserUnits = mkOption {
      default = [];
      type = types.listOf types.str;
      example = [];
      description = ''
        Additional units shipped with systemd that should be enabled for per-user systemd instances.
      '';
      internal = true;
    };
  };

  config = {
    systemd.additionalUpstreamSystemUnits = [
      "user.slice"
    ];

    environment.etc = {
      "systemd/user".source = generateUnits {
        type = "user";
        inherit (cfg) units;
        upstreamUnits = upstreamUserUnits;
        upstreamWants = [];
      };

      "systemd/user.conf".text = ''
        [Manager]
        ${cfg.extraConfig}
      '';
    };

    systemd.user.units =
         mapAttrs' (n: v: nameValuePair "${n}.path"    (pathToUnit    n v)) cfg.paths
      // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
      // mapAttrs' (n: v: nameValuePair "${n}.slice"   (sliceToUnit   n v)) cfg.slices
      // mapAttrs' (n: v: nameValuePair "${n}.socket"  (socketToUnit  n v)) cfg.sockets
      // mapAttrs' (n: v: nameValuePair "${n}.target"  (targetToUnit  n v)) cfg.targets
      // mapAttrs' (n: v: nameValuePair "${n}.timer"   (timerToUnit   n v)) cfg.timers;

    # Generate timer units for all services that have a ‘startAt’ value.
    systemd.user.timers =
      mapAttrs (name: service: {
        wantedBy = ["timers.target"];
        timerConfig.OnCalendar = service.startAt;
      })
      (filterAttrs (name: service: service.startAt != []) cfg.services);

    # Provide the systemd-user PAM service, required to run systemd
    # user instances.
    security.pam.services.systemd-user =
      { # Ensure that pam_systemd gets included. This is special-cased
        # in systemd to provide XDG_RUNTIME_DIR.
        startSession = true;
        # Disable pam_mount in systemd-user to prevent it from being called
        # multiple times during login, because it will prevent pam_mount from
        # unmounting the previously mounted volumes.
        pamMount = false;
      };

    # Some overrides to upstream units.
    systemd.services."user@".restartIfChanged = false;
    systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions.
  };
}