nixos/etc: Replace make-etc.sh with nix and bash
The main goal of this commit is to replace the rather fragile passing of multiple arrays which could break in cases like #130935. While I could have just added proper shell escaping to the variables being passed, I opted for the more painful approach of replacing the fragile and somewhat strange construct with the 5 bash lists. While there are currently no more problems present with the current approach (at least none that I know of), the new approach seems more solid and might get around problems that could arise in the future stemming from either the multiple-lists situation or from the absence of proper shell quoting all over the script.
This commit is contained in:
parent
6337261453
commit
eb7120dc79
|
@ -1045,7 +1045,7 @@ in
|
|||
done
|
||||
'' + concatMapStrings (name: optionalString (hasPrefix "tmpfiles.d/" name) ''
|
||||
rm -f $out/${removePrefix "tmpfiles.d/" name}
|
||||
'') config.system.build.etc.targets;
|
||||
'') config.system.build.etc.passthru.targets;
|
||||
}) + "/*";
|
||||
|
||||
"systemd/system-generators" = { source = hooks "generators" cfg.generators; };
|
||||
|
|
|
@ -8,21 +8,61 @@ let
|
|||
|
||||
etc' = filter (f: f.enable) (attrValues config.environment.etc);
|
||||
|
||||
etc = pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "etc";
|
||||
|
||||
builder = ./make-etc.sh;
|
||||
|
||||
etc = pkgs.runCommand "etc" {
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
|
||||
/* !!! Use toXML. */
|
||||
sources = map (x: x.source) etc';
|
||||
targets = map (x: x.target) etc';
|
||||
modes = map (x: x.mode) etc';
|
||||
users = map (x: x.user) etc';
|
||||
groups = map (x: x.group) etc';
|
||||
};
|
||||
# This is needed for the systemd module
|
||||
passthru.targets = map (x: x.target) etc';
|
||||
} /* sh */ ''
|
||||
set -euo pipefail
|
||||
|
||||
makeEtcEntry() {
|
||||
src="$1"
|
||||
target="$2"
|
||||
mode="$3"
|
||||
user="$4"
|
||||
group="$5"
|
||||
|
||||
if [[ "$src" = *'*'* ]]; then
|
||||
# If the source name contains '*', perform globbing.
|
||||
mkdir -p "$out/etc/$target"
|
||||
for fn in $src; do
|
||||
ln -s "$fn" "$out/etc/$target/"
|
||||
done
|
||||
else
|
||||
|
||||
mkdir -p "$out/etc/$(dirname "$target")"
|
||||
if ! [ -e "$out/etc/$target" ]; then
|
||||
ln -s "$src" "$out/etc/$target"
|
||||
else
|
||||
echo "duplicate entry $target -> $src"
|
||||
if [ "$(readlink "$out/etc/$target")" != "$src" ]; then
|
||||
echo "mismatched duplicate entry $(readlink "$out/etc/$target") <-> $src"
|
||||
ret=1
|
||||
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$mode" != symlink ]; then
|
||||
echo "$mode" > "$out/etc/$target.mode"
|
||||
echo "$user" > "$out/etc/$target.uid"
|
||||
echo "$group" > "$out/etc/$target.gid"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "$out/etc"
|
||||
${concatMapStringsSep "\n" (etcEntry: escapeShellArgs [
|
||||
"makeEtcEntry"
|
||||
etcEntry.source
|
||||
etcEntry.target
|
||||
etcEntry.mode
|
||||
etcEntry.user
|
||||
etcEntry.group
|
||||
]) etc'}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
source $stdenv/setup
|
||||
|
||||
mkdir -p $out/etc
|
||||
|
||||
set -f
|
||||
sources_=($sources)
|
||||
targets_=($targets)
|
||||
modes_=($modes)
|
||||
users_=($users)
|
||||
groups_=($groups)
|
||||
set +f
|
||||
|
||||
for ((i = 0; i < ${#targets_[@]}; i++)); do
|
||||
source="${sources_[$i]}"
|
||||
target="${targets_[$i]}"
|
||||
|
||||
if [[ "$source" =~ '*' ]]; then
|
||||
|
||||
# If the source name contains '*', perform globbing.
|
||||
mkdir -p $out/etc/$target
|
||||
for fn in $source; do
|
||||
ln -s "$fn" $out/etc/$target/
|
||||
done
|
||||
|
||||
else
|
||||
|
||||
mkdir -p $out/etc/$(dirname $target)
|
||||
if ! [ -e $out/etc/$target ]; then
|
||||
ln -s $source $out/etc/$target
|
||||
else
|
||||
echo "duplicate entry $target -> $source"
|
||||
if test "$(readlink $out/etc/$target)" != "$source"; then
|
||||
echo "mismatched duplicate entry $(readlink $out/etc/$target) <-> $source"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "${modes_[$i]}" != symlink; then
|
||||
echo "${modes_[$i]}" > $out/etc/$target.mode
|
||||
echo "${users_[$i]}" > $out/etc/$target.uid
|
||||
echo "${groups_[$i]}" > $out/etc/$target.gid
|
||||
fi
|
||||
|
||||
fi
|
||||
done
|
Loading…
Reference in a new issue