#!/bin/sh command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh command -v getargbool >/dev/null || { # Compatibility with older Dracut versions. # With apologies to the Dracut developers. getargbool() { _default="$1"; shift ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default" if [ -n "$_b" ]; then [ "$_b" = "0" ] && return 1 [ "$_b" = "no" ] && return 1 [ "$_b" = "off" ] && return 1 fi return 0 } } OLDIFS="${IFS}" NEWLINE=" " TAB=" " ZPOOL_IMPORT_OPTS="" if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then warn "ZFS: Will force-import pools if necessary." ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f" fi # import_pool POOL # imports the given zfs pool if it isn't imported already. import_pool() { pool="${1}" if ! zpool list -H "${pool}" > /dev/null 2>&1; then info "ZFS: Importing pool ${pool}..." # shellcheck disable=SC2086 if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${pool}" ; then warn "ZFS: Unable to import pool ${pool}" return 1 fi fi return 0 } _mount_dataset_cb() { mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}" } # mount_dataset DATASET # mounts the given zfs dataset. mount_dataset() { dataset="${1}" mountpoint="$(zfs get -H -o value mountpoint "${dataset}")" ret=0 # We need zfsutil for non-legacy mounts and not for legacy mounts. if [ "${mountpoint}" = "legacy" ] ; then mount -t zfs "${dataset}" "${NEWROOT}" || ret=$? else mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$? if [ "$ret" = "0" ]; then for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$? fi fi return ${ret} } # for_relevant_root_children DATASET EXEC # Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup # Used by zfs-generator.sh 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="${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} ) } # ask_for_password tries prompt cmd # # Wraps around plymouth ask-for-password and adds fallback to tty password ask # if plymouth is not present. ask_for_password() { tries="$1" prompt="$2" cmd="$3" { flock -s 9 # Prompt for password with plymouth, if installed and running. if plymouth --ping 2>/dev/null; then plymouth ask-for-password \ --prompt "$prompt" --number-of-tries="$tries" | \ eval "$cmd" ret=$? else i=1 while [ "$i" -le "$tries" ]; do printf "%s [%i/%i]:" "$prompt" "$i" "$tries" >&2 eval "$cmd" && ret=0 && break ret=$? i=$((i+1)) printf '\n' >&2 done unset i fi } 9>/.console_lock [ $ret -ne 0 ] && echo "Wrong password" >&2 return $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 root=$(getarg root=) rootfstype=$(getarg rootfstype=) # shellcheck disable=SC2249 case "$root" in ""|zfs|zfs:|zfs:AUTO) root=zfs:AUTO rootfstype=zfs return 0 ;; ZFS=*|zfs:*) root="${root#zfs:}" root="${root#ZFS=}" root=$(echo "$root" | tr '+' ' ') rootfstype=zfs return 0 ;; esac if [ "$rootfstype" = "zfs" ]; then case "$root" in "") root=zfs:AUTO ;; *) root=$(echo "$root" | tr '+' ' ') ;; esac return 0 fi return 1 }