diff --git a/initrd/dracut/tzpfms-load-key.sh b/initrd/dracut/tzpfms-load-key.sh index 132028c..fec3566 100755 --- a/initrd/dracut/tzpfms-load-key.sh +++ b/initrd/dracut/tzpfms-load-key.sh @@ -3,69 +3,34 @@ #include "../mount.h" +WITH_PROMPTABLE_TTY{< /dev/console > /dev/console 2>&1} +#include "../zfs-lib.sh.h" # Only run on systemd systems, mimicking zfs-dracut's zfs-load-key.sh; TODO: "see mount-zfs.sh for non-systemd systems", confer README -[ -d /run/systemd ] || exit 0 +[ -d /run/systemd ] || return 0 . "/lib/dracut-lib.sh" - - -# If root is not "ZFS=" or "zfs:", or rootfstype is not "zfs" then we aren't supposed to handle it -root="${root:=$(getarg root=)}" -rootfstype="${rootfstype:=$(getarg rootfstype=)}" -[ "${root##zfs:}" = "$root" ] && [ "${root##ZFS=}" = "$root" ] && [ "$rootfstype" != "zfs" ] && exit 0 - -TZPFMS_TPM1X="$(getarg TZPFMS_TPM1X=)" -[ -z "$TZPFMS_TPM1X" ] || export TZPFMS_TPM1X - -getarg 0 quiet && quiet=y +decode_root_args || return 0 # There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported -while [ "$(zpool list -H)" = "" ]; do +while ! systemctl is-active --quiet zfs-import.target; do + systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1 sleep 0.1s - systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1 done - -if [ "$root" = "zfs:AUTO" ]; then - BOOTFS="$(zpool list -H -o bootfs | while read -r b; do [ "$b" = '-' ] || { printf '%s\n' "$b"; exit; }; done)" -else - BOOTFS="${root##zfs:}" - BOOTFS="${BOOTFS##ZFS=}" +BOOTFS="$root" +if [ "$BOOTFS" = "zfs:AUTO" ]; then + BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)" fi +[ "$(zpool get -Ho value feature@encryption "${BOOTFS%%/*}")" = 'active' ] || return 0 -WITH_PROMPTABLE_TTY{< /dev/console > /dev/console 2>&1} -# tzpfms_for_relevant_root_children DATASET EXEC -# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup -# Used by zfs-nonroot-necessities.service and friends, too! -tzpfms_for_relevant_root_children() { - dataset="${1}" - exec="${2}" +getarg 0 quiet && quiet=y - zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | - ( - _ret=0 - while IFS="${TAB}" read -r dataset mountpoint canmount; do - [ "$canmount" != "on" ] && continue - - case "$mountpoint" in - /etc|/bin|/lib|/lib??|/libx32|/usr) - # If these aren't mounted we may not be able to get to the real init at all, or pollute the dataset holding the rootfs - "${exec}" "${dataset}" "${mountpoint}" || _ret=$? - ;; - *) - # Up to the real init to remount everything else it might need - ;; - esac - done - exit "${_ret}" - ) -} tzpfms_load() { # Match this sexion to i-t/zfs-patch.sh @@ -83,14 +48,5 @@ tzpfms_load() { } -# If pool encryption is active and the zfs command understands '-o encryption' -if [ "$(zpool list -H -o feature@encryption "${BOOTFS%%/*}")" = "active" ]; then - ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "$BOOTFS")" - - if ! [ "${ENCRYPTIONROOT}" = "-" ]; then - tzpfms_load "$ENCRYPTIONROOT" || exit - # Fall through to zfs-dracut's zfs-load-key.sh - fi - - tzpfms_for_relevant_root_children "$ENCRYPTIONROOT" tzpfms_load || exit -fi +tzpfms_load "$BOOTFS" +for_relevant_root_children "$BOOTFS" tzpfms_load diff --git a/initrd/zfs-lib.sh.h b/initrd/zfs-lib.sh.h new file mode 100644 index 0000000..42b99dc --- /dev/null +++ b/initrd/zfs-lib.sh.h @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: 0BSD +# dbda45160ffa43e5ecf0498a609230f1afee7b3f (zfs-2.2.99-270-gdbda45160) + + +# for_relevant_root_children DATASET EXEC +# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup +# Used by zfs-nonroot-necessities.service and friends, too! +for_relevant_root_children() { + dataset="${1}" + exec="${2}" + + zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | + ( + _ret=0 + while IFS=" " read -r dataset mountpoint canmount; do + [ "$canmount" != "on" ] && continue + + case "$mountpoint" in + /etc|/bin|/lib|/lib??|/libx32|/usr) + # If these aren't mounted we may not be able to get to the real init at all, or pollute the dataset holding the rootfs + "${exec}" "${dataset}" "${mountpoint}" || _ret=$? + ;; + *) + # Up to the real init to remount everything else it might need + ;; + esac + done + exit "${_ret}" + ) +} + +# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit +# +# True if ZFS-on-root, false if we shouldn't +# +# Supported values: +# root= +# root=zfs +# root=zfs: +# root=zfs:AUTO +# +# root=ZFS=data/set +# root=zfs:data/set +# root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented) +# +# rootfstype=zfs AND root=data/set <=> root=data/set +# rootfstype=zfs AND root= <=> root=zfs:AUTO +# +# '+'es in explicit dataset decoded to ' 's. +decode_root_args() { + if [ -n "$rootfstype" ]; then + [ "$rootfstype" = zfs ] + return + fi + + xroot=$(getarg root=) + rootfstype=$(getarg rootfstype=) + + # shellcheck disable=SC2249 + case "$xroot" in + ""|zfs|zfs:|zfs:AUTO) + root=zfs:AUTO + rootfstype=zfs + return 0 + ;; + + ZFS=*|zfs:*) + root="${xroot#zfs:}" + root="${root#ZFS=}" + root=$(echo "$root" | tr '+' ' ') + rootfstype=zfs + return 0 + ;; + esac + + if [ "$rootfstype" = "zfs" ]; then + case "$xroot" in + "") root=zfs:AUTO ;; + *) root=$(echo "$xroot" | tr '+' ' ') ;; + esac + return 0 + fi + + return 1 +}