]> git.proxmox.com Git - mirror_zfs.git/blame - contrib/dracut/90zfs/zfs-lib.sh.in
contrib; dracut: centralise root= parsing, actually support root=s
[mirror_zfs.git] / contrib / dracut / 90zfs / zfs-lib.sh.in
CommitLineData
16692e6b 1#!/bin/sh
eda3d4e1 2
245529d8 3command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
d402c18d
MAR
4command -v getargbool >/dev/null || {
5 # Compatibility with older Dracut versions.
6 # With apologies to the Dracut developers.
7 getargbool() {
d402c18d 8 _default="$1"; shift
2ca77988 9 ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default"
d402c18d 10 if [ -n "$_b" ]; then
41532e5a
KP
11 [ "$_b" = "0" ] && return 1
12 [ "$_b" = "no" ] && return 1
13 [ "$_b" = "off" ] && return 1
d402c18d
MAR
14 fi
15 return 0
16 }
17}
eda3d4e1
ST
18
19OLDIFS="${IFS}"
20NEWLINE="
21"
d8ced661 22TAB=" "
eda3d4e1
ST
23
24ZPOOL_IMPORT_OPTS=""
25if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
41532e5a
KP
26 warn "ZFS: Will force-import pools if necessary."
27 ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f"
eda3d4e1
ST
28fi
29
30# find_bootfs
31# returns the first dataset with the bootfs attribute.
32find_bootfs() {
41532e5a
KP
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
eda3d4e1
ST
53}
54
55# import_pool POOL
56# imports the given zfs pool if it isn't imported already.
57import_pool() {
d8ced661 58 pool="${1}"
eda3d4e1 59
41532e5a
KP
60 if ! zpool list -H "${pool}" > /dev/null 2>&1; then
61 info "ZFS: Importing pool ${pool}..."
6fc30992 62 # shellcheck disable=SC2086
41532e5a
KP
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
eda3d4e1 68
41532e5a 69 return 0
eda3d4e1
ST
70}
71
d8ced661 72_mount_dataset_cb() {
34eef3e9 73 # shellcheck disable=SC2154
d8ced661
AZ
74 mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
75}
76
eda3d4e1
ST
77# mount_dataset DATASET
78# mounts the given zfs dataset.
79mount_dataset() {
d8ced661 80 dataset="${1}"
41532e5a 81 mountpoint="$(zfs get -H -o value mountpoint "${dataset}")"
d8ced661 82 ret=0
eda3d4e1 83
41532e5a
KP
84 # We need zfsutil for non-legacy mounts and not for legacy mounts.
85 if [ "${mountpoint}" = "legacy" ] ; then
d8ced661 86 mount -t zfs "${dataset}" "${NEWROOT}" || ret=$?
41532e5a 87 else
d8ced661
AZ
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
41532e5a 93 fi
eda3d4e1 94
34eef3e9 95 return "${ret}"
d8ced661
AZ
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
34eef3e9 121 exit "${_ret}"
d8ced661 122 )
eda3d4e1
ST
123}
124
7280d581
KP
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() {
41532e5a
KP
145 ply_tries=3
146 tty_tries=3
147 while [ "$#" -gt 0 ]; do
7280d581
KP
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;;
34eef3e9 159 *) echo "ask_for_password(): wrong opt '$1'" >&2;;
7280d581
KP
160 esac
161 shift
162 done
163
245529d8
AZ
164 {
165 flock -s 9
166
7280d581 167 # Prompt for password with plymouth, if installed and running.
16692e6b 168 if plymouth --ping 2>/dev/null; then
7280d581 169 plymouth ask-for-password \
f20fb199
MV
170 --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \
171 eval "$ply_cmd"
7280d581
KP
172 ret=$?
173 else
174 if [ "$tty_echo_off" = yes ]; then
175 stty_orig="$(stty -g)"
176 stty -echo
177 fi
178
41532e5a
KP
179 i=1
180 while [ "$i" -le "$tty_tries" ]; do
7280d581 181 [ -n "$tty_prompt" ] && \
41532e5a 182 printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2
7280d581
KP
183 eval "$tty_cmd" && ret=0 && break
184 ret=$?
41532e5a 185 i=$((i+1))
7280d581
KP
186 [ -n "$tty_prompt" ] && printf '\n' >&2
187 done
41532e5a
KP
188 unset i
189 [ "$tty_echo_off" = yes ] && stty "$stty_orig"
7280d581
KP
190 fi
191 } 9>/.console_lock
192
34eef3e9
DS
193 [ "$ret" -ne 0 ] && echo "Wrong password" >&2
194 return "$ret"
7280d581 195}
245529d8
AZ
196
197# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
198#
199# True if ZFS-on-root, false if we shouldn't
200#
201# Supported values:
202# root=
203# root=zfs
204# root=zfs:
205# root=zfs:AUTO
206#
207# root=ZFS=data/set
208# root=zfs:data/set
209# root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
210#
211# rootfstype=zfs AND root=data/set <=> root=data/set
212# rootfstype=zfs AND root= <=> root=zfs:AUTO
213#
214# '+'es in explicit dataset decoded to ' 's.
215decode_root_args() {
216 if [ -n "$rootfstype" ]; then
217 [ "$rootfstype" = zfs ]
218 return
219 fi
220
221 root=$(getarg root=)
222 rootfstype=$(getarg rootfstype=)
223
224 # shellcheck disable=SC2249
225 case "$root" in
226 ""|zfs|zfs:|zfs:AUTO)
227 root=zfs:AUTO
228 rootfstype=zfs
229 return 0
230 ;;
231
232 ZFS=*|zfs:*)
233 root="${root#zfs:}"
234 root="${root#ZFS=}"
235 root=$(echo "$root" | tr '+' ' ')
236 rootfstype=zfs
237 return 0
238 ;;
239 esac
240
241 if [ "$rootfstype" = "zfs" ]; then
242 case "$root" in
243 "") root=zfs:AUTO ;;
244 *) root=$(echo "$root" | tr '+' ' ') ;;
245 esac
246 return 0
247 fi
248
249 return 1
250}