mirror of
https://github.com/NiklasGollenstede/nixos-installer.git
synced 2024-11-21 23:43:14 +01:00
various small fixes, fixes + fileSystems.*.postUnmountCommands
This commit is contained in:
parent
4b31e64901
commit
2bce37a185
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
@ -28,7 +28,8 @@ function gen-key-usb-part {( set -eu # 1: usage
|
|||||||
|
|
||||||
## Outputs a key by simply printing an different keystore entry (that must have been generated before).
|
## Outputs a key by simply printing an different keystore entry (that must have been generated before).
|
||||||
function gen-key-copy {( set -eu # 1: _, 2: source
|
function gen-key-copy {( set -eu # 1: _, 2: source
|
||||||
keystore=/run/keystore-@{config.networking.hostName!hashString.sha256:0:8} ; source=$2
|
source=$2
|
||||||
|
keystore=/run/keystore-@{config.networking.hostName!hashString.sha256:0:8}
|
||||||
cat "$keystore"/"$source".key
|
cat "$keystore"/"$source".key
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -41,16 +42,17 @@ function gen-key-constant {( set -eu # 1: _, 2: value
|
|||||||
## Obtains a key by prompting for a password.
|
## Obtains a key by prompting for a password.
|
||||||
function gen-key-password {( set -eu # 1: usage
|
function gen-key-password {( set -eu # 1: usage
|
||||||
usage=$1
|
usage=$1
|
||||||
( prompt-new-password "as key for @{config.networking.hostName}:$usage" || \exit 1 )
|
( prompt-new-password "as key »(@{config.networking.hostName}:)$usage«" || \exit 1 )
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Generates a key by prompting for (or reusing) a »$user«'s password, combining it with »$keystore/home/$user.key«.
|
## Generates a key by prompting for (or reusing) a »$user«'s password, combining it with »$keystore/home/$user.key«.
|
||||||
function gen-key-home-composite {( set -eu # 1: usage, 2: user
|
function gen-key-home-composite {( set -eu # 1: usage, 2: user
|
||||||
keystore=/run/keystore-@{config.networking.hostName!hashString.sha256:0:8} ; usage=$1 ; user=$2
|
usage=$1 ; user=$2
|
||||||
|
keystore=/run/keystore-@{config.networking.hostName!hashString.sha256:0:8}
|
||||||
if [[ ${!userPasswords[@]} && ${userPasswords[$user]:-} ]] ; then
|
if [[ ${!userPasswords[@]} && ${userPasswords[$user]:-} ]] ; then
|
||||||
password=${userPasswords[$user]}
|
password=${userPasswords[$user]}
|
||||||
else
|
else
|
||||||
password=$(prompt-new-password "that will be used as component of the key for »@{config.networking.hostName}:$usage«")
|
password=$(prompt-new-password "for the user account »$user« (as component for key »(@{config.networking.hostName}:)$usage«)")
|
||||||
if [[ ! $password ]] ; then \exit 1 ; fi
|
if [[ ! $password ]] ; then \exit 1 ; fi
|
||||||
fi
|
fi
|
||||||
{ cat "$keystore"/home/"$user".key && cat <<<"$password" ; } | sha256sum | head -c 64
|
{ cat "$keystore"/home/"$user".key && cat <<<"$password" ; } | sha256sum | head -c 64
|
||||||
@ -60,49 +62,49 @@ function gen-key-home-composite {( set -eu # 1: usage, 2: user
|
|||||||
function gen-key-home-yubikey {( set -eu # 1: usage, 2: serialAndSlotAndUser(as »serial:slot:user«)
|
function gen-key-home-yubikey {( set -eu # 1: usage, 2: serialAndSlotAndUser(as »serial:slot:user«)
|
||||||
usage=$1 ; args=$2
|
usage=$1 ; args=$2
|
||||||
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
||||||
user=${args/$serial:$slot:/}
|
user=${args#$serial:$slot:}
|
||||||
if [[ ${!userPasswords[@]} && ${userPasswords[$user]:-} ]] ; then
|
if [[ ${!userPasswords[@]} && ${userPasswords[$user]:-} ]] ; then
|
||||||
password=${userPasswords[$user]}
|
password=${userPasswords[$user]}
|
||||||
else
|
else
|
||||||
password=$(prompt-new-password "as YubiKey challenge for »@{config.networking.hostName}:$usage«")
|
password=$(prompt-new-password "for the user account »$user« (as YubiKey challenge for key »:$usage«)")
|
||||||
if [[ ! $password ]] ; then \exit 1 ; fi
|
if [[ ! $password ]] ; then \exit 1 ; fi
|
||||||
fi
|
fi
|
||||||
gen-key-yubikey-challenge "$usage" "$serial:$slot:home-$user=$password" true "»${user}«'s password (for key »${usage}«)"
|
gen-key-yubikey-challenge "$usage" "$serial:$slot:home-$user=$password" true "»${user}«'s password (to create key »:${usage}«)"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Generates a reproducible secret by prompting for a pin/password and then challenging slot »$slot« of YubiKey »$serial«.
|
## Generates a reproducible secret by prompting for a pin/password and then challenging slot »$slot« of YubiKey »$serial«.
|
||||||
function gen-key-yubikey-pin {( set -eu # 1: usage, 2: serialAndSlot(as »serial:slot«)
|
function gen-key-yubikey-pin {( set -eu # 1: usage, 2: serialAndSlot(as »serial:slot«)
|
||||||
usage=$1 ; serialAndSlot=$2
|
usage=$1 ; serialAndSlot=$2
|
||||||
pin=$( prompt-new-password "/ pin as challenge to YubiKey »$serialAndSlot« as key for »@{config.networking.hostName}:$usage«" )
|
pin=$( prompt-new-password "/ pin as challenge to YubiKey »$serialAndSlot« for key »:$usage«" )
|
||||||
if [[ ! $pin ]] ; then \exit 1 ; fi
|
if [[ ! $pin ]] ; then \exit 1 ; fi
|
||||||
gen-key-yubikey-challenge "$usage" "$serialAndSlot:$pin" true "password / pin as key for »@{config.networking.hostName}:$usage«"
|
gen-key-yubikey-challenge "$usage" "$serialAndSlot:$pin" true "password / pin to create key »:$usage«"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Generates a reproducible secret for a certain »$use«case and optionally »$salt« on a »$host« by challenging slot »$slot« of YubiKey »$serial«.
|
## Generates a reproducible secret for a certain »$use«case and optionally »$salt« specific to the current host(name) by challenging slot »$slot« of YubiKey »$serial«.
|
||||||
function gen-key-yubikey {( set -eu # 1: usage, 2: serialAndSlotAndSalt(as »serial:slot:salt«)
|
function gen-key-yubikey {( set -eu # 1: usage, 2: serialAndSlotAndSalt(as »serial:slot:salt«)
|
||||||
usage=$1 ; args=$2
|
usage=$1 ; args=$2
|
||||||
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
||||||
salt=${args/$serial:$slot:/}
|
salt=${args/$serial:$slot:/}
|
||||||
usagE="$usage" ; if [[ "$usage" =~ ^(luks/.*/[0-8])$ ]] ; then usagE="${usage:0:(-2)}" ; fi # produce the same secret, regardless of the target luks slot
|
usagE="$usage" ; if [[ "$usage" =~ ^(luks/.*/[0-8])$ ]] ; then usagE="${usage:0:(-2)}" ; fi # produce the same secret, regardless of the target luks slot
|
||||||
challenge="@{config.networking.hostName}:$usagE${salt:+:$salt}"
|
challenge="@{config.networking.hostName}:$usagE${salt:+:$salt}"
|
||||||
gen-key-yubikey-challenge "$usage" "$serial:$slot:$challenge"
|
gen-key-yubikey-challenge "$usage" "$serial:$slot:$challenge" '' "challenge »"$challenge":1/2« to create key »@{config.networking.hostName}:$usage«"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Generates a reproducible secret by challenging slot »$slot« of YubiKey »$serial« with the fixed »$challenge«.
|
## Generates a reproducible secret by challenging slot »$slot« of YubiKey »$serial« with the fixed »$challenge«.
|
||||||
function gen-key-yubikey-challenge {( set -eu # 1: _, 2: serialAndSlotAndChallenge(as »$serial:$slot:$challenge«), 3?: onlyOnce, 4?: message
|
function gen-key-yubikey-challenge {( set -eu # 1: _, 2: serialAndSlotAndChallenge(as »$serial:$slot:$challenge«), 3?: onlyOnce, 4?: message
|
||||||
args=$2 ; message=${4:-}
|
args=$2 ; onlyOnce=$3 ; message=$4
|
||||||
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
serial=$( <<<"$args" cut -d: -f1 ) ; slot=$( <<<"$args" cut -d: -f2 )
|
||||||
challenge=${args/$serial:$slot:/}
|
challenge=${args/$serial:$slot:/}
|
||||||
|
|
||||||
if [[ "$serial" != "$( @{native.yubikey-personalization}/bin/ykinfo -sq 2>/dev/null )" ]] ; then printf 'Please insert / change to YubiKey with serial %s!\n' "$serial" 1>&2 ; fi
|
if [[ "$serial" != "$( @{native.yubikey-personalization}/bin/ykinfo -sq 2>/dev/null )" ]] ; then printf 'Please insert / change to YubiKey with serial %s!\n' "$serial" 1>&2 ; fi
|
||||||
if [[ ! "${3:-}" ]] ; then
|
if [[ ! $onlyOnce ]] ; then
|
||||||
read -p 'Challenging YubiKey '"$serial"' slot '"$slot"' twice with '"${message:-challenge »"$challenge":1/2«}"'. Enter to continue, or Ctrl+C to abort:'
|
read -p 'Challenging YubiKey '"$serial"' slot '"$slot"' twice with '"$message"'. Enter to continue, or Ctrl+C to abort:'
|
||||||
else
|
else
|
||||||
read -p 'Challenging YubiKey '"$serial"' slot '"$slot"' once with '"${message:-challenge »"$challenge"«}"'. Enter to continue, or Ctrl+C to abort:'
|
read -p 'Challenging YubiKey '"$serial"' slot '"$slot"' once with '"$message"'. Enter to continue, or Ctrl+C to abort:'
|
||||||
fi
|
fi
|
||||||
if [[ "$serial" != "$( @{native.yubikey-personalization}/bin/ykinfo -sq )" ]] ; then printf 'YubiKey with serial %s not present, aborting.\n' "$serial" 1>&2 ; \exit 1 ; fi
|
if [[ "$serial" != "$( @{native.yubikey-personalization}/bin/ykinfo -sq )" ]] ; then printf 'YubiKey with serial %s not present, aborting.\n' "$serial" 1>&2 ; \exit 1 ; fi
|
||||||
|
|
||||||
if [[ ! "${3:-}" ]] ; then
|
if [[ ! $onlyOnce ]] ; then
|
||||||
secret="$( @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":1 )""$( sleep .5 || : ; @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":2 || @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":2 )" # the second consecutive challenge tends to fail if it follows immediately
|
secret="$( @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":1 )""$( sleep .5 || : ; @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":2 || @{native.yubikey-personalization}/bin/ykchalresp -"$slot" "$challenge":2 )" # the second consecutive challenge tends to fail if it follows immediately
|
||||||
if [[ ${#secret} != 80 ]] ; then printf 'YubiKey challenge failed, aborting.\n' "$serial" 1>&2 ; \exit 1 ; fi
|
if [[ ${#secret} != 80 ]] ; then printf 'YubiKey challenge failed, aborting.\n' "$serial" 1>&2 ; \exit 1 ; fi
|
||||||
else
|
else
|
||||||
|
@ -9,7 +9,6 @@ declare-flag install-system skip-formatting "" "Skip partitioning, formatting, a
|
|||||||
function do-disk-setup { # 1: diskPaths
|
function do-disk-setup { # 1: diskPaths
|
||||||
|
|
||||||
ensure-disks "$1" || return
|
ensure-disks "$1" || return
|
||||||
prompt-for-user-passwords || return
|
|
||||||
|
|
||||||
export mnt=/tmp/nixos-install-@{config.networking.hostName} && mkdir -p "$mnt" && prepend_trap "rmdir $mnt" EXIT || return # »mnt=/run/user/0/...« would be more appropriate, but »nixos-install« does not like the »700« permissions on »/run/user/0«
|
export mnt=/tmp/nixos-install-@{config.networking.hostName} && mkdir -p "$mnt" && prepend_trap "rmdir $mnt" EXIT || return # »mnt=/run/user/0/...« would be more appropriate, but »nixos-install« does not like the »700« permissions on »/run/user/0«
|
||||||
|
|
||||||
@ -22,6 +21,7 @@ function do-disk-setup { # 1: diskPaths
|
|||||||
open-luks-layers || return
|
open-luks-layers || return
|
||||||
if [[ $(LC_ALL=C type -t import-zpools) == function ]] ; then import-zpools $mnt || return ; fi
|
if [[ $(LC_ALL=C type -t import-zpools) == function ]] ; then import-zpools $mnt || return ; fi
|
||||||
else
|
else
|
||||||
|
prompt-for-user-passwords || return
|
||||||
populate-keystore || return
|
populate-keystore || return
|
||||||
partition-disks || return
|
partition-disks || return
|
||||||
create-luks-layers || return
|
create-luks-layers || return
|
||||||
@ -34,9 +34,9 @@ function do-disk-setup { # 1: diskPaths
|
|||||||
run-hook-script 'Post Formatting' @{config.installer.commands.postFormat!writeText.postFormatCommands} || return
|
run-hook-script 'Post Formatting' @{config.installer.commands.postFormat!writeText.postFormatCommands} || return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fix-grub-install || return
|
#fix-grub-install || return
|
||||||
|
|
||||||
prepend_trap "unmount-system $mnt" EXIT && mount-system $mnt || return
|
prepend_trap "unmount-system $mnt" EXIT && mount-system $mnt '' "${args[skip-formatting]:-}" || return
|
||||||
run-hook-script 'Post Mounting' @{config.installer.commands.postMount!writeText.postMountCommands} || return
|
run-hook-script 'Post Mounting' @{config.installer.commands.postMount!writeText.postMountCommands} || return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ function format-partitions {
|
|||||||
for swapDev in "@{config.swapDevices!catAttrs.device[@]}" ; do
|
for swapDev in "@{config.swapDevices!catAttrs.device[@]}" ; do
|
||||||
if [[ $swapDev == /dev/disk/by-partlabel/* ]] ; then
|
if [[ $swapDev == /dev/disk/by-partlabel/* ]] ; then
|
||||||
if ! is-partition-on-disks "$swapDev" "${blockDevs[@]}" ; then echo "Partition alias $swapDev used for SWAP does not point at one of the target disks ${blockDevs[@]}" 1>&2 ; \return 1 ; fi
|
if ! is-partition-on-disks "$swapDev" "${blockDevs[@]}" ; then echo "Partition alias $swapDev used for SWAP does not point at one of the target disks ${blockDevs[@]}" 1>&2 ; \return 1 ; fi
|
||||||
@{native.util-linux}/bin/wipefs --all "${fs[device]}" >$beLoud 2>$beSilent || return # else mkswap might refuse to replace any previous filesystems
|
@{native.util-linux}/bin/wipefs --all "$swapDev" >$beLoud 2>$beSilent || return # else mkswap might refuse to replace any previous filesystems
|
||||||
elif [[ $swapDev == /dev/mapper/* ]] ; then
|
elif [[ $swapDev == /dev/mapper/* ]] ; then
|
||||||
if [[ ! @{config.boot.initrd.luks.devices!catAttrSets.device[${swapDev/'/dev/mapper/'/}]:-} ]] ; then echo "LUKS device $swapDev used for SWAP does not point at one of the device mappings @{!config.boot.initrd.luks.devices!catAttrSets.device[@]}" 1>&2 ; \return 1 ; fi
|
if [[ ! @{config.boot.initrd.luks.devices!catAttrSets.device[${swapDev/'/dev/mapper/'/}]:-} ]] ; then echo "LUKS device $swapDev used for SWAP does not point at one of the device mappings @{!config.boot.initrd.luks.devices!catAttrSets.device[@]}" 1>&2 ; \return 1 ; fi
|
||||||
else continue ; fi
|
else continue ; fi
|
||||||
@ -226,11 +226,11 @@ function fix-grub-install {
|
|||||||
}
|
}
|
||||||
|
|
||||||
## Mounts all file systems as it would happen during boot, but at path prefix »$mnt« (instead of »/«).
|
## Mounts all file systems as it would happen during boot, but at path prefix »$mnt« (instead of »/«).
|
||||||
function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowFail
|
function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowNoautoFail
|
||||||
# While not generally required for fstab, nixos uses the dependency-sorted »config.system.build.fileSystems« list (instead of plain »builtins.attrValues config.fileSystems«) to generate »/etc/fstab« (provided »config.fileSystems.*.depends« is set correctly, e.g. for overlay mounts).
|
# While not generally required for fstab, nixos uses the dependency-sorted »config.system.build.fileSystems« list (instead of plain »builtins.attrValues config.fileSystems«) to generate »/etc/fstab« (provided »config.fileSystems.*.depends« is set correctly, e.g. for overlay mounts).
|
||||||
# This function depends on the file at »fstabPath« to be sorted like that.
|
# This function depends on the file at »fstabPath« to be sorted like that.
|
||||||
|
|
||||||
mnt=$1 ; fstabPath=${2:-"@{config.system.build.toplevel}/etc/fstab"} ; allowFail=${3:-}
|
mnt=$1 ; fstabPath=${2:-"@{config.system.build.toplevel}/etc/fstab"} ; allowNoautoFail=${3:-}
|
||||||
PATH=@{native.e2fsprogs}/bin:@{native.f2fs-tools}/bin:@{native.xfsprogs}/bin:@{native.dosfstools}/bin:$PATH
|
PATH=@{native.e2fsprogs}/bin:@{native.f2fs-tools}/bin:@{native.xfsprogs}/bin:@{native.dosfstools}/bin:$PATH
|
||||||
|
|
||||||
# The following is roughly equivalent to: mount --all --fstab "$fstabPath" --target-prefix "$mnt" -o X-mount.mkdir # (but »--target-prefix« does not apply to bind/overlay sources)
|
# The following is roughly equivalent to: mount --all --fstab "$fstabPath" --target-prefix "$mnt" -o X-mount.mkdir # (but »--target-prefix« does not apply to bind/overlay sources)
|
||||||
@ -239,7 +239,13 @@ function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowFail
|
|||||||
options=,$options, ; options=${options//,ro,/,}
|
options=,$options, ; options=${options//,ro,/,}
|
||||||
|
|
||||||
if ! @{native.util-linux}/bin/mountpoint -q "$mnt"/"$target" ; then (
|
if ! @{native.util-linux}/bin/mountpoint -q "$mnt"/"$target" ; then (
|
||||||
mkdir-sticky "$mnt"/"$target" || exit
|
|
||||||
|
if [[ $options =~ ,x-bind-file, ]] ; then
|
||||||
|
mkdir-sticky "$(dirname "$mnt"/"$target")" && touch -a "$mnt"/"$target" || \exit
|
||||||
|
else
|
||||||
|
mkdir-sticky "$mnt"/"$target" || \exit
|
||||||
|
fi
|
||||||
|
|
||||||
[[ $type == tmpfs || $type == auto || $type == */* ]] || @{native.kmod}/bin/modprobe --quiet $type || true # (this does help sometimes)
|
[[ $type == tmpfs || $type == auto || $type == */* ]] || @{native.kmod}/bin/modprobe --quiet $type || true # (this does help sometimes)
|
||||||
|
|
||||||
if [[ $type == overlay ]] ; then
|
if [[ $type == overlay ]] ; then
|
||||||
@ -251,12 +257,18 @@ function mount-system {( # 1: mnt, 2?: fstabPath, 3?: allowFail
|
|||||||
# TODO: test the lowerdir stuff
|
# TODO: test the lowerdir stuff
|
||||||
elif [[ $options =~ ,r?bind, ]] ; then
|
elif [[ $options =~ ,r?bind, ]] ; then
|
||||||
if [[ $source == /nix/store/* ]] ; then options=,ro$options ; fi
|
if [[ $source == /nix/store/* ]] ; then options=,ro$options ; fi
|
||||||
source=$mnt/$source ; if [[ ! -e $source ]] ; then mkdir-sticky "$source" || exit ; fi
|
source=$mnt/$source ; if [[ ! -e $source ]] ; then
|
||||||
|
if [[ $options =~ ,x-bind-file, ]] ; then
|
||||||
|
mkdir-sticky "$(dirname "$source")" && touch -a "$source" || \exit
|
||||||
|
else
|
||||||
|
mkdir-sticky "$source" || \exit
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@{native.util-linux}/bin/mount -t $type -o "${options:1:(-1)}" "$source" "$mnt"/"$target" || exit
|
@{native.util-linux}/bin/mount -t $type -o "${options:1:(-1)}" "$source" "$mnt"/"$target" || \exit
|
||||||
|
|
||||||
) || [[ $options == *,nofail,* || $allowFail ]] || exit ; fi # (actually, nofail already makes mount fail silently)
|
) || [[ $options == *,nofail,* ]] || [[ $options == *,noauto,* && $allowNoautoFail ]] || exit ; fi # (actually, nofail already makes mount fail silently)
|
||||||
done 3< <( <$fstabPath grep -v '^#' )
|
done 3< <( <$fstabPath grep -v '^#' )
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ function prepare-installer { # 1: diskPaths
|
|||||||
if @{native.zfs}/bin/zfs get -o value -H name "$poolName" &>/dev/null ; then echo "ZFS pool »$poolName« is already imported. Export the pool before running the installer." 1>&2 ; \return 1 ; fi
|
if @{native.zfs}/bin/zfs get -o value -H name "$poolName" &>/dev/null ; then echo "ZFS pool »$poolName« is already imported. Export the pool before running the installer." 1>&2 ; \return 1 ; fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${SUDO_USER:-} && $( PATH=$hostPath which su 2>/dev/null ) ]] ; then # use Nix as the user who called this script, as Nix may not be set up for root
|
if [[ ${SUDO_USER:-} && ! $( PATH=$hostPath which nix 2>/dev/null ) && $( PATH=$hostPath which su 2>/dev/null ) ]] ; then # use Nix as the user who called this script, as Nix may not be set up for root
|
||||||
function nix {( set +x ; declare -a args=("$@") ; PATH=$hostPath su - "$SUDO_USER" -s "@{native.bashInteractive!getExe}" -c "$(declare -p args)"' ; nix "${args[@]}"' )}
|
function nix {( set +x ; declare -a args=("$@") ; PATH=$hostPath su - "$SUDO_USER" -s "@{native.bashInteractive!getExe}" -c "$(declare -p args)"' ; nix "${args[@]}"' )}
|
||||||
else # use Nix by absolute path, as it won't be on »$PATH«
|
else # use Nix by absolute path, as it won't be on »$PATH«
|
||||||
PATH=$PATH:@{native.nix}/bin
|
PATH=$PATH:@{native.nix}/bin
|
||||||
@ -73,6 +73,7 @@ function prepare-installer { # 1: diskPaths
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare-flag install-system vm-shared "dir-path" "When installing inside the VM, specifies a host path that is read-write mounted at »/tmp/shared« inside the VM."
|
declare-flag install-system vm-shared "dir-path" "When installing inside the VM, specifies a host path that is read-write mounted at »/tmp/shared« inside the VM."
|
||||||
|
declare-flag install-system vm-args "qemu-args" "When installing inside the VM, extra arguments to pass to qemu."
|
||||||
|
|
||||||
## Re-executes the current system's installation in a qemu VM.
|
## Re-executes the current system's installation in a qemu VM.
|
||||||
function reexec-in-qemu {
|
function reexec-in-qemu {
|
||||||
@ -110,7 +111,7 @@ function reexec-in-qemu {
|
|||||||
|
|
||||||
local runInVm ; runInVm=$( build-lazy $output )/bin/run-@{config.system.name}-vm-exec || return
|
local runInVm ; runInVm=$( build-lazy $output )/bin/run-@{config.system.name}-vm-exec || return
|
||||||
|
|
||||||
$runInVm ${args[vm-shared]:+--shared="${args[vm-shared]}"} ${args[debug]:+--initrd-console} ${args[trace]:+--initrd-console} ${args[quiet]:+--quiet} -- "$command" "${qemu[@]}" || return # --initrd-console
|
$runInVm ${args[vm-shared]:+--shared="${args[vm-shared]}"} ${args[debug]:+--initrd-console} ${args[trace]:+--initrd-console} ${args[quiet]:+--quiet} -- "$command" "${qemu[@]}" ${args[vm-args]:-} || return # --initrd-console
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ function install-system-to {( set -u # 1: mnt, 2?: topLevel
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Copy system closure to new nix store:
|
# Copy system closure to new nix store:
|
||||||
if [[ ${SUDO_USER:-} ]] ; then chown -R $SUDO_USER: $mnt/nix/store $mnt/nix/var || exit ; fi
|
if declare -f nix >&/dev/null ; then chown -R $SUDO_USER: $mnt/nix/store $mnt/nix/var || exit ; fi
|
||||||
cmd=( nix --extra-experimental-features nix-command --offline copy --no-check-sigs --to $mnt "$topLevel" )
|
cmd=( nix --extra-experimental-features nix-command --offline copy --no-check-sigs --to $mnt "$topLevel" )
|
||||||
if [[ ${args[quiet]:-} ]] ; then
|
if [[ ${args[quiet]:-} ]] ; then
|
||||||
"${cmd[@]}" --quiet >/dev/null 2> >( grep -Pe '^error:' || true ) || exit
|
"${cmd[@]}" --quiet >/dev/null 2> >( grep -Pe '^error:' || true ) || exit
|
||||||
@ -173,7 +174,7 @@ function install-system-to {( set -u # 1: mnt, 2?: topLevel
|
|||||||
fi
|
fi
|
||||||
rm -rf $mnt/nix/var/nix/gcroots || exit
|
rm -rf $mnt/nix/var/nix/gcroots || exit
|
||||||
# TODO: if the target has @{config.nix.settings.auto-optimise-store} and the host doesn't (there is no .links dir?), optimize now
|
# TODO: if the target has @{config.nix.settings.auto-optimise-store} and the host doesn't (there is no .links dir?), optimize now
|
||||||
if [[ ${SUDO_USER:-} ]] ; then chown -R root:root $mnt/nix $mnt/nix/var || exit ; chown :30000 $mnt/nix/store || exit ; fi
|
if declare -f nix >&/dev/null ; then chown -R root:root $mnt/nix $mnt/nix/var || exit ; chown :30000 $mnt/nix/store || exit ; fi
|
||||||
|
|
||||||
# Set this as the initial system generation (in case »nixos-install-cmd« won't):
|
# Set this as the initial system generation (in case »nixos-install-cmd« won't):
|
||||||
# (does about the same as »nix-env --profile /nix/var/nix/profiles/system --set $targetSystem«)
|
# (does about the same as »nix-env --profile /nix/var/nix/profiles/system --set $targetSystem«)
|
||||||
|
@ -6,7 +6,7 @@ function prompt-for-user-passwords { # (void)
|
|||||||
local user ; for user in "@{!config.users.users!catAttrSets.password[@]}" ; do # Also grab any plaintext passwords for testing setups.
|
local user ; for user in "@{!config.users.users!catAttrSets.password[@]}" ; do # Also grab any plaintext passwords for testing setups.
|
||||||
userPasswords[$user]=@{config.users.users!catAttrSets.password[$user]}
|
userPasswords[$user]=@{config.users.users!catAttrSets.password[$user]}
|
||||||
done
|
done
|
||||||
local user ; for user in "@{!config.users.users!catAttrSets.passwordFile[@]}" ; do
|
local user ; for user in "@{!config.users.users!catAttrSets.hashedPasswordFile[@]}" "@{!config.users.users!catAttrSets.passwordFile[@]}" ; do
|
||||||
for attempt in 2 3 x ; do
|
for attempt in 2 3 x ; do
|
||||||
if userPasswords[$user]=$(prompt-new-password "for the user account »$user«") ; then break ; fi
|
if userPasswords[$user]=$(prompt-new-password "for the user account »$user«") ; then break ; fi
|
||||||
if [[ $attempt == x ]] ; then \return 1 ; fi ; echo "Retrying ($attempt/3):"
|
if [[ $attempt == x ]] ; then \return 1 ; fi ; echo "Retrying ($attempt/3):"
|
||||||
|
@ -212,6 +212,7 @@ function mount-keystore-luks-primary {
|
|||||||
local method=@{config.setup.keystore.keys[$usage]%%=*}
|
local method=@{config.setup.keystore.keys[$usage]%%=*}
|
||||||
local options=@{config.setup.keystore.keys[$usage]:$(( ${#method} + 1 ))}
|
local options=@{config.setup.keystore.keys[$usage]:$(( ${#method} + 1 ))}
|
||||||
|
|
||||||
|
echo 'Opening keystore with primary key (this may cause prompts, but no new keys are written):'
|
||||||
local attempt ; for attempt in 2 3 x ; do
|
local attempt ; for attempt in 2 3 x ; do
|
||||||
if mount-keystore-luks --key-file=<( gen-key-"$method" "$usage" "$options" ) ; then break ; fi
|
if mount-keystore-luks --key-file=<( gen-key-"$method" "$usage" "$options" ) ; then break ; fi
|
||||||
if [[ $attempt == x ]] ; then \return 1 ; fi ; echo "Retrying ($attempt/3):"
|
if [[ $attempt == x ]] ; then \return 1 ; fi ; echo "Retrying ($attempt/3):"
|
||||||
|
@ -89,7 +89,7 @@ function build-lazy { # 1: drvPath, 2?: output
|
|||||||
}
|
}
|
||||||
|
|
||||||
## Tests whether (returns 0/success if) the first version argument is greater/less than (or equal) the second version argument.
|
## Tests whether (returns 0/success if) the first version argument is greater/less than (or equal) the second version argument.
|
||||||
function version-gr-eq { printf '%s\n%s' "$1" "$2" | sort -C -V -r ; }
|
function version-gr-eq { printf '%s\n%s' "$1" "$2" | LC_ALL=C sort -C -V -r ; }
|
||||||
function version-lt-eq { printf '%s\n%s' "$1" "$2" | sort -C -V ; }
|
function version-lt-eq { printf '%s\n%s' "$1" "$2" | LC_ALL=C sort -C -V ; }
|
||||||
function version-gt { ! version-gt-eq "$2" "$1" ; }
|
function version-gt { ! version-gt-eq "$2" "$1" ; }
|
||||||
function version-lt { ! version-lt-eq "$2" "$1" ; }
|
function version-lt { ! version-lt-eq "$2" "$1" ; }
|
||||||
|
@ -25,6 +25,8 @@ Creates a single of the system's ZFS pools, and its datasets. Can be called manu
|
|||||||
EOD
|
EOD
|
||||||
declare-flag install-system,create-zpool zpool-force "" "When creating ZFS storage pools, pass the »-f« (force) option. This may be required when installing to disks that are currently part of a pool, or ZFS refuses do reuse them."
|
declare-flag install-system,create-zpool zpool-force "" "When creating ZFS storage pools, pass the »-f« (force) option. This may be required when installing to disks that are currently part of a pool, or ZFS refuses do reuse them."
|
||||||
function create-zpool {
|
function create-zpool {
|
||||||
|
local beLoud=/dev/null ; if [[ ${args[debug]:-} ]] ; then beLoud=/dev/stdout ; fi
|
||||||
|
local beSilent=/dev/stderr ; if [[ ${args[quiet]:-} ]] ; then beSilent=/dev/null ; fi
|
||||||
local mnt=$1 ; local poolName=$2
|
local mnt=$1 ; local poolName=$2
|
||||||
eval 'local -A pool='"@{config.setup.zfs.pools[$poolName]}"
|
eval 'local -A pool='"@{config.setup.zfs.pools[$poolName]}"
|
||||||
eval 'local -a vdevs='"${pool[vdevArgs]}"
|
eval 'local -a vdevs='"${pool[vdevArgs]}"
|
||||||
@ -45,6 +47,7 @@ function create-zpool {
|
|||||||
else
|
else
|
||||||
part=/dev/disk/by-partlabel/$part ; vdevs[$index]=$part
|
part=/dev/disk/by-partlabel/$part ; vdevs[$index]=$part
|
||||||
if ! is-partition-on-disks "$part" "${blockDevs[@]}" ; then echo "Partition alias $part used by zpool ${pool[name]} does not point at one of the target disks ${blockDevs[@]}" 1>&2 ; \return 1 ; fi
|
if ! is-partition-on-disks "$part" "${blockDevs[@]}" ; then echo "Partition alias $part used by zpool ${pool[name]} does not point at one of the target disks ${blockDevs[@]}" 1>&2 ; \return 1 ; fi
|
||||||
|
@{native.util-linux}/bin/wipefs --all "$part" >$beLoud 2>$beSilent || return # else mkfs might refuse to replace any previous filesystems
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@{native.kmod}/bin/modprobe zfs || true
|
@{native.kmod}/bin/modprobe zfs || true
|
||||||
@ -147,6 +150,7 @@ function ensure-datasets {
|
|||||||
( PATH=@{native.zfs}/bin ; ${_set_x:-:} ; zfs allow -$who "${allows[$who]}" "${dataset[name]}" >&2 ) || return
|
( PATH=@{native.zfs}/bin ; ${_set_x:-:} ; zfs allow -$who "${allows[$who]}" "${dataset[name]}" >&2 ) || return
|
||||||
done
|
done
|
||||||
done 3< <( printf '%s\0' "@{!config.setup.zfs.datasets[@]}" | LC_ALL=C sort -z )
|
done 3< <( printf '%s\0' "@{!config.setup.zfs.datasets[@]}" | LC_ALL=C sort -z )
|
||||||
|
# zfs list -o name,referenced,encryption,encryptionroot,keylocation,keystatus,mounted,mountpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
## Given the name (»datasetPath«) of a ZFS dataset, this deducts crypto-related options from the declared keys (»config.setup.keystore.keys."zfs/..."«).
|
## Given the name (»datasetPath«) of a ZFS dataset, this deducts crypto-related options from the declared keys (»config.setup.keystore.keys."zfs/..."«).
|
||||||
|
@ -17,6 +17,9 @@ in {
|
|||||||
This is not implemented for mounts in the initrd (those that are `neededForBoot`) yet.
|
This is not implemented for mounts in the initrd (those that are `neededForBoot`) yet.
|
||||||
Note that if a symlink exists at a mount point when systemd's fstab-generator runs, it will read/resolve the symlink and use the link's target as the mount point, resulting in mismatching unit names for that mount, effectively disabling its `.preMountCommands`.
|
Note that if a symlink exists at a mount point when systemd's fstab-generator runs, it will read/resolve the symlink and use the link's target as the mount point, resulting in mismatching unit names for that mount, effectively disabling its `.preMountCommands`.
|
||||||
This does not (apparently and unfortunately) run when mounting via the `mount` command (and probably not with the `mount` system call either).
|
This does not (apparently and unfortunately) run when mounting via the `mount` command (and probably not with the `mount` system call either).
|
||||||
|
''; type = lib.types.lines; default = ""; };
|
||||||
|
postUnmountCommands = lib.mkOption { description = ''
|
||||||
|
Like `.preMountCommands`, but runs after unmounting the filesystem.
|
||||||
''; type = lib.types.lines; default = ""; };
|
''; type = lib.types.lines; default = ""; };
|
||||||
#Also, trying to create the "device" of a "nofail" mount will not work with `mount`, as it will not even attempt to mount anything (and thus not run the `.preMountCommands`) if the "device" is missing.
|
#Also, trying to create the "device" of a "nofail" mount will not work with `mount`, as it will not even attempt to mount anything (and thus not run the `.preMountCommands`) if the "device" is missing.
|
||||||
}; } ]);
|
}; } ]);
|
||||||
@ -31,17 +34,19 @@ in {
|
|||||||
}) config.fileSystems;
|
}) config.fileSystems;
|
||||||
|
|
||||||
# The implementation is derived from the "mkfs-${device'}" service in nixpkgs.
|
# The implementation is derived from the "mkfs-${device'}" service in nixpkgs.
|
||||||
systemd.services = lib.fun.mapMergeUnique (_: args@{ mountPoint, device, depends, ... }: if (args.preMountCommands != "") then let
|
systemd.services = lib.fun.mapMergeUnique (_: args@{ mountPoint, device, depends, ... }: if (args.preMountCommands != "") || (args.postUnmountCommands != "") then let
|
||||||
isDevice = lib.fun.startsWith "/dev/" device;
|
isDevice = lib.fun.startsWith "/dev/" device;
|
||||||
mountPoint' = utils.escapeSystemdPath mountPoint;
|
mountPoint' = utils.escapeSystemdPath mountPoint;
|
||||||
device' = utils.escapeSystemdPath device;
|
device' = utils.escapeSystemdPath device;
|
||||||
in { "pre-mount-${mountPoint'}" = {
|
in { "pre-mount-${mountPoint'}" = rec {
|
||||||
description = "Prepare mounting ${device} at ${mountPoint}";
|
description = "Prepare mounting ${device} at ${mountPoint}";
|
||||||
wantedBy = [ "${mountPoint'}.mount" ]; before = [ "${mountPoint'}.mount" ];
|
wantedBy = [ "${mountPoint'}.mount" ]; before = wantedBy; partOf = wantedBy;
|
||||||
requires = lib.optional isDevice "${device'}.device"; after = lib.optional isDevice "${device'}.device";
|
requires = lib.optional isDevice "${device'}.device"; after = lib.optional isDevice "${device'}.device";
|
||||||
unitConfig.RequiresMountsFor = depends ++ [ (builtins.dirOf device) (builtins.dirOf mountPoint) ];
|
unitConfig.RequiresMountsFor = map utils.escapeSystemdExecArg (depends ++ (lib.optional (lib.hasPrefix "/" device) device) ++ [ (builtins.dirOf mountPoint) ]);
|
||||||
unitConfig.DefaultDependencies = false;
|
unitConfig.DefaultDependencies = false; restartIfChanged = false;
|
||||||
serviceConfig.Type = "oneshot"; script = args.preMountCommands;
|
serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true;
|
||||||
|
script = lib.mkIf (args.preMountCommands != "") args.preMountCommands;
|
||||||
|
preStop = lib.mkIf (args.postUnmountCommands != "") args.postUnmountCommands; # ("preStop" still runs post unmount)
|
||||||
}; } else { }) config.fileSystems;
|
}; } else { }) config.fileSystems;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user