1#!/bin/sh 2 3command -v getarg >/dev/null || . /lib/dracut-lib.sh 4command -v getargbool >/dev/null || { 5 # Compatibility with older Dracut versions. 6 # With apologies to the Dracut developers. 7 getargbool() { 8 _default="$1"; shift 9 ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default" 10 if [ -n "$_b" ]; then 11 [ "$_b" = "0" ] && return 1 12 [ "$_b" = "no" ] && return 1 13 [ "$_b" = "off" ] && return 1 14 fi 15 return 0 16 } 17} 18 19OLDIFS="${IFS}" 20NEWLINE=" 21" 22TAB=" " 23 24ZPOOL_IMPORT_OPTS="" 25if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then 26 warn "ZFS: Will force-import pools if necessary." 27 ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f" 28fi 29 30# find_bootfs 31# returns the first dataset with the bootfs attribute. 32find_bootfs() { 33 IFS="${NEWLINE}" 34 for dataset in $(zpool list -H -o bootfs); do 35 case "${dataset}" in 36 "" | "-") 37 continue 38 ;; 39 "no pools available") 40 IFS="${OLDIFS}" 41 return 1 42 ;; 43 *) 44 IFS="${OLDIFS}" 45 echo "${dataset}" 46 return 0 47 ;; 48 esac 49 done 50 51 IFS="${OLDIFS}" 52 return 1 53} 54 55# import_pool POOL 56# imports the given zfs pool if it isn't imported already. 57import_pool() { 58 pool="${1}" 59 60 if ! zpool list -H "${pool}" > /dev/null 2>&1; then 61 info "ZFS: Importing pool ${pool}..." 62 # shellcheck disable=SC2086 63 if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${pool}" ; then 64 warn "ZFS: Unable to import pool ${pool}" 65 return 1 66 fi 67 fi 68 69 return 0 70} 71 72_mount_dataset_cb() { 73 mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}" 74} 75 76# mount_dataset DATASET 77# mounts the given zfs dataset. 78mount_dataset() { 79 dataset="${1}" 80 mountpoint="$(zfs get -H -o value mountpoint "${dataset}")" 81 ret=0 82 83 # We need zfsutil for non-legacy mounts and not for legacy mounts. 84 if [ "${mountpoint}" = "legacy" ] ; then 85 mount -t zfs "${dataset}" "${NEWROOT}" || ret=$? 86 else 87 mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$? 88 89 if [ "$ret" = "0" ]; then 90 for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$? 91 fi 92 fi 93 94 return ${ret} 95} 96 97# for_relevant_root_children DATASET EXEC 98# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup 99# Used by zfs-generator.sh and friends, too! 100for_relevant_root_children() { 101 dataset="${1}" 102 exec="${2}" 103 104 zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | 105 ( 106 _ret=0 107 while IFS="${TAB}" read -r dataset mountpoint canmount; do 108 [ "$canmount" != "on" ] && continue 109 110 case "$mountpoint" in 111 /etc|/bin|/lib|/lib??|/libx32|/usr) 112 # 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 113 "${exec}" "${dataset}" "${mountpoint}" || _ret=$? 114 ;; 115 *) 116 # Up to the real init to remount everything else it might need 117 ;; 118 esac 119 done 120 exit ${_ret} 121 ) 122} 123 124# export_all OPTS 125# exports all imported zfs pools. 126export_all() { 127 ret=0 128 129 IFS="${NEWLINE}" 130 for pool in $(zpool list -H -o name) ; do 131 if zpool list -H "${pool}" > /dev/null 2>&1; then 132 zpool export "${pool}" "$@" || ret=$? 133 fi 134 done 135 IFS="${OLDIFS}" 136 137 return ${ret} 138} 139 140# ask_for_password 141# 142# Wraps around plymouth ask-for-password and adds fallback to tty password ask 143# if plymouth is not present. 144# 145# --cmd command 146# Command to execute. Required. 147# --prompt prompt 148# Password prompt. Note that function already adds ':' at the end. 149# Recommended. 150# --tries n 151# How many times repeat command on its failure. Default is 3. 152# --ply-[cmd|prompt|tries] 153# Command/prompt/tries specific for plymouth password ask only. 154# --tty-[cmd|prompt|tries] 155# Command/prompt/tries specific for tty password ask only. 156# --tty-echo-off 157# Turn off input echo before tty command is executed and turn on after. 158# It's useful when password is read from stdin. 159ask_for_password() { 160 ply_tries=3 161 tty_tries=3 162 while [ "$#" -gt 0 ]; do 163 case "$1" in 164 --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;; 165 --ply-cmd) ply_cmd="$2"; shift;; 166 --tty-cmd) tty_cmd="$2"; shift;; 167 --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;; 168 --ply-prompt) ply_prompt="$2"; shift;; 169 --tty-prompt) tty_prompt="$2"; shift;; 170 --tries) ply_tries="$2"; tty_tries="$2"; shift;; 171 --ply-tries) ply_tries="$2"; shift;; 172 --tty-tries) tty_tries="$2"; shift;; 173 --tty-echo-off) tty_echo_off=yes;; 174 esac 175 shift 176 done 177 178 { flock -s 9; 179 # Prompt for password with plymouth, if installed and running. 180 if plymouth --ping 2>/dev/null; then 181 plymouth ask-for-password \ 182 --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \ 183 eval "$ply_cmd" 184 ret=$? 185 else 186 if [ "$tty_echo_off" = yes ]; then 187 stty_orig="$(stty -g)" 188 stty -echo 189 fi 190 191 i=1 192 while [ "$i" -le "$tty_tries" ]; do 193 [ -n "$tty_prompt" ] && \ 194 printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2 195 eval "$tty_cmd" && ret=0 && break 196 ret=$? 197 i=$((i+1)) 198 [ -n "$tty_prompt" ] && printf '\n' >&2 199 done 200 unset i 201 [ "$tty_echo_off" = yes ] && stty "$stty_orig" 202 fi 203 } 9>/.console_lock 204 205 [ $ret -ne 0 ] && echo "Wrong password" >&2 206 return $ret 207} 208