#!/bin/sh
while getopts "z:d:p:v" arg; do
    case $arg in
        z) zpool=$OPTARG      ;;
        d) dest=$OPTARG       ;;
        p) passphrase=$OPTARG ;;
        v) verbose=1          ;;
    esac
done
_hash() { md5sum|awk '{print $1}'|sha1sum|awk '{print $1}'|sha224sum|awk '{print $1}'|sha256sum|awk '{print $1}'|sha384sum|awk '{print $1}'|sha512sum|awk '{print $1}'; }
# Hold the hash in a variable: printf does not read stdin, so piping into
# `printf '%s\n' "$(cat)"` relied on whatever stdin the caller happened to
# have. Same output, no dependence on the calling context.
# Keep in sync with the Arch install hook: the two must derive identical keys
# or an initramfs built by one cannot unlock the other's pool.
_keygen() { local h; h=$(printf '%s\n' "$1"|_hash); printf '%s\n' "$h"|base64 -w 0|cut -c1-500; }
# Resolve the pool from the dataset serving /. The mount table is relative to the
# caller's root, so this stays correct in a chroot. findmnt --target matches the
# mountpoint exactly and -t zfs fails cleanly when / is not ZFS; the awk fallback
# reads the same data from mountinfo, since busybox has no findmnt.
[ -z "$zpool" ] && {
    if command -v findmnt >/dev/null 2>&1; then
        rootds=$(findmnt -n -o SOURCE --target / -t zfs 2>/dev/null)
    else
        rootds=$(awk '$5=="/" {for(i=6;i<=NF;i++) if($i=="-"){if($(i+1)=="zfs") print $(i+2); exit}}' /proc/self/mountinfo 2>/dev/null)
    fi
    zpool="${rootds%%/*}"
}
[ -z "$zpool" ] && { echo "zpool not found"; exit 1; }
[ -z "$(zpool list -o name|grep -v "NAME"|grep "^$zpool$")" ] && { echo "[$zpool] zpool not found"; exit 1; }
[ -z "$passphrase" ] && { echo "passphrase required: -p <passphrase>"; exit 1; }
tmp=$(mktemp /dev/shm/keys.XXXXXX)
chmod 600 "$tmp"
trap 'rm -f "$tmp" /dev/shm/encpass' EXIT INT TERM
# zpool status shows a vdev by the path it was imported with, e.g.
# /dev/mapper/<uuid> after `zpool import -d /dev/mapper`. Keep only the last
# component: it is both the _keygen input and the LUKS UUID safego opens, so a
# path here derives the wrong key and names a device that does not exist.
zpool status "$zpool"|grep "ONLINE"|grep -v state|grep -v "$zpool"|awk '{sub(/.*\//,"",$1); print $1}'|while IFS= read -r line; do
    printf '%s %s\n' "$(_keygen "$line")" "$line" >> "$tmp"
done
printf '%s %s\n' "$(_keygen "$(zpool get -H -o value guid "$zpool")")" "$zpool" >> "$tmp"
[ -n "$verbose" ] && cat "$tmp"
[ -n "$dest" ] && {
    openssl enc -aes-256-cbc -pbkdf2 -pass "pass:$passphrase" -in "$tmp" -out "$dest"
}