1#!/bin/sh
2# shellcheck disable=SC2154
3
4# only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise
5[ -e /bin/systemctl ] || [ -e /usr/bin/systemctl ] || return 0
6
7# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems
8
9# import the libs now that we know the pool imported
10[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
11[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
12# shellcheck source=./lib-zfs.sh.in
13. "$dracutlib"
14
15# load the kernel command line vars
16[ -z "$root" ] && root="$(getarg root=)"
17# If root is not ZFS= or zfs: or rootfstype is not zfs then we are not supposed to handle it.
18[ "${root##zfs:}" = "${root}" ] && [ "${root##ZFS=}" = "${root}" ] && [ "$rootfstype" != "zfs" ] && exit 0
19
20# There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported
21while [ "$(zpool list -H)" = "" ]; do
22    systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1
23    sleep 0.1s
24done
25
26# run this after import as zfs-import-cache/scan service is confirmed good
27# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset
28if [ "${root}" = "zfs:AUTO" ] ; then
29    BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')"
30else
31    BOOTFS="${root##zfs:}"
32    BOOTFS="${BOOTFS##ZFS=}"
33fi
34
35# if pool encryption is active and the zfs command understands '-o encryption'
36if [ "$(zpool list -H -o feature@encryption "${BOOTFS%%/*}")" = 'active' ]; then
37    # if the root dataset has encryption enabled
38    ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${BOOTFS}")"
39    if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
40        KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
41        # continue only if the key needs to be loaded
42        [ "$KEYSTATUS" = "unavailable" ] || exit 0
43
44        KEYLOCATION="$(zfs get -H -o value keylocation "${ENCRYPTIONROOT}")"
45        case "${KEYLOCATION%%://*}" in
46            prompt)
47                for _ in 1 2 3; do
48                    systemd-ask-password --no-tty "Encrypted ZFS password for ${BOOTFS}" | zfs load-key "${ENCRYPTIONROOT}" && break
49                done
50                ;;
51            http*)
52                systemctl start network-online.target
53                zfs load-key "${ENCRYPTIONROOT}"
54                ;;
55            file)
56                KEYFILE="${KEYLOCATION#file://}"
57                [ -r "${KEYFILE}" ] || udevadm settle
58                [ -r "${KEYFILE}" ] || {
59                    info "Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..."
60                    for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
61                        sleep 0.5s
62                        [ -r "${KEYFILE}" ] && break
63                    done
64                }
65                [ -r "${KEYFILE}" ] || warn "Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway."
66                zfs load-key "${ENCRYPTIONROOT}"
67                ;;
68            *)
69                zfs load-key "${ENCRYPTIONROOT}"
70                ;;
71        esac
72    fi
73fi
74