@@ -87,10 +87,10 @@ verify_global_hashes() {
8787 valid_global_hash=' y'
8888 else
8989 if [ " $gui_menu " = " y" ]; then
90- CHANGED_FILES=$( grep -v ' OK$' /tmp/hash_output | cut -f1 -d ' :' )
9190 whiptail_error --title ' ERROR: Boot Hash Mismatch' \
9291 --msgbox " The following files failed the verification process:\n${CHANGED_FILES} \nExiting to a recovery shell" 0 80
9392 fi
93+ DEBUG " kexec-select-boot: hash mismatch in $TMP_HASH_FILE "
9494 DIE " $TMP_HASH_FILE : boot hash mismatch"
9595 fi
9696 # If user enables it, check root hashes before boot as well
@@ -139,40 +139,73 @@ get_menu_option() {
139139 if [ $num_options -eq 1 -a $first_menu = " y" ]; then
140140 option_index=1
141141 elif [ " $gui_menu " = " y" ]; then
142+ if [ ! -f /tmp/kexec_compat_shown ]; then
143+ NOTE " $( printf ' \033[0;32m[OK]\033[0m=compatible \033[1;33m[!]\033[0m=may fail after kexec (blank)=cannot verify' ) "
144+ touch /tmp/kexec_compat_shown
145+ fi
142146 MENU_OPTIONS=()
143147 n=0
148+ # Show kernel/initrd in menu as "[OK] name (params) [kernel | initrd]"
149+ # Log to debug.log so remote troubleshooting can see exact menu format.
150+ # Long store paths (NixOS) collapse to basename; short paths keep directory context
144151 while read option; do
145152 parse_option
146153 n=$( expr $n + 1)
147- MENU_OPTIONS+=(" $n " " $name " )
154+ local marker target optline
155+ marker=$( boot_marker)
156+ target=$( fmt_boot_target)
157+ if [ -n " $params " ]; then
158+ optline=" $name ($params ) $target "
159+ else
160+ optline=" $name $target "
161+ fi
162+ if [ -n " $marker " ]; then
163+ MENU_OPTIONS+=(" $n " " $marker $optline " )
164+ else
165+ MENU_OPTIONS+=(" $n " " $optline " )
166+ fi
167+ DEBUG " whiptail menu: [$n ] $marker $optline "
148168 done < $TMP_MENU_FILE
169+ MENU_OPTIONS+=(" b" " Select different ISO" )
149170
150171 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 \
172+ --menu " Choose the boot option [1-$n , a to abort, b to select different ISO ]:" 0 80 8 \
152173 -- " ${MENU_OPTIONS[@]} " \
153- 2> /tmp/whiptail || DIE " Aborting boot attempt "
174+ 2> /tmp/whiptail || option_index= " a "
154175
155176 option_index=$( cat /tmp/whiptail)
156177 else
178+ if [ ! -f /tmp/kexec_compat_shown ]; then
179+ NOTE " $( printf ' \033[0;32m[OK]\033[0m=compatible \033[1;33m[!]\033[0m=may fail after kexec (blank)=cannot verify' ) "
180+ touch /tmp/kexec_compat_shown
181+ fi
157182 STATUS " Select your boot option:"
158183 n=0
159184 while read option; do
160185 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} "
186+ n=$(( n + 1 ))
187+ local marker target optline
188+ marker=$( boot_marker)
189+ target=$( fmt_boot_target)
190+ if [ -n " $marker " ]; then
191+ optline=" $n . $marker $name ${params: +($params )} $target "
192+ else
193+ optline=" $n . $name ${params: +($params )} $target "
194+ fi
195+ printf ' %s\n' " $optline " > " ${HEADS_TTY:-/ dev/ stderr} "
196+ DEBUG " CLI menu: $optline "
169197 done < $TMP_MENU_FILE
170198
171- INPUT " Choose the boot option [1-$n , a to abort]:" -r option_index
199+ INPUT " Choose the boot option [1-$n , a to abort, b for different ISO]:" -r option_index
200+ fi
172201
173- if [ " $option_index " = " a" ]; then
174- DIE " Aborting boot attempt"
175- fi
202+ if [ " $option_index " = " a" ]; then
203+ STATUS " Boot aborted by user"
204+ exit 1
205+ fi
206+ if [ " $option_index " = " b" ]; then
207+ STATUS " Returning to ISO selection"
208+ exit 2
176209 fi
177210 first_menu=" n"
178211
@@ -181,40 +214,117 @@ get_menu_option() {
181214}
182215
183216confirm_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)
217+ # Show full kernel/initrd/params in the confirmation dialog.
218+ # Cancel/Esc returns to the menu (option_confirm="b") instead of aborting,
219+ # so users can change their selection without restarting the boot flow.
220+ # The full cmdline combines the entry's parsed params with the global ADD
221+ # params (injected by kexec-iso-init.sh for ISO boot).
222+ if [ " $gui_menu " = " y" ]; then
223+ default_text=" Make default"
224+ [[ " $CONFIG_TPM_NO_LUKS_DISK_UNLOCK " = " y" ]] && default_text=" ${default_text} and boot"
225+ whiptail_warning --title " Confirm boot details" \
226+ --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 \
227+ -- ' y' " Boot" ' d' " ${default_text} " ' b' " Back to menu" \
228+ 2> /tmp/whiptail && option_confirm=$( cat /tmp/whiptail) || option_confirm=" b"
193229 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
230+ STATUS " Confirm boot details for $name :"
231+ STATUS " Kernel: $kernel "
232+ STATUS " Initramfs: ${initrd:- -} "
233+ STATUS " Options: ${params:- -} "
234+ [ -n " $CONFIG_BOOT_KERNEL_ADD " ] && STATUS " Board adds: $CONFIG_BOOT_KERNEL_ADD "
235+ [ -n " $CONFIG_BOOT_KERNEL_REMOVE " ] && STATUS " Board removes: $CONFIG_BOOT_KERNEL_REMOVE "
236+ [ -n " $add " ] && STATUS " ISO params: $add "
237+ local final=" $params "
238+ for rem in $CONFIG_BOOT_KERNEL_REMOVE ; do final=$( echo " $final " | sed " s/ $rem / /g; s/^$rem //; s/ $rem $//" ) ; done
239+ final=" $final $CONFIG_BOOT_KERNEL_ADD $add "
240+ STATUS " Kernel cmdline: $( echo " $final " | xargs) "
241+ INPUT " Boot (Y), make default (d), back to menu (b) [Y/d/b]:" -n 1 option_confirm
242+ [ -z " $option_confirm " ] && option_confirm=" y"
243+ return 0
198244 fi
199245}
200246
201247parse_option () {
248+ # Parse pipe-delimited boot entry: name|kexectype|kernel /path|initrd /path|append params
249+ # Field 4 can be either "initrd /path" or "append ..." when no initrd is present.
202250 name=$( echo $option | cut -d\| -f1)
203- kernel=$( echo $option | cut -d\| -f3)
251+ kernel=$( echo $option | cut -d\| -f3 | sed ' s/^kernel //' )
252+ initrd=" " ; params=" "
253+ f4=$( echo $option | cut -d\| -f4)
254+ case " $f4 " in
255+ initrd* ) initrd=" ${f4# initrd } " ; params=$( echo $option | cut -d\| -f5 | sed ' s/append //' | xargs) ;;
256+ append* ) params=$( echo " $f4 " | sed ' s/^append //' | xargs) ;;
257+ * ) ;;
258+ esac
259+ LOG " parse_option: name='$name ' kernel='$kernel ' initrd='$initrd ' params='${params: 0: 80} ...'"
260+ }
261+
262+ # Return the initrd compat marker for the current entry's initrd.
263+ # Three possible states:
264+ # [OK] — initrd has the USB fs module as .ko or in modules.builtin
265+ # [!] — initrd has loadable modules but none for the USB fs type
266+ # "" — initrd has zero .ko files (can't verify — assume OK)
267+ #
268+ # The $initrd global is set by parse_option() for each menu entry before
269+ # this function is called, so each entry independently looks up its own
270+ # initrd in the compat file.
271+ #
272+ # Compat file format (written by kexec-iso-init.sh Layer 1):
273+ # initrd/relative/path [OK]
274+ # other/initrd/path [!]
275+ # (absent entries = zero modules, can't verify)
276+ #
277+ # Each line maps one initrd to its USB-filesystem compat status.
278+ # boot_marker() greps for the current entry's initrd path and returns
279+ # that initrd's marker — entries using different initrds show different
280+ # markers even on the same ISO.
281+ # In CLI mode adds ANSI colors: green [OK], yellow [!].
282+ boot_marker () {
283+ local m=" " grn=" " ylw=" " rst=" "
284+ [ " $gui_menu " != " y" ] && { grn=$' \033 [0;32m' ; ylw=$' \033 [1;33m' ; rst=$' \033 [0m' ; }
285+ if [ -n " $initrd " ] && [ -r " /tmp/kexec_initrd_compat.txt" ]; then
286+ local ip=$( echo " $initrd " | sed ' s|^/*||' )
287+ m=$( grep " ^$ip " /tmp/kexec_initrd_compat.txt 2> /dev/null | head -1 | cut -d' ' -f2)
288+ [ -n " $m " ] && LOG " boot_marker: initrd=$ip marker=$m " || LOG " boot_marker: initrd=$ip no compat entry"
289+ [ " $m " = " [OK]" ] && m=" ${grn} [OK]${rst} "
290+ [ " $m " = " [!]" ] && m=" ${ylw} [!]${rst} "
291+ fi
292+ echo " $m "
293+ }
294+
295+ # Format kernel/initrd for menu display: "[path | path]"
296+ # Keeps directory context for short paths (live/vmlinuz) but falls back to
297+ # basename for unreasonably long store paths (NixOS /nix/store/.../bzImage).
298+ # 35-char threshold: typical paths like "boot/x86_64/loader/linux" fit;
299+ # NixOS store paths with hashes exceed it.
300+ fmt_boot_target () {
301+ local k i
302+ k=$( echo " $kernel " | sed ' s|^/*||' )
303+ [ -z " $k " ] && k=" $kernel "
304+ [ " ${# k} " -gt 35 ] && k=$( basename " $k " )
305+ i=$( echo " $initrd " | sed ' s|^/*||' )
306+ [ " ${# i} " -gt 35 ] && i=$( basename " $i " )
307+ if [ -n " $i " ]; then echo " [$k | $i ]" ; else echo " [$k ]" ; fi
204308}
205309
206310scan_options () {
207- STATUS " Scanning for boot options"
311+ STATUS " Scanning for unsigned boot options"
208312 option_file=" /tmp/kexec_options.txt"
209313 scan_boot_options " $bootdir " " $config " " $option_file "
210314 if [ ! -s $option_file ]; then
211315 DIE " Failed to parse any boot options"
212316 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
317+ # Sort entries by name so users can scan the menu alphabetically.
318+ # When -u (unique) is set, strip --- markers from append params first
319+ # so entries differing only by GRUB's bootloader separator get deduped.
320+ if [ " $unique " = ' y' ]; then
321+ sed ' s/|append \([^|]*\)---[^|]*/|append \1/g' " $option_file " | sort -t\| -k1 -u > " $TMP_MENU_FILE "
322+ else
323+ sort -t\| -k1 " $option_file " > " $TMP_MENU_FILE "
324+ fi
325+ DEBUG " kexec-select-boot: parsed boot options for user selection"
326+ # Option entries are already logged as echo_entry by kexec-parse-boot.sh;
327+ # no need to dump them again here.
218328}
219329
220330save_default_option () {
0 commit comments