summaryrefslogtreecommitdiffstats
path: root/pkgs/build-support/setup-systemd-units.nix
blob: 0dcf320733e8b7b67091f7c8b33bb440c349989a (plain)
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
# | Build a script to install and start a set of systemd units on any
# systemd-based system.
#
# Creates a symlink at /etc/systemd-static/${namespace} for slightly
# improved atomicity.
{
  writeScriptBin,
  bash,
  coreutils,
  systemd,
  runCommand,
  lib,
}:
{
  units,
  # : { [String] :: Path | { path :: Path; wanted-by :: [String]; } }
  # ^ A set whose names are unit names and values are
  # either paths to the corresponding unit files or a set
  # containing the path and the list of units this unit
  # should be wanted-by (none by default).
  #
  # The names should include the unit suffix
  # (e.g. ".service")
  namespace,
  # : String
  # The namespace for the unit files, to allow for
  # multiple independent unit sets managed by
  # `setupSystemdUnits`.
}:
let
  static = runCommand "systemd-static" { } ''
    mkdir -p $out
    ${lib.concatStringsSep "\n" (
      lib.mapAttrsToList (nm: file: "ln -sv ${file.path or file} $out/${nm}") units
    )}
  '';
  add-unit-snippet = name: file: ''
    oldUnit=$(readlink -f "$unitDir/${name}" || echo "$unitDir/${name}")
    if [ -f "$oldUnit" -a "$oldUnit" != "${file.path or file}" ]; then
      unitsToStop+=("${name}")
    fi
    ln -sf "/etc/systemd-static/${namespace}/${name}" \
      "$unitDir/.${name}.tmp"
    mv -T "$unitDir/.${name}.tmp" "$unitDir/${name}"
    ${lib.concatStringsSep "\n" (
      map (unit: ''
        mkdir -p "$unitDir/${unit}.wants"
        ln -sf "../${name}" \
          "$unitDir/${unit}.wants/.${name}.tmp"
        mv -T "$unitDir/${unit}.wants/.${name}.tmp" \
          "$unitDir/${unit}.wants/${name}"
      '') file.wanted-by or [ ]
    )}
    unitsToStart+=("${name}")
  '';
in
writeScriptBin "setup-systemd-units" ''
  #!${bash}/bin/bash -e
  export PATH=${coreutils}/bin:${systemd}/bin

  unitDir=/etc/systemd/system
  if [ ! -w "$unitDir" ]; then
    unitDir=/nix/var/nix/profiles/default/lib/systemd/system
    mkdir -p "$unitDir"
  fi
  declare -a unitsToStop unitsToStart

  oldStatic=$(readlink -f /etc/systemd-static/${namespace} || true)
  if [ "$oldStatic" != "${static}" ]; then
    ${lib.concatStringsSep "\n" (lib.mapAttrsToList add-unit-snippet units)}
    if [ ''${#unitsToStop[@]} -ne 0 ]; then
      echo "Stopping unit(s) ''${unitsToStop[@]}" >&2
      systemctl stop "''${unitsToStop[@]}"
    fi
    mkdir -p /etc/systemd-static
    ln -sfT ${static} /etc/systemd-static/.${namespace}.tmp
    mv -T /etc/systemd-static/.${namespace}.tmp /etc/systemd-static/${namespace}
    systemctl daemon-reload
    echo "Starting unit(s) ''${unitsToStart[@]}" >&2
    systemctl start "''${unitsToStart[@]}"
  else
    echo "Units unchanged, doing nothing" >&2
  fi
''