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 # shellcheck disable=SC2154 74 mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}" 75} 76 77# mount_dataset DATASET 78# mounts the given zfs dataset. 79mount_dataset() { 80 dataset="${1}" 81 mountpoint="$(zfs get -H -o value mountpoint "${dataset}")" 82 ret=0 83 84 # We need zfsutil for non-legacy mounts and not for legacy mounts. 85 if [ "${mountpoint}" = "legacy" ] ; then 86 mount -t zfs "${dataset}" "${NEWROOT}" || ret=$? 87 else 88 mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$? 89 90 if [ "$ret" = "0" ]; then 91 for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$? 92 fi 93 fi 94 95 return "${ret}" 96} 97 98# for_relevant_root_children DATASET EXEC 99# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup 100# Used by zfs-generator.sh and friends, too! 101for_relevant_root_children() { 102 dataset="${1}" 103 exec="${2}" 104 105 zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | 106 ( 107 _ret=0 108 while IFS="${TAB}" read -r dataset mountpoint canmount; do 109 [ "$canmount" != "on" ] && continue 110 111 case "$mountpoint" in 112 /etc|/bin|/lib|/lib??|/libx32|/usr) 113 # 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 114 "${exec}" "${dataset}" "${mountpoint}" || _ret=$? 115 ;; 116 *) 117 # Up to the real init to remount everything else it might need 118 ;; 119 esac 120 done 121 exit "${_ret}" 122 ) 123} 124 125# ask_for_password 126# 127# Wraps around plymouth ask-for-password and adds fallback to tty password ask 128# if plymouth is not present. 129# 130# --cmd command 131# Command to execute. Required. 132# --prompt prompt 133# Password prompt. Note that function already adds ':' at the end. 134# Recommended. 135# --tries n 136# How many times repeat command on its failure. Default is 3. 137# --ply-[cmd|prompt|tries] 138# Command/prompt/tries specific for plymouth password ask only. 139# --tty-[cmd|prompt|tries] 140# Command/prompt/tries specific for tty password ask only. 141# --tty-echo-off 142# Turn off input echo before tty command is executed and turn on after. 143# It's useful when password is read from stdin. 144ask_for_password() { 145 ply_tries=3 146 tty_tries=3 147 while [ "$#" -gt 0 ]; do 148 case "$1" in 149 --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;; 150 --ply-cmd) ply_cmd="$2"; shift;; 151 --tty-cmd) tty_cmd="$2"; shift;; 152 --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;; 153 --ply-prompt) ply_prompt="$2"; shift;; 154 --tty-prompt) tty_prompt="$2"; shift;; 155 --tries) ply_tries="$2"; tty_tries="$2"; shift;; 156 --ply-tries) ply_tries="$2"; shift;; 157 --tty-tries) tty_tries="$2"; shift;; 158 --tty-echo-off) tty_echo_off=yes;; 159 *) echo "ask_for_password(): wrong opt '$1'" >&2;; 160 esac 161 shift 162 done 163 164 { flock -s 9; 165 # Prompt for password with plymouth, if installed and running. 166 if plymouth --ping 2>/dev/null; then 167 plymouth ask-for-password \ 168 --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \ 169 eval "$ply_cmd" 170 ret=$? 171 else 172 if [ "$tty_echo_off" = yes ]; then 173 stty_orig="$(stty -g)" 174 stty -echo 175 fi 176 177 i=1 178 while [ "$i" -le "$tty_tries" ]; do 179 [ -n "$tty_prompt" ] && \ 180 printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2 181 eval "$tty_cmd" && ret=0 && break 182 ret=$? 183 i=$((i+1)) 184 [ -n "$tty_prompt" ] && printf '\n' >&2 185 done 186 unset i 187 [ "$tty_echo_off" = yes ] && stty "$stty_orig" 188 fi 189 } 9>/.console_lock 190 191 [ "$ret" -ne 0 ] && echo "Wrong password" >&2 192 return "$ret" 193} 194