Skip to content

Commit ee468aa

Browse files
committed
Initial split of core menu logic from initialization
To support remote interaction with something like dropbear, the core menu should be divorced from the early setup and executable from the command line. The setup is done exactly once and touches an "initialized" file to signal when it has finished. The menu script awaits this signal when it launches. To prevent simultaneous execution of multiple instances, the menu script uses a mutex.
1 parent 5768f3a commit ee468aa

File tree

5 files changed

+180
-125
lines changed

5 files changed

+180
-125
lines changed

90zfsbootmenu/module-setup.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ install() {
129129
_ret=0
130130
# shellcheck disable=SC2154
131131
inst_simple "${moddir}/zfsbootmenu-lib.sh" "/lib/zfsbootmenu-lib.sh" || _ret=$?
132+
inst_simple "${moddir}/zfsbootmenu-countdown.sh" "/libexec/zfsbootmenu-countdown" || _ret=$?
132133
inst_simple "${moddir}/zfsbootmenu-preview.sh" "/bin/zfsbootmenu-preview.sh" || _ret=$?
133134
inst_simple "${moddir}/zfs-chroot" "/bin/zfs-chroot" || _ret=$?
134135
inst_simple "${moddir}/zfsbootmenu.sh" "/bin/zfsbootmenu" || _ret=$?
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/bin/bash
2+
# vim: softtabstop=2 shiftwidth=2 expandtab
3+
4+
# store current kernel log level
5+
read -r PRINTK < /proc/sys/kernel/printk
6+
PRINTK=${PRINTK:0:1}
7+
export PRINTK
8+
9+
# Set it to 0
10+
echo 0 > /proc/sys/kernel/printk
11+
12+
# disable ctrl-c (SIGINT)
13+
trap '' SIGINT
14+
15+
# shellcheck disable=SC1091
16+
test -f /lib/zfsbootmenu-lib.sh && source /lib/zfsbootmenu-lib.sh
17+
# shellcheck disable=SC1091
18+
test -f zfsbootmenu-lib.sh && source zfsbootmenu-lib.sh
19+
20+
echo "Loading boot menu ..."
21+
TERM=linux
22+
tput reset
23+
24+
export BASE="/zfsbootmenu"
25+
mkdir -p "${BASE}"
26+
27+
modprobe zfs 2>/dev/null
28+
udevadm settle
29+
30+
# try to set console options for display and interaction
31+
# this is sometimes run as an initqueue hook, but cannot be guaranteed
32+
#shellcheck disable=SC2154
33+
test -x /lib/udev/console_init -a -c "${control_term}" \
34+
&& /lib/udev/console_init "${control_term##*/}" >/dev/null 2>&1
35+
36+
# set the console size, if indicated
37+
#shellcheck disable=SC2154
38+
if [ -n "$zbm_lines" ]; then
39+
stty rows "$zbm_lines"
40+
fi
41+
42+
#shellcheck disable=SC2154
43+
if [ -n "$zbm_columns" ]; then
44+
stty cols "$zbm_columns"
45+
fi
46+
47+
# Attempt to import all pools read-only
48+
read_write='' all_pools=yes import_pool
49+
50+
# Make sure at least one pool can be imported; if not,
51+
# drop to an emergency shell to allow the user to attempt recovery
52+
import_success=0
53+
while true; do
54+
while IFS=$'\t' read -r _pool _health; do
55+
[ -n "${_pool}" ] || continue
56+
57+
import_success=1
58+
if [ "${_health}" != "ONLINE" ]; then
59+
echo "${_pool}" >> "${BASE}/degraded"
60+
fi
61+
done <<<"$( zpool list -H -o name,health )"
62+
63+
if [ "${import_success}" -ne 1 ]; then
64+
emergency_shell "unable to successfully import a pool"
65+
else
66+
break
67+
fi
68+
done
69+
70+
# Prefer a specific pool when checking for a bootfs value
71+
# shellcheck disable=SC2154
72+
if [ "${root}" = "zfsbootmenu" ]; then
73+
boot_pool=
74+
else
75+
boot_pool="${root}"
76+
fi
77+
78+
# Make sure the preferred pool was imported
79+
if [ -n "${boot_pool}" ] && ! zpool list -H -o name "${boot_pool}" >/dev/null 2>&1; then
80+
emergency_shell "\nCannot import requested pool '${boot_pool}'\nType 'exit' to try booting anyway"
81+
fi
82+
83+
unsupported=0
84+
while IFS=$'\t' read -r _pool _property; do
85+
if [[ "${_property}" =~ "unsupported@" ]]; then
86+
if ! grep -q "${_pool}" "${BASE}/degraded" >/dev/null 2>&1 ; then
87+
echo "${_pool}" >> "${BASE}/degraded"
88+
fi
89+
unsupported=1
90+
fi
91+
done <<<"$( zpool get all -H -o name,property )"
92+
93+
if [ "${unsupported}" -ne 0 ]; then
94+
color=red timed_prompt "Unsupported features detected" "Upgrade ZFS modules in ZFSBootMenu with generate-zbm"
95+
fi
96+
97+
# Attempt to find the bootfs property
98+
# shellcheck disable=SC2086
99+
while read -r line; do
100+
if [ "${line}" = "-" ]; then
101+
BOOTFS=
102+
else
103+
BOOTFS="${line}"
104+
break
105+
fi
106+
done <<<"$( zpool list -H -o bootfs ${boot_pool} )"
107+
108+
if [ -n "${BOOTFS}" ]; then
109+
export BOOTFS
110+
echo "${BOOTFS}" > "${BASE}/bootfs"
111+
fi
112+
113+
: > "${BASE}/initialized"
114+
115+
# If BOOTFS is not empty display the fast boot menu
116+
if [ -n "${BOOTFS}" ]; then
117+
# Draw a countdown menu
118+
# shellcheck disable=SC2154
119+
if [ "${menu_timeout}" -gt 0 ]; then
120+
if delay="${menu_timeout}" prompt="Booting ${BOOTFS} in %0.2d seconds" timed_prompt "[ENTER] to boot" "[ESC] boot menu" ; then
121+
# Clear screen before a possible password prompt
122+
tput clear
123+
if ! key_wrapper "${BOOTFS}"; then
124+
emergency_shell "unable to load key for ${BOOTFS}; type 'exit' to continue"
125+
elif find_be_kernels "${BOOTFS}" && [ ! -e "${BASE}/active" ]; then
126+
# Automatically select a kernel and boot it
127+
kexec_kernel "$( select_kernel "${BOOTFS}" )"
128+
fi
129+
fi
130+
fi
131+
fi
132+
133+
while true; do
134+
if [ -x /bin/zfsbootmenu ]; then
135+
/bin/zfsbootmenu
136+
fi
137+
138+
emergency_shell "type 'exit' to return to ZFSBootMenu"
139+
done

90zfsbootmenu/zfsbootmenu-exec.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ export zbm_lines
99
export zbm_columns
1010

1111
# https://busybox.net/FAQ.html#job_control
12-
exec setsid bash -c "exec /bin/zfsbootmenu <${control_term} >${control_term} 2>&1"
12+
exec setsid bash -c "exec /libexec/zfsbootmenu-countdown <${control_term} >${control_term} 2>&1"

90zfsbootmenu/zfsbootmenu-lib.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ kexec_kernel() {
217217
mnt="$( mount_zfs "${fs}" )"
218218

219219
ret=$?
220-
if [ $ret != 0 ]; then
220+
if [ $ret -ne 0 ]; then
221221
emergency_shell "unable to mount ${fs}"
222222
return 1
223223
fi
@@ -227,7 +227,7 @@ kexec_kernel() {
227227

228228
# restore kernel log level just before we kexec
229229
# shellcheck disable=SC2154
230-
echo "${printk}" > /proc/sys/kernel/printk
230+
[ -n "${PRINTK}" ] && echo "${PRINTK}" > /proc/sys/kernel/printk
231231

232232
kexec -l "${mnt}${kernel}" \
233233
--initrd="${mnt}${initramfs}" \

90zfsbootmenu/zfsbootmenu.sh

Lines changed: 37 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,40 @@
11
#!/bin/bash
22
# vim: softtabstop=2 shiftwidth=2 expandtab
33

4-
# store current kernel log level
5-
read -r printk < /proc/sys/kernel/printk
6-
printk=${printk:0:1}
7-
8-
# Set it to 0
9-
echo 0 > /proc/sys/kernel/printk
10-
11-
# disable ctrl-c (SIGINT)
12-
trap '' SIGINT
4+
##
5+
# Look for BEs with kernels and present a selection menu
6+
##
137

148
# shellcheck disable=SC1091
159
test -f /lib/zfsbootmenu-lib.sh && source /lib/zfsbootmenu-lib.sh
1610
# shellcheck disable=SC1091
1711
test -f zfsbootmenu-lib.sh && source zfsbootmenu-lib.sh
1812

19-
echo "Loading boot menu ..."
20-
TERM=linux
21-
tput reset
13+
if [ -z "${BASE}" ]; then
14+
export BASE="/zfsbootmenu"
15+
fi
16+
17+
while [ ! -e "${BASE}/initialized" ]; do
18+
if ! delay=5 prompt="Press [ESC] to cancel" timed_prompt "Waiting for ZFSBootMenu initialization"; then
19+
tput cnorm
20+
tput clear
21+
exit
22+
fi
23+
done
24+
25+
while [ -e "${BASE}/active" ]; do
26+
if ! delay=5 prompt="Press [ESC] to cancel" timed_prompt "Waiting for other ZFSBootMenu instace to terminate"; then
27+
tput cnorm
28+
tput clear
29+
exit
30+
fi
31+
done
32+
33+
: > "${BASE}/active"
34+
35+
# shellcheck disable=SC2064
36+
trap "rm -f '${BASE}/active'" EXIT
37+
trap '' SIGINT
2238

2339
if command -v fzf >/dev/null 2>&1; then
2440
export FUZZYSEL=fzf
@@ -32,122 +48,20 @@ elif command -v sk >/dev/null 2>&1; then
3248
export PREVIEW_HEIGHT=3
3349
fi
3450

35-
BASE="$( mktemp -d /tmp/zfs.XXXX )"
36-
export BASE
37-
38-
modprobe zfs 2>/dev/null
39-
udevadm settle
40-
41-
# try to set console options for display and interaction
42-
# this is sometimes run as an initqueue hook, but cannot be guaranteed
43-
#shellcheck disable=SC2154
44-
test -x /lib/udev/console_init -a -c "${control_term}" \
45-
&& /lib/udev/console_init "${control_term##*/}" >/dev/null 2>&1
46-
47-
# set the console size, if indicated
48-
#shellcheck disable=SC2154
49-
if [ -n "$zbm_lines" ]; then
50-
stty rows "$zbm_lines"
51-
fi
52-
53-
#shellcheck disable=SC2154
54-
if [ -n "$zbm_columns" ]; then
55-
stty cols "$zbm_columns"
56-
fi
57-
58-
# Attempt to import all pools read-only
59-
read_write='' all_pools=yes import_pool
60-
61-
# Make sure at least one pool can be imported; if not,
62-
# drop to an emergency shell to allow the user to attempt recovery
63-
import_success=0
64-
while true; do
65-
while IFS=$'\t' read -r _pool _health; do
66-
[ -n "${_pool}" ] || continue
67-
68-
import_success=1
69-
if [ "${_health}" != "ONLINE" ]; then
70-
echo "${_pool}" >> "${BASE}/degraded"
71-
fi
72-
done <<<"$( zpool list -H -o name,health )"
73-
74-
if [ "${import_success}" -ne 1 ]; then
75-
emergency_shell "unable to successfully import a pool"
76-
else
77-
break
78-
fi
79-
done
80-
81-
# Prefer a specific pool when checking for a bootfs value
82-
# shellcheck disable=SC2154
83-
if [ "${root}" = "zfsbootmenu" ]; then
84-
boot_pool=
85-
else
86-
boot_pool="${root}"
87-
fi
88-
89-
# Make sure the preferred pool was imported
90-
if [ -n "${boot_pool}" ] && ! zpool list -H -o name "${boot_pool}" >/dev/null 2>&1; then
91-
emergency_shell "\nCannot import requested pool '${boot_pool}'\nType 'exit' to try booting anyway"
51+
# The menu will not work if a fuzzy menu isn't available
52+
if [ -z "${FUZZYSEL}" ]; then
53+
emergency_shell "no fuzzy menu available"
54+
exit
9255
fi
9356

94-
unsupported=0
95-
while IFS=$'\t' read -r _pool _property; do
96-
if [[ "${_property}" =~ "unsupported@" ]]; then
97-
if ! grep -q "${_pool}" "${BASE}/degraded" >/dev/null 2>&1 ; then
98-
echo "${_pool}" >> "${BASE}/degraded"
99-
fi
100-
unsupported=1
101-
fi
102-
done <<<"$( zpool get all -H -o name,property )"
103-
104-
if [ "${unsupported}" -ne 0 ]; then
105-
color=red timed_prompt "Unsupported features detected" "Upgrade ZFS modules in ZFSBootMenu with generate-zbm"
57+
if [ -r "${BASE}/bootfs" ]; then
58+
read -r BOOTFS < "${BASE}/bootfs"
59+
export BOOTFS
10660
fi
10761

108-
# Attempt to find the bootfs property
109-
# shellcheck disable=SC2086
110-
while read -r line; do
111-
if [ "${line}" = "-" ]; then
112-
BOOTFS=
113-
else
114-
BOOTFS="${line}"
115-
break
116-
fi
117-
done <<<"$( zpool list -H -o bootfs ${boot_pool} )"
118-
119-
# If BOOTFS is not empty display the fast boot menu
120-
if [[ -n "${BOOTFS}" ]]; then
121-
# Draw a countdown menu
122-
# shellcheck disable=SC2154
123-
if [[ ${menu_timeout} -gt 0 ]]; then
124-
if delay="${menu_timeout}" prompt="Booting ${BOOTFS} in %0.2d seconds" timed_prompt "[ENTER] to boot" "[ESC] boot menu" ; then
125-
# Clear screen before a possible password prompt
126-
tput clear
127-
if ! key_wrapper "${BOOTFS}" ; then
128-
emergency_shell "unable to load required key for ${BOOTFS}"
129-
elif find_be_kernels "${BOOTFS}" ; then
130-
# Automatically select a kernel and boot it
131-
kexec_kernel "$( select_kernel "${BOOTFS}" )"
132-
fi
133-
fi
134-
fi
135-
fi
136-
137-
##
138-
# No automatic boot has taken place
139-
# Look for BEs with kernels and present a selection menu
140-
##
141-
14262
# Clear screen before a possible password prompt
14363
tput clear
14464

145-
# The menu will not work if a fuzzy menu isn't available
146-
if [ -z "${FUZZYSEL}" ]; then
147-
emergency_shell "no fuzzy menu available"
148-
exit
149-
fi
150-
15165
BE_SELECTED=0
15266

15367
while true; do
@@ -230,6 +144,7 @@ while true; do
230144
;;
231145
"alt-d")
232146
set_default_env "${selected_be}"
147+
echo "${BOOTFS}" > "${BASE}/bootfs"
233148
;;
234149
"alt-s")
235150
selection="$( draw_snapshots "${selected_be}" )"
@@ -318,7 +233,7 @@ while true; do
318233
esac
319234
;;
320235
"alt-r")
321-
emergency_shell "alt-r invoked"
236+
break
322237
;;
323238
"alt-w")
324239
pool="${selected_be%%/*}"

0 commit comments

Comments
 (0)