failsafe: run on all consoles listed in /proc/cmdline

On x86, when both CONFIG_GRUB_CONSOLE and CONFIG_GRUB_SERIAL are set (as
they are by default), the kernel command line will have two console=
entries, such as

    console=tty0 console=ttyS0,115200n8

Failsafe was only running a shell on the first defined console, the VGA
console. This is a problem for devices like apu2, where there is only a
serial console and it appears on ttyS0.

Moreover, the console prompt to enter failsafe during boot was delivered
to, and its input read from, the last console= on the kernel command
line. So while the failsafe shell was on the first defined console, only
the last defined console could be used to enter failsafe during boot.

In contrast, the x86 bootloader (GRUB) operates on both the serial
console and the VGA console by virtue of "terminal_{input,output}
console serial". GRUB also provided an alternate means to enter failsafe
from either console. The presence of two console= kernel command line
parameters causes kernel messages to be delivered to both. Under normal
operation (not failsafe), procd runs login in accordance with inittab,
which on x86 specifies ttyS0, hvc0, and tty1, allowing login through any
of serial, hypervisor, or VGA console. Thus, serial access was
consistently available on x86 devices with serial consoles under normal
operation, except for shell access in failsafe mode (without editing the
kernel command line).

By presenting the failsafe prompt, reading failsafe prompt input, and
running failsafe shells on all consoles listed in /proc/cmdline,
failsafe mode will work correctly on devices with a serial console (like
apu2), and the same image without any need for reconfiguration can be
shared by devices with the more traditional (for x86) VGA console. This
improvement should benefit any system with multiple console= arguments,
including x86 and bcm27xx (Raspberry Pi).

Signed-off-by: Mark Mentovai <mark at moxienet.com>
This commit is contained in:
Mark Mentovai 2022-06-06 00:59:14 -04:00 committed by coolsnowwolf
parent 75663fdd70
commit a4c100df52
2 changed files with 40 additions and 35 deletions

View File

@ -40,35 +40,39 @@ fs_wait_for_key () {
rm -f $keypress_wait rm -f $keypress_wait
} & } &
[ "$pi_preinit_no_failsafe" != "y" ] && echo "Press the [$1] key and hit [enter] $2" local consoles="$(sed -e 's/ /\n/g' /proc/cmdline | grep '^console=' | sed -e 's/^console=//' -e 's/,.*//')"
echo "Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level" [ -n "$consoles" ] || consoles=console
# if we're on the console we wait for input for console in $consoles; do
{ [ -c "/dev/$console" ] || continue
while [ -r $keypress_wait ]; do [ "$pi_preinit_no_failsafe" != "y" ] && echo "Press the [$1] key and hit [enter] $2" > "/dev/$console"
timer="$(cat $keypress_sec)" echo "Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level" > "/dev/$console"
{
while [ -r $keypress_wait ]; do
timer="$(cat $keypress_sec)"
[ -n "$timer" ] || timer=1 [ -n "$timer" ] || timer=1
timer="${timer%%\ *}" timer="${timer%%\ *}"
[ $timer -ge 1 ] || timer=1 [ $timer -ge 1 ] || timer=1
do_keypress="" do_keypress=""
{ {
read -t "$timer" do_keypress read -t "$timer" do_keypress < "/dev/$console"
case "$do_keypress" in case "$do_keypress" in
$1) $1)
echo "true" >$keypress_true echo "true" >$keypress_true
;; ;;
1 | 2 | 3 | 4) 1 | 2 | 3 | 4)
echo "$do_keypress" >/tmp/debug_level echo "$do_keypress" >/tmp/debug_level
;; ;;
*) *)
continue; continue;
;; ;;
esac esac
lock -u $keypress_wait lock -u $keypress_wait
rm -f $keypress_wait rm -f $keypress_wait
} }
done done
} } &
done
lock -w $keypress_wait lock -w $keypress_wait
keypressed=1 keypressed=1

View File

@ -2,13 +2,14 @@
# Copyright (C) 2010 Vertical Communications # Copyright (C) 2010 Vertical Communications
failsafe_shell() { failsafe_shell() {
local console="$(sed -e 's/ /\n/g' /proc/cmdline | grep '^console=' | head -1 | sed -e 's/^console=//' -e 's/,.*//')" local consoles="$(sed -e 's/ /\n/g' /proc/cmdline | grep '^console=' | sed -e 's/^console=//' -e 's/,.*//')"
[ -n "$console" ] || console=console [ -n "$consoles" ] || consoles=console
[ -c "/dev/$console" ] || return 0 for console in $consoles; do
while true; do [ -c "/dev/$console" ] && while true; do
ash --login <"/dev/$console" >"/dev/$console" 2>"/dev/$console" ash --login <"/dev/$console" >"/dev/$console" 2>"/dev/$console"
sleep 1 sleep 1
done & done &
done
} }
boot_hook_add failsafe failsafe_shell boot_hook_add failsafe failsafe_shell