summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorEmily <vcs@emily.moe>2023-07-16 15:16:07 +0100
committerGitHub <noreply@github.com>2023-07-16 15:16:07 +0100
commit61662a63bfe1726588c1da6b412df86d8ca94d63 (patch)
treef93a1b7ef2d968d2d8b3c8ad3746c7a2caa2bcb4 /modules
parentc806a73609e77f0c446fdad5d3ea6ca3b7ae6e5f (diff)
parent4eb1c549a9d43c4a85373dbf63986869aab9589b (diff)
Merge pull request #731 from emilazy/etc-checks
etc: check for existing files during checks stage
Diffstat (limited to 'modules')
-rw-r--r--modules/services/activate-system/default.nix3
-rw-r--r--modules/system/activation-scripts.nix4
-rw-r--r--modules/system/etc.nix132
3 files changed, 89 insertions, 50 deletions
diff --git a/modules/services/activate-system/default.nix b/modules/services/activate-system/default.nix
index 90b7d3c..19034a1 100644
--- a/modules/services/activate-system/default.nix
+++ b/modules/services/activate-system/default.nix
@@ -3,8 +3,6 @@
with lib;
let
- inherit (pkgs) stdenv;
-
cfg = config.services.activate-system;
in
@@ -36,6 +34,7 @@ in
# Prevent the current configuration from being garbage-collected.
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
+ ${config.system.activationScripts.etcChecks.text}
${config.system.activationScripts.etc.text}
${config.system.activationScripts.keyboard.text}
'';
diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix
index b92a692..67d69be 100644
--- a/modules/system/activation-scripts.nix
+++ b/modules/system/activation-scripts.nix
@@ -52,6 +52,9 @@ in
${cfg.activationScripts.preActivation.text}
+ # We run `etcChecks` again just in case someone runs `activate`
+ # directly without `activate-user`.
+ ${cfg.activationScripts.etcChecks.text}
${cfg.activationScripts.extraActivation.text}
${cfg.activationScripts.groups.text}
${cfg.activationScripts.users.text}
@@ -99,6 +102,7 @@ in
${cfg.activationScripts.createRun.text}
${cfg.activationScripts.checks.text}
+ ${cfg.activationScripts.etcChecks.text}
${cfg.activationScripts.extraUserActivation.text}
${cfg.activationScripts.userDefaults.text}
${cfg.activationScripts.userLaunchd.text}
diff --git a/modules/system/etc.nix b/modules/system/etc.nix
index 2dfafcc..9608033 100644
--- a/modules/system/etc.nix
+++ b/modules/system/etc.nix
@@ -9,11 +9,8 @@ let
mkTextDerivation = name: text: pkgs.writeText "etc-${name}" text;
};
- hasDir = path: length (splitString "/" path) > 1;
-
etc = filter (f: f.enable) (attrValues config.environment.etc);
etcCopy = filter (f: f.copy) (attrValues config.environment.etc);
- etcDirs = filter (attr: hasDir attr.target) (attrValues config.environment.etc);
in
@@ -42,64 +39,103 @@ in
${concatMapStringsSep "\n" (attr: "touch '${attr.target}'.copy") etcCopy}
'';
+ system.activationScripts.etcChecks.text = ''
+ declare -A etcSha256Hashes=(
+ ${concatMapStringsSep "\n "
+ (attr:
+ "[${escapeShellArg attr.target}]=" +
+ escapeShellArg (concatStringsSep " " attr.knownSha256Hashes))
+ etc}
+ )
+
+ declare -a etcProblems
+
+ while IFS= read -r -d "" configFile; do
+ subPath=''${configFile#"$systemConfig"/etc/}
+ etcStaticFile=/etc/static/$subPath
+ etcFile=/etc/$subPath
+
+ if [[ -e $configFile.copy ]]; then
+ continue
+ fi
+
+ # We need to check files that exist and aren't already links to
+ # $etcStaticFile for known hashes.
+ if [[
+ -e $etcFile
+ && $(readlink "$etcFile") != "$etcStaticFile"
+ ]]; then
+ # Only check hashes of paths that resolve to regular files;
+ # everything else (e.g. directories) we complain about
+ # unconditionally.
+ if [[ -f $(readlink -f "$etcFile") ]]; then
+ etcFileSha256Output=$(shasum -a 256 "$etcFile")
+ etcFileSha256Hash=''${etcFileSha256Output%% *}
+ for knownSha256Hash in ''${etcSha256Hashes[$subPath]}; do
+ if [[ $etcFileSha256Hash == "$knownSha256Hash" ]]; then
+ # Hash matches, OK to overwrite; go to the next file.
+ continue 2
+ fi
+ done
+ fi
+ etcProblems+=("$etcFile")
+ fi
+ done < <(find -H "$systemConfig/etc" -type l -print0)
+
+ if (( ''${#etcProblems[@]} )); then
+ printf >&2 '\x1B[1;31merror: Unexpected files in /etc, aborting '
+ printf >&2 'activation\x1B[0m\n'
+ printf >&2 'The following files have unrecognized content and would be '
+ printf >&2 'overwritten:\n\n'
+ printf >&2 ' %s\n' "''${etcProblems[@]}"
+ printf >&2 '\nPlease check there is nothing critical in these files, '
+ printf >&2 'rename them by adding .before-nix-darwin to the end, and '
+ printf >&2 'then try again.\n'
+ exit 2
+ fi
+ '';
+
system.activationScripts.etc.text = ''
# Set up the statically computed bits of /etc.
- echo "setting up /etc..." >&2
+ printf >&2 'setting up /etc...\n'
- declare -A etcSha256Hashes
- ${concatMapStringsSep "\n" (attr: "etcSha256Hashes['/etc/${attr.target}']='${concatStringsSep " " attr.knownSha256Hashes}'") etc}
+ ln -sfn "$(readlink -f "$systemConfig/etc")" /etc/static
- ln -sfn "$(readlink -f $systemConfig/etc)" /etc/static
+ while IFS= read -r -d "" etcStaticFile; do
+ etcFile=/etc/''${etcStaticFile#/etc/static/}
+ etcDir=''${etcFile%/*}
- errorOccurred=false
- for f in $(find /etc/static/* -type l); do
- l=/etc/''${f#/etc/static/}
- d=''${l%/*}
- if [ ! -e "$d" ]; then
- mkdir -p "$d"
+ if [[ ! -d $etcDir ]]; then
+ mkdir -p "$etcDir"
fi
- if [ -e "$f".copy ]; then
- cp "$f" "$l"
+
+ if [[ -e $etcStaticFile.copy ]]; then
+ cp "$etcStaticFile" "$etcFile"
continue
fi
- if [ -e "$l" ]; then
- if [ "$(readlink "$l")" != "$f" ]; then
- if ! grep -q /etc/static "$l"; then
- o=''$(shasum -a256 "$l")
- o=''${o%% *}
- for h in ''${etcSha256Hashes["$l"]}; do
- if [ "$o" = "$h" ]; then
- mv "$l" "$l.before-nix-darwin"
- ln -s "$f" "$l"
- break
- else
- h=
- fi
- done
-
- if [ -z "$h" ]; then
- echo "error: not linking environment.etc.\"''${l#/etc/}\" because $l already exists, skipping..." >&2
- echo "existing file has unknown content $o, move and activate again to apply" >&2
- errorOccurred=true
- fi
- fi
+
+ if [[ -e $etcFile ]]; then
+ if [[ $(readlink -- "$etcFile") == "$etcStaticFile" ]]; then
+ continue
+ else
+ mv "$etcFile" "$etcFile.before-nix-darwin"
fi
- else
- ln -s "$f" "$l"
fi
- done
- if [ "$errorOccurred" != "false" ]; then
- exit 1
- fi
+ ln -s "$etcStaticFile" "$etcFile"
+ done < <(find -H /etc/static -type l -print0)
+
+ while IFS= read -r -d "" etcFile; do
+ etcStaticFile=/etc/static/''${etcFile#/etc/}
- for l in $(find /etc/* -type l 2> /dev/null); do
- f="$(echo $l | sed 's,/etc/,/etc/static/,')"
- f=/etc/static/''${l#/etc/}
- if [ "$(readlink "$l")" = "$f" -a ! -e "$(readlink -f "$l")" ]; then
- rm "$l"
+ # Delete stale links into /etc/static.
+ if [[
+ $(readlink "$etcFile") == "$etcStaticFile"
+ && ! -e $etcStaticFile
+ ]]; then
+ rm "$etcFile"
fi
- done
+ done < <(find -H /etc -type l -print0)
'';
};