Skip to content

Commit 1526bb8

Browse files
committed
zfsbootmenu-core: improve kernel searches
- Remove obsolete default_kernel file - Avoid reversing kernels list in select_kernel - Avoid `ls` hack to find kernels in boot environment - Make initramfs/kernel pairing agnostic of actual kernel path
1 parent 955ac2f commit 1526bb8

File tree

1 file changed

+47
-48
lines changed

1 file changed

+47
-48
lines changed

zfsbootmenu/lib/zfsbootmenu-core.sh

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -629,8 +629,9 @@ set_default_kernel() {
629629
set_rw_pool "${pool}" || return 1
630630
CLEAR_SCREEN=1 load_key "${fs}"
631631

632-
# Strip /boot/ to list only the file
633-
kernel="${2#/boot/}"
632+
# Strip leading /boot/ or / to list only the file
633+
kernel="${2#/}"
634+
kernel="${kernel#boot/}"
634635

635636
# Restore nonspecific default when no kernel specified
636637
if [ -z "$kernel" ]; then
@@ -682,8 +683,7 @@ set_default_env() {
682683

683684
find_be_kernels() {
684685
local fs mnt
685-
local kernel kernel_base labels version kernel_records
686-
local defaults def_kernel def_kernel_file
686+
local kpath kdir kernel kernel_base labels version kernel_records
687687

688688
fs="${1}"
689689
if [ -z "${fs}" ]; then
@@ -698,76 +698,71 @@ find_be_kernels() {
698698
return 1
699699
fi
700700

701-
# Check if /boot even exists in the environment
702-
if [ ! -d "${mnt}/boot" ]; then
703-
zdebug "${mnt}/boot not present"
704-
umount "${mnt}"
705-
return 1
706-
fi
707-
708701
# Make sure the kernel list starts fresh
709-
kernel_records="${mnt/mnt/kernels}"
702+
kernel_records="${mnt%/*}/kernels"
710703
: > "${kernel_records}"
711704

712-
# shellcheck disable=SC2012,2086
713-
for kernel in $( ls \
714-
${mnt}/boot/{{vm,}linu{x,z},kernel}{,-*} 2>/dev/null | sort -V ); do
715-
# Pull basename and validate
716-
kernel="${kernel##*/}"
717-
[ -e "${mnt}/boot/${kernel}" ] || continue
718-
zdebug "found ${mnt}/boot/${kernel}"
705+
# Look for kernels in / and /boot, sorted in version order
706+
while read -r kpath; do
707+
# Strip mount point from path
708+
kpath="${kpath#"${mnt}"}"
709+
# Ensure kpath has leading slash
710+
kpath="/${kpath#/}"
711+
zdebug "found kernel: ${mnt}${kpath}"
712+
713+
# Extract base name and kernel directory
714+
kernel="${kpath##*/}"
715+
kdir="${kpath%"${kernel}"}"
716+
# Trim trailing slash (note: kdir will be empty if kernel is at root)
717+
kdir="${kdir%/}"
718+
zdebug "kernel directory: '${kdir}', file: '${kernel}'"
719719

720720
# Kernel "base" extends to first hyphen
721721
kernel_base="${kernel%%-*}"
722+
722723
# Kernel "version" is everything after base and may be empty
723724
version="${kernel#"${kernel_base}"}"
724725
version="${version#-}"
725-
zdebug "kernel version: ${version}"
726+
zdebug "kernel base: '${kernel_base}', version: '${version}'"
726727

727728
# initramfs images can take many forms, look for a sensible one
728729
labels=( "$kernel" )
729730
if [ -n "$version" ]; then
730731
labels+=( "$version" )
731732
fi
732733

733-
local ext pfx lbl i
734734
# Use a mess of loops instead better brace expansions to control priorities
735+
local ext pfx lbl i ipath
735736
for ext in {.img,""}{"",.{gz,bz2,xz,lzma,lz4,lzo,zstd}}; do
736737
for pfx in initramfs initrd; do
737738
for lbl in "${labels[@]}"; do
738739
for i in "${pfx}-${lbl}${ext}" "${pfx}${ext}-${lbl}"; do
739-
if [ -e "${mnt}/boot/${i}" ]; then
740-
zdebug "matching ${i} to ${kernel}"
741-
echo "${fs} /boot/${kernel} /boot/${i}" >> "${kernel_records}"
742-
break 4
743-
fi
740+
ipath="${kdir}/${i}"
741+
[ -e "${mnt}${ipath}" ] || continue
742+
zdebug "matching '${i}' to '${kernel}'"
743+
echo "${fs} ${kpath} ${ipath}" >> "${kernel_records}"
744+
break 4
744745
done
745746
done
746747
done
747748
done
748-
done
749+
750+
done <<<"$(
751+
for k in "${mnt}/boot"/{{vm,}linu{x,z},kernel}{,-*}; do
752+
[ -e "${k}" ] && echo "${k}"
753+
done | sort -V
754+
)"
749755

750756
# No further need for the mount
751757
umount "${mnt}"
752758

753-
defaults="$( select_kernel "${fs}" )"
754-
755-
# shellcheck disable=SC2034
756-
IFS=' ' read -r def_fs def_kernel def_initramfs <<<"${defaults}"
759+
# Search was successful if at least one kernel can be selected
760+
[ -s "${kernel_records}" ] && select_kernel "${fs}" >/dev/null && return 0
757761

758-
def_kernel_file="${mnt/mnt/default_kernel}"
759-
760-
# If no default kernel is found, there are no kernels; leave the BE
761-
# directory in the same state it would be in had no /boot existed
762-
if [ -z "${def_kernel}" ]; then
763-
zdebug "no default kernel found for ${fs}"
764-
rm -f "${kernel_records}" "${def_kernel_file}"
765-
return 1
766-
fi
767-
768-
zdebug "default kernel set to ${def_kernel}"
769-
echo "${def_kernel##*/}" > "${def_kernel_file}"
770-
return 0
762+
# Remove an invalid kernel record if the search failed
763+
zerror "failed to find kernels on ${fs}"
764+
rm -f "${kernel_records}"
765+
return 1
771766
}
772767

773768
# arg1: ZFS filesystem
@@ -786,8 +781,8 @@ select_kernel() {
786781

787782
kernel_list="$( be_location "${zfsbe}" )/kernels"
788783

789-
if [ ! -f "${kernel_list}" ]; then
790-
zerror "kernel list '${kernel_list}' missing"
784+
if [ ! -s "${kernel_list}" ]; then
785+
zerror "kernel list '${kernel_list}' missing or empty"
791786
return 1
792787
fi
793788

@@ -804,9 +799,13 @@ select_kernel() {
804799
if [[ "${kernel}" =~ ${specific_kernel} ]]; then
805800
zdebug "matched ${kernel} to ${specific_kernel}"
806801
kexec_args="${spec_kexec_args}"
807-
break
808802
fi
809-
done <<<"$( tac "${kernel_list}" )"
803+
done < "${kernel_list}"
804+
fi
805+
806+
if [ -z "${kexec_args}" ]; then
807+
zerror "failed to identify kexec arguments for ${fs}"
808+
return 1
810809
fi
811810

812811
zdebug "using kexec args: ${kexec_args}"

0 commit comments

Comments
 (0)