From f60a1ed689c45a1220eac2fe23e1fb7a9ab33a1d Mon Sep 17 00:00:00 2001 From: Robert Helgesson Date: Mon, 15 May 2017 23:53:49 +0200 Subject: [PATCH] systemd: handle non-Linux systems better This commit causes an error to be printed if running under a non-Linux system when a systemd service, target, or timer is active. It will also prevent running systemd during activation if running under a non-Linux system. --- modules/systemd.nix | 189 +++++++++++++++++++++++++------------------- 1 file changed, 106 insertions(+), 83 deletions(-) diff --git a/modules/systemd.nix b/modules/systemd.nix index 1e6117a12..ef68b6d64 100644 --- a/modules/systemd.nix +++ b/modules/systemd.nix @@ -5,6 +5,10 @@ with import ./lib/dag.nix; let + cfg = config.systemd.user; + + enabled = cfg.services != {} || cfg.targets != {} || cfg.timers != {}; + toSystemdIni = (import lib/generators.nix).toINI { mkKeyValue = key: value: let @@ -60,98 +64,117 @@ in }; }; - config = { - home.file = - listToAttrs ( - (buildServices "service" config.systemd.user.services) - ++ - (buildServices "target" config.systemd.user.targets) - ++ - (buildServices "timer" config.systemd.user.timers) - ); + config = mkMerge [ + { + assertions = [ + { + assertion = enabled -> pkgs.stdenv.isLinux; + message = + let + names = concatStringsSep ", " ( + attrNames (cfg.services // cfg.targets // cfg.timers) + ); + in + "Must use Linux for modules that require systemd: " + names; + } + ]; + } - home.activation.reloadSystemD = dagEntryAfter ["linkGeneration"] '' - function systemdPostReload() { - local workDir - workDir="$(mktemp -d)" + # If we run under a Linux system we assume that systemd is + # available, in particular we assume that systemctl is in PATH. + (mkIf pkgs.stdenv.isLinux { + home.file = + listToAttrs ( + (buildServices "service" cfg.services) + ++ + (buildServices "target" cfg.targets) + ++ + (buildServices "timer" cfg.timers) + ); - if [[ -v oldGenPath ]] ; then - local oldUserServicePath="$oldGenPath/home-files/.config/systemd/user" - fi + home.activation.reloadSystemD = dagEntryAfter ["linkGeneration"] '' + function systemdPostReload() { + local workDir + workDir="$(mktemp -d)" - local newUserServicePath="$newGenPath/home-files/.config/systemd/user" - local oldServiceFiles="$workDir/old-files" - local newServiceFiles="$workDir/new-files" - local servicesDiffFile="$workDir/diff-files" - - if [[ ! (-v oldUserServicePath && -d "$oldUserServicePath") \ - && ! -d "$newUserServicePath" ]]; then - return - fi - - if [[ ! (-v oldUserServicePath && -d "$oldUserServicePath") ]]; then - touch "$oldServiceFiles" - else - find "$oldUserServicePath" \ - -maxdepth 1 -name '*.service' -exec basename '{}' ';' \ - | sort \ - > "$oldServiceFiles" - fi - - if [[ ! -d "$newUserServicePath" ]]; then - touch "$newServiceFiles" - else - find "$newUserServicePath" \ - -maxdepth 1 -name '*.service' -exec basename '{}' ';' \ - | sort \ - > "$newServiceFiles" - fi - - diff \ - --new-line-format='+%L' \ - --old-line-format='-%L' \ - --unchanged-line-format=' %L' \ - "$oldServiceFiles" "$newServiceFiles" \ - > $servicesDiffFile - - local -a maybeRestart=( $(grep '^ ' $servicesDiffFile | cut -c2-) ) - local -a toStop=( $(grep '^-' $servicesDiffFile | cut -c2-) ) - local -a toStart=( $(grep '^+' $servicesDiffFile | cut -c2-) ) - local -a toRestart=( ) - - for f in ''${maybeRestart[@]} ; do - if systemctl --quiet --user is-active "$f" \ - && ! cmp --quiet \ - "$oldUserServicePath/$f" \ - "$newUserServicePath/$f" ; then - toRestart+=("$f") + if [[ -v oldGenPath ]] ; then + local oldUserServicePath="$oldGenPath/home-files/.config/systemd/user" fi - done - rm -r $workDir + local newUserServicePath="$newGenPath/home-files/.config/systemd/user" + local oldServiceFiles="$workDir/old-files" + local newServiceFiles="$workDir/new-files" + local servicesDiffFile="$workDir/diff-files" - local sugg="" + if [[ ! (-v oldUserServicePath && -d "$oldUserServicePath") \ + && ! -d "$newUserServicePath" ]]; then + return + fi - if [[ -n "''${toRestart[@]}" ]] ; then - sugg="''${sugg}systemctl --user restart ''${toRestart[@]}\n" - fi + if [[ ! (-v oldUserServicePath && -d "$oldUserServicePath") ]]; then + touch "$oldServiceFiles" + else + find "$oldUserServicePath" \ + -maxdepth 1 -name '*.service' -exec basename '{}' ';' \ + | sort \ + > "$oldServiceFiles" + fi - if [[ -n "''${toStop[@]}" ]] ; then - sugg="''${sugg}systemctl --user stop ''${toStop[@]}\n" - fi + if [[ ! -d "$newUserServicePath" ]]; then + touch "$newServiceFiles" + else + find "$newUserServicePath" \ + -maxdepth 1 -name '*.service' -exec basename '{}' ';' \ + | sort \ + > "$newServiceFiles" + fi - if [[ -n "''${toStart[@]}" ]] ; then - sugg="''${sugg}systemctl --user start ''${toStart[@]}\n" - fi + diff \ + --new-line-format='+%L' \ + --old-line-format='-%L' \ + --unchanged-line-format=' %L' \ + "$oldServiceFiles" "$newServiceFiles" \ + > $servicesDiffFile - if [[ -n "$sugg" ]] ; then - echo "Suggested commands:" - echo -n -e "$sugg" - fi - } + local -a maybeRestart=( $(grep '^ ' $servicesDiffFile | cut -c2-) ) + local -a toStop=( $(grep '^-' $servicesDiffFile | cut -c2-) ) + local -a toStart=( $(grep '^+' $servicesDiffFile | cut -c2-) ) + local -a toRestart=( ) - $DRY_RUN_CMD systemctl --user daemon-reload - systemdPostReload - ''; - }; + for f in ''${maybeRestart[@]} ; do + if systemctl --quiet --user is-active "$f" \ + && ! cmp --quiet \ + "$oldUserServicePath/$f" \ + "$newUserServicePath/$f" ; then + toRestart+=("$f") + fi + done + + rm -r $workDir + + local sugg="" + + if [[ -n "''${toRestart[@]}" ]] ; then + sugg="''${sugg}systemctl --user restart ''${toRestart[@]}\n" + fi + + if [[ -n "''${toStop[@]}" ]] ; then + sugg="''${sugg}systemctl --user stop ''${toStop[@]}\n" + fi + + if [[ -n "''${toStart[@]}" ]] ; then + sugg="''${sugg}systemctl --user start ''${toStart[@]}\n" + fi + + if [[ -n "$sugg" ]] ; then + echo "Suggested commands:" + echo -n -e "$sugg" + fi + } + + $DRY_RUN_CMD systemctl --user daemon-reload + systemdPostReload + ''; + }) + ]; }