@@ -59,7 +59,7 @@ paramsdev="${paramsdev%%/}"
5959paramsdir=" ${paramsdir%%/ } "
6060
6161PRIMHASH_FILE=" $paramsdir /kexec_primhdl_hash.txt"
62- if [ " $CONFIG_TPM2_TOOLS " = " y" ]; then
62+ if [ " $CONFIG_TPM2_TOOLS " = " y" ] && [ " $valid_rollback " != " y " ] ; then
6363 if [ -s " $PRIMHASH_FILE " ]; then
6464 # PRIMHASH_FILE (normally /boot/kexec_primhdl_hash.txt) exists and is not empty
6565 sha256sum -c " $PRIMHASH_FILE " > /dev/null 2>&1 ||
@@ -91,6 +91,7 @@ verify_global_hashes() {
9191 whiptail_error --title ' ERROR: Boot Hash Mismatch' \
9292 --msgbox " The following files failed the verification process:\n${CHANGED_FILES} \nExiting to a recovery shell" 0 80
9393 fi
94+ DEBUG " kexec-select-boot: hash mismatch in $TMP_HASH_FILE "
9495 DIE " $TMP_HASH_FILE : boot hash mismatch"
9596 fi
9697 # If user enables it, check root hashes before boot as well
@@ -139,82 +140,230 @@ get_menu_option() {
139140 if [ $num_options -eq 1 -a $first_menu = " y" ]; then
140141 option_index=1
141142 elif [ " $gui_menu " = " y" ]; then
143+ if [ ! -f /tmp/kexec_compat_shown ] && [ -f /tmp/kexec_initrd_compat.txt ]; then
144+ NOTE " $( printf ' \033[0;32m[OK]\033[0m=compatible \033[1;33m[!]\033[0m=may fail after kexec (blank)=cannot verify' ) "
145+ touch /tmp/kexec_compat_shown
146+ fi
142147 MENU_OPTIONS=()
143148 n=0
149+ # Show kernel/initrd in menu as "[OK] name (params) [kernel | initrd]"
150+ # Log to debug.log so remote troubleshooting can see exact menu format.
151+ # Long store paths (NixOS) collapse to basename; short paths keep directory context
144152 while read option; do
145153 parse_option
146154 n=$( expr $n + 1)
147- MENU_OPTIONS+=(" $n " " $name " )
155+ local marker target display_params optline
156+ marker=$( boot_marker)
157+ target=$( fmt_boot_target)
158+ display_params=$( fmt_display_params " $params " )
159+ if [ -n " $display_params " ]; then
160+ optline=" $name ($display_params ) $target "
161+ else
162+ optline=" $name $target "
163+ fi
164+ if [ -n " $marker " ]; then
165+ MENU_OPTIONS+=(" $n " " $marker $optline " )
166+ else
167+ MENU_OPTIONS+=(" $n " " $optline " )
168+ fi
169+ DEBUG " whiptail menu: [$n ] $marker $optline "
148170 done < $TMP_MENU_FILE
171+ if [ -n " $add " ]; then
172+ MENU_OPTIONS+=(" b" " Select different ISO" )
173+ fi
149174
175+ if [ -n " $add " ]; then
176+ local menu_prompt=" Choose the boot option [1-$n , a to abort, b to select different ISO]:"
177+ else
178+ local menu_prompt=" Choose the boot option [1-$n , a to abort]:"
179+ fi
150180 whiptail_type $BG_COLOR_MAIN_MENU --title " Select your boot option" \
151- --menu " Choose the boot option [1- $n , a to abort]: " 0 80 8 \
181+ --menu " $menu_prompt " 0 80 8 \
152182 -- " ${MENU_OPTIONS[@]} " \
153- 2> /tmp/whiptail || DIE " Aborting boot attempt "
183+ 2> /tmp/whiptail || option_index= " a "
154184
155185 option_index=$( cat /tmp/whiptail)
156186 else
187+ if [ ! -f /tmp/kexec_compat_shown ] && [ -f /tmp/kexec_initrd_compat.txt ]; then
188+ NOTE " $( printf ' \033[0;32m[OK]\033[0m=compatible \033[1;33m[!]\033[0m=may fail after kexec (blank)=cannot verify' ) "
189+ touch /tmp/kexec_compat_shown
190+ fi
157191 STATUS " Select your boot option:"
158192 n=0
159193 while read option; do
160194 parse_option
161- n=$( expr $n + 1)
162- # Use the same device routing as INPUT so option lines and the
163- # prompt share the same unbuffered fd (HEADS_TTY when in gui-init
164- # context, stderr otherwise). Writing to stdout is wrong here
165- # because DO_WITH_DEBUG pipes stdout through tee for debug logging,
166- # making it fully buffered — the last option would appear after the
167- # INPUT prompt.
168- printf ' %d. %s [%s]\n' " $n " " $name " " $kernel " > " ${HEADS_TTY:-/ dev/ stderr} "
195+ n=$(( n + 1 ))
196+ local marker target display_params optline
197+ marker=$( boot_marker)
198+ target=$( fmt_boot_target)
199+ display_params=$( fmt_display_params " $params " )
200+ if [ -n " $marker " ]; then
201+ optline=" $n . $marker $name ${display_params: +($display_params )} $target "
202+ else
203+ optline=" $n . $name ${display_params: +($display_params )} $target "
204+ fi
205+ printf ' %s\n' " $optline " > " ${HEADS_TTY:-/ dev/ stderr} "
206+ DEBUG " CLI menu: $optline "
169207 done < $TMP_MENU_FILE
170208
171- INPUT " Choose the boot option [1- $n , a to abort]: " -r option_index
172-
173- if [ " $option_index " = " a " ] ; then
174- DIE " Aborting boot attempt "
209+ if [ -n " $add " ] ; then
210+ INPUT " Choose the boot option [1- $n , a to abort, b for different ISO]: " -r option_index
211+ else
212+ INPUT " Choose the boot option [1- $n , a to abort]: " -r option_index
175213 fi
176214 fi
215+
216+ if [ " $option_index " = " a" ]; then
217+ STATUS " Boot aborted by user"
218+ exit 1
219+ fi
220+ if [ " $option_index " = " b" ] && [ -n " $add " ]; then
221+ STATUS " Returning to ISO selection"
222+ exit 2
223+ fi
177224 first_menu=" n"
178225
179226 option=$( head -n $option_index $TMP_MENU_FILE | tail -1)
180227 parse_option
181228}
182229
183230confirm_menu_option () {
184- if [ " $gui_menu " = " y" ]; then
185- default_text=" Make default"
186- [[ " $CONFIG_TPM_NO_LUKS_DISK_UNLOCK " = " y" ]] && default_text=" ${default_text} and boot"
187- whiptail_warning --title " Confirm boot details" \
188- --menu " Confirm the boot details for $name :\n\n$( echo $kernel | fold -s -w 80) \n\n" 0 80 8 \
189- -- ' d' " ${default_text} " ' y' " Boot one time" \
190- 2> /tmp/whiptail || DIE " Aborting boot attempt"
191-
192- option_confirm=$( cat /tmp/whiptail)
231+ # Show full kernel/initrd/params in the confirmation dialog.
232+ # Cancel/Esc returns to the menu (option_confirm="b") instead of aborting,
233+ # so users can change their selection without restarting the boot flow.
234+ # The full cmdline combines the entry's parsed params with the global ADD
235+ # params (injected by kexec-iso-init.sh for ISO boot).
236+ if [ " $gui_menu " = " y" ]; then
237+ default_text=" Make default"
238+ [[ " $CONFIG_TPM_NO_LUKS_DISK_UNLOCK " = " y" ]] && default_text=" ${default_text} and boot"
239+ whiptail_warning --title " Confirm boot details" \
240+ --menu " $name \n\nKernel: $kernel \nInitramfs: ${initrd:- -} \nOptions: ${params:- -} \n${CONFIG_BOOT_KERNEL_ADD: +Board adds: $CONFIG_BOOT_KERNEL_ADD \n }${CONFIG_BOOT_KERNEL_REMOVE: +Board removes: $CONFIG_BOOT_KERNEL_REMOVE \n }${add: +ISO params: $add \n } Kernel cmdline: $( echo " $params $CONFIG_BOOT_KERNEL_ADD $add " | xargs) \n" 0 80 8 \
241+ -- ' y' " Boot" ' d' " ${default_text} " ' b' " Back to menu" \
242+ 2> /tmp/whiptail && option_confirm=$( cat /tmp/whiptail) || option_confirm=" b"
193243 else
194- STATUS " Confirm boot details for $name :"
195- INFO " $option "
196-
197- INPUT " Confirm selection by pressing 'y', make default with 'd':" -n 1 option_confirm
244+ STATUS " Confirm boot details for $name :"
245+ STATUS " Kernel: $kernel "
246+ STATUS " Initramfs: ${initrd:- -} "
247+ STATUS " Options: ${params:- -} "
248+ [ -n " $CONFIG_BOOT_KERNEL_ADD " ] && STATUS " Board adds: $CONFIG_BOOT_KERNEL_ADD "
249+ [ -n " $CONFIG_BOOT_KERNEL_REMOVE " ] && STATUS " Board removes: $CONFIG_BOOT_KERNEL_REMOVE "
250+ [ -n " $add " ] && STATUS " ISO params: $add "
251+ local final=" $params "
252+ for rem in $CONFIG_BOOT_KERNEL_REMOVE ; do
253+ final=" $final "
254+ final=" ${final// $rem / } "
255+ final=" ${final# } "
256+ final=" ${final% } "
257+ done
258+ final=" $final $CONFIG_BOOT_KERNEL_ADD $add "
259+ STATUS " Kernel cmdline: $( echo " $final " | xargs) "
260+ INPUT " Boot (Y), make default (d), back to menu (b) [Y/d/b]:" -n 1 option_confirm
261+ [ -z " $option_confirm " ] && option_confirm=" y"
262+ return 0
198263 fi
199264}
200265
201266parse_option () {
267+ # Parse pipe-delimited boot entry: name|kexectype|kernel /path|initrd /path|append params
268+ # Field 4 can be either "initrd /path" or "append ..." when no initrd is present.
202269 name=$( echo $option | cut -d\| -f1)
203- kernel=$( echo $option | cut -d\| -f3)
270+ kernel=$( echo $option | cut -d\| -f3 | sed ' s/^kernel //' )
271+ initrd=" " ; params=" "
272+ f4=$( echo $option | cut -d\| -f4)
273+ case " $f4 " in
274+ initrd* ) initrd=" ${f4# initrd } " ; params=$( echo $option | cut -d\| -f5 | sed ' s/append //' | xargs) ;;
275+ append* ) params=$( echo " $f4 " | sed ' s/^append //' | xargs) ;;
276+ * ) ;;
277+ esac
278+ LOG " parse_option: name='$name ' kernel='$kernel ' initrd='$initrd ' params='${params: 0: 80} ...'"
279+ }
280+
281+ # Return the initrd compat marker for the current entry's initrd.
282+ # Three possible states:
283+ # [OK] — initrd has the USB fs module as .ko or in modules.builtin
284+ # [!] — initrd has loadable modules but none for the USB fs type
285+ # "" — initrd has zero .ko files (can't verify — assume OK)
286+ #
287+ # The $initrd global is set by parse_option() for each menu entry before
288+ # this function is called, so each entry independently looks up its own
289+ # initrd in the compat file.
290+ #
291+ # Compat file format (written by kexec-iso-init.sh Layer 1):
292+ # initrd/relative/path [OK]
293+ # other/initrd/path [!]
294+ # (absent entries = zero modules, can't verify)
295+ #
296+ # Each line maps one initrd to its USB-filesystem compat status.
297+ # boot_marker() greps for the current entry's initrd path and returns
298+ # that initrd's marker — entries using different initrds show different
299+ # markers even on the same ISO.
300+ # In CLI mode adds ANSI colors: green [OK], yellow [!].
301+ boot_marker () {
302+ local m=" " grn=" " ylw=" " rst=" "
303+ [ " $gui_menu " != " y" ] && { grn=$' \033 [0;32m' ; ylw=$' \033 [1;33m' ; rst=$' \033 [0m' ; }
304+ if [ -n " $initrd " ] && [ -r " /tmp/kexec_initrd_compat.txt" ]; then
305+ local ip=$( echo " $initrd " | sed ' s|^/*||' )
306+ m=$( grep " ^$ip " /tmp/kexec_initrd_compat.txt 2> /dev/null | head -1 | cut -d' ' -f2)
307+ [ -n " $m " ] && LOG " boot_marker: initrd=$ip marker=$m " || LOG " boot_marker: initrd=$ip no compat entry"
308+ [ " $m " = " [OK]" ] && m=" ${grn} [OK]${rst} "
309+ [ " $m " = " [!]" ] && m=" ${ylw} [!]${rst} "
310+ fi
311+ echo " $m "
312+ }
313+
314+ # Strip ISO-finding boot parameters for display only.
315+ # The full params remain in the entry passed to kexec-boot.sh.
316+ # These params are injected by kexec-iso-init.sh via -a and would
317+ # clutter the menu if shown redundantly. Only affects menu display.
318+ fmt_display_params () {
319+ local dp=" $1 "
320+ [ -z " $dp " ] && echo " " && return
321+ echo " $dp " | sed \
322+ -e ' s|iso-scan/filename=[^ ]*| |g' \
323+ -e ' s|findiso=[^ ]*| |g' \
324+ -e ' s|fromiso=[^ ]*| |g' \
325+ -e ' s|img_dev=[^ ]*| |g' \
326+ -e ' s|img_loop=[^ ]*| |g' \
327+ -e ' s|iso=[^ ]*| |g' \
328+ -e ' s|live-media=[^ ]*| |g' \
329+ -e ' s| *| |g' \
330+ -e ' s|^ ||' \
331+ -e ' s| $||' | xargs
332+ }
333+
334+ # Format kernel/initrd for menu display: "[path | path]"
335+ # Keeps directory context for short paths (live/vmlinuz) but falls back to
336+ # basename for unreasonably long store paths (NixOS /nix/store/.../bzImage).
337+ # 35-char threshold: typical paths like "boot/x86_64/loader/linux" fit;
338+ # NixOS store paths with hashes exceed it.
339+ fmt_boot_target () {
340+ local k i
341+ k=$( echo " $kernel " | sed ' s|^/*||' )
342+ [ -z " $k " ] && k=" $kernel "
343+ [ " ${# k} " -gt 35 ] && k=$( basename " $k " )
344+ i=$( echo " $initrd " | sed ' s|^/*||' )
345+ [ " ${# i} " -gt 35 ] && i=$( basename " $i " )
346+ if [ -n " $i " ]; then echo " [$k | $i ]" ; else echo " [$k ]" ; fi
204347}
205348
206349scan_options () {
207- STATUS " Scanning for boot options"
350+ STATUS " Scanning for unsigned boot options"
208351 option_file=" /tmp/kexec_options.txt"
209352 scan_boot_options " $bootdir " " $config " " $option_file "
210353 if [ ! -s $option_file ]; then
211354 DIE " Failed to parse any boot options"
212355 fi
213- if [ " $unique " = ' y' ]; then
214- sort -r $option_file | uniq > $TMP_MENU_FILE
215- else
216- cp $option_file $TMP_MENU_FILE
217- fi
356+ # Sort entries by name so users can scan the menu alphabetically.
357+ # When -u (unique) is set, strip --- markers from append params first
358+ # so entries differing only by GRUB's bootloader separator get deduped.
359+ if [ " $unique " = ' y' ]; then
360+ sed ' s/|append \([^|]*\)---[^|]*/|append \1/g' " $option_file " | awk -F' |' ' !seen[$1]++' > " $TMP_MENU_FILE "
361+ else
362+ cp " $option_file " " $TMP_MENU_FILE "
363+ fi
364+ DEBUG " kexec-select-boot: parsed boot options for user selection"
365+ # Option entries are already logged as echo_entry by kexec-parse-boot.sh;
366+ # no need to dump them again here.
218367}
219368
220369save_default_option () {
0 commit comments