mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2024-11-27 23:34:30 +00:00
1310e4f1ae
When running a failsafe shell on a console, job control was unavailable, and ^C did not function correctly. This change invokes console failsafe shells via `setsid`, making them session leaders and allowing them to claim controlling terminals, which makes job control function properly. To support this, the busybox `setsid` utility is enabled. This has a minimal 149-byte size impact on a test x86_64 squashfs rootfs image. ^C was ignored in subprocesses of failsafe shells: it was not possible to ^C out of a program that would not exit on its own, such as many typical `ping` invocations. As job control was unavailable, it was not possible to suspend these subprocesses either, causing a hung program to tie up a console indefinitely, unless another means to signal the program was available. This was caused by SIGINT being placed at disposition SIG_IGN by the shell running preinit, which it did because the console shell was executed asynchronously with &. That disposition was inherited by the console shell and its subprocesses, generally causing ^C to have no effect. As there is no way in busybox `ash` to reset the disposition of a signal already ignored at shell entry, and no apparent way to avoid SIGINT being placed at SIG_IGN when & is used in preinit, an alternative construct is needed. Now, `start-stop-daemon` is used to start (-S) the console failsafe shell in the background (-b). This approach does not alter SIGINT, allowing the console shell to be started with that signal's handling intact, and normal ^C processing to occur. busybox `ash` has some behaviors conditional on SHLVL, and while the console shells ought to run at SHLVL=1, they were not by virtue of being started by the shell-based preinit system. Additionally, a variety of detritus was present in the console shell's environment, carried over from preinit. These conditions are corrected by running the console shell via `env -i` to clear the environment and establish a minimum and correct set of environment variables for operation, in the same manner as `login`. HOME is not explicitly set, because it's addressed in /etc/profile. For non-failsafe console shells when system.@system[0].ttylogin = 0, `login -f root` achieves a similar effect. (`login` already started non-failsafe console shells when ttylogin = 1 and behaved correctly. This brings the ttylogin = 0 case to parity.) Note that even `login -f` is somewhat undesirable for failsafe shells because it requires a viable /etc/passwd, hence the `env -i` construct in that case. The TERM environment variable from the preinit environment, with value "linux", would rarely be correct for serial consoles. Now, the preinit TERM value is preserved (or set to "linux" if unset) only when the console is /dev/console or /dev/tty[0-9]*. Otherwise, it will be set to a safe default appropriate for serial consoles, "vt102", as used for serial consoles by busybox init. This "linux"/"vt102" TERM setting is also duplicated for non-failsafe console shells. This also indicates failsafe mode by showing "- failsafe -" on all consoles (not just the last-defined one). It sets a hostname of "OpenWrt-failsafe" in failsafe mode which is rendered in the shell's prompt as a reminder of the mode during interactive failsafe use. Previously, no hostname was set, which resulted in the kernel-default hostname, "(none)", appearing in failsafe shell prompts. Signed-off-by: Mark Mentovai <mark@mentovai.com> Link: https://github.com/openwrt/openwrt/pull/16113 Signed-off-by: Robert Marko <robimarko@gmail.com>
106 lines
2.7 KiB
Plaintext
106 lines
2.7 KiB
Plaintext
# Copyright (C) 2006-2010 OpenWrt.org
|
|
# Copyright (C) 2010 Vertical Communications
|
|
|
|
fs_wait_for_key () {
|
|
local timeout=$3
|
|
local timer
|
|
local do_keypress
|
|
local keypress_true="$(mktemp)"
|
|
local keypress_wait="$(mktemp)"
|
|
local keypress_sec="$(mktemp)"
|
|
if [ -z "$keypress_wait" ]; then
|
|
keypress_wait=/tmp/.keypress_wait
|
|
touch $keypress_wait
|
|
fi
|
|
if [ -z "$keypress_true" ]; then
|
|
keypress_true=/tmp/.keypress_true
|
|
touch $keypress_true
|
|
fi
|
|
if [ -z "$keypress_sec" ]; then
|
|
keypress_sec=/tmp/.keypress_sec
|
|
touch $keypress_sec
|
|
fi
|
|
|
|
trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" INT
|
|
trap "echo 'true' >$keypress_true; lock -u $keypress_wait ; rm -f $keypress_wait" USR1
|
|
|
|
[ -n "$timeout" ] || timeout=1
|
|
[ $timeout -ge 1 ] || timeout=1
|
|
timer=$timeout
|
|
lock $keypress_wait
|
|
{
|
|
while [ $timer -gt 0 ]; do
|
|
pi_failsafe_net_message=true \
|
|
preinit_net_echo "Please press button now to enter failsafe"
|
|
echo "$timer" >$keypress_sec
|
|
timer=$(($timer - 1))
|
|
sleep 1
|
|
done
|
|
lock -u $keypress_wait
|
|
rm -f $keypress_wait
|
|
} &
|
|
|
|
local consoles="$(cat /sys/class/tty/console/active)"
|
|
[ -n "$consoles" ] || consoles=console
|
|
for console in $consoles; do
|
|
[ -c "/dev/$console" ] || continue
|
|
[ "$pi_preinit_no_failsafe" != "y" ] && echo "Press the [$1] key and hit [enter] $2" > "/dev/$console"
|
|
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
|
|
timer="${timer%%\ *}"
|
|
[ $timer -ge 1 ] || timer=1
|
|
do_keypress=""
|
|
{
|
|
read -t "$timer" do_keypress < "/dev/$console"
|
|
case "$do_keypress" in
|
|
$1)
|
|
echo "true" >$keypress_true
|
|
;;
|
|
1 | 2 | 3 | 4)
|
|
echo "$do_keypress" >/tmp/debug_level
|
|
;;
|
|
*)
|
|
continue;
|
|
;;
|
|
esac
|
|
lock -u $keypress_wait
|
|
rm -f $keypress_wait
|
|
}
|
|
done
|
|
} &
|
|
done
|
|
lock -w $keypress_wait
|
|
|
|
keypressed=1
|
|
[ "$(cat $keypress_true)" = "true" ] && keypressed=0
|
|
|
|
trap - INT
|
|
trap - USR1
|
|
|
|
rm -f $keypress_true
|
|
rm -f $keypress_wait
|
|
rm -f $keypress_sec
|
|
|
|
return $keypressed
|
|
}
|
|
|
|
failsafe_wait() {
|
|
FAILSAFE=
|
|
[ "$pi_preinit_no_failsafe" = "y" ] && {
|
|
fs_wait_for_key "" "" $fs_failsafe_wait_timeout
|
|
return
|
|
}
|
|
grep -q 'failsafe=' /proc/cmdline && FAILSAFE=true && export FAILSAFE
|
|
if [ "$FAILSAFE" != "true" ]; then
|
|
fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true
|
|
[ -f "/tmp/failsafe_button" ] && FAILSAFE=true && echo "- failsafe button "$(cat /tmp/failsafe_button)" was pressed -"
|
|
[ "$FAILSAFE" = "true" ] && export FAILSAFE && touch /tmp/failsafe
|
|
fi
|
|
}
|
|
|
|
boot_hook_add preinit_main failsafe_wait
|