feat: Preserve graceful shutdown for interactive console (#1876)

This commit is contained in:
Kroese
2026-07-17 21:09:04 +02:00
committed by GitHub
parent f997e81e81
commit 810a53980f
2 changed files with 83 additions and 9 deletions
+6
View File
@@ -53,13 +53,19 @@ if ! enabled "$SHUTDOWN"; then
exec "${cmd[@]}" ${ARGS:+ $ARGS} >"$pipe" 2>&1
fi
if ! interactive; then
"${cmd[@]}" ${ARGS:+ $ARGS} >"$pipe" 2>&1 &
else
startConsole "$pipe"
setsid -w "${cmd[@]}" ${ARGS:+ $ARGS} </dev/null >"$pipe" 2>&1 &
fi
pid=$!
( sleep 30; boot ) &
rc=0
wait "$pid" || rc=$?
interactive && stopConsole
wait "$output" || :
[ -f "$QEMU_END" ] && exit "$rc"
+75 -7
View File
@@ -6,13 +6,19 @@ set -Eeuo pipefail
# Configure QEMU for graceful shutdown
SHUTDOWN_SKIP=0
SHUTDOWN_SIGNAL=0
QEMU_PTY="$QEMU_DIR/qemu.pty"
QEMU_END="$QEMU_DIR/qemu.end"
CONSOLE_PID="$QEMU_DIR/console.pid"
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
_trap() {
local func="$1"; shift
local sig
TRAP_PID=$BASHPID
for sig; do
@@ -174,8 +180,8 @@ cleanupHelpers() {
local pids=( "${SMB_PID:-}" "${NMB_PID:-}" "${DDN_PID:-}" \
"${TPM_PID:-}" "${WSD_PID:-}" "${WEB_PID:-}" \
"${AUX_PID:-}" "${AUDIO_PID:-}" "${PASST_PID:-}" \
"${DNSMASQ_PID:-}" "${BALLOONING_PID:-}" )
"${AUX_PID:-}" "${AUDIO_PID:-}" "${CONSOLE_PID:-}" \
"${PASST_PID:-}" "${DNSMASQ_PID:-}" "${BALLOONING_PID:-}" )
mKill "${pids[@]}"
@@ -183,6 +189,55 @@ cleanupHelpers() {
return 0
}
startConsole() {
local cnt=0
local pid=""
local output="${1:-/dev/tty}"
rm -f -- "$CONSOLE_SOCKET" "$CONSOLE_PID"
if ! stty -icanon -echo isig -ixon min 1 time 0 </dev/tty; then
error "Failed to configure serial console terminal!"
return 1
fi
(
trap '' INT QUIT
exec nc -lU "$CONSOLE_SOCKET" </dev/tty >"$output"
) &
pid=$!
echo "$pid" > "$CONSOLE_PID"
while [ ! -S "$CONSOLE_SOCKET" ]; do
if ! isAlive "$pid"; then
rm -f -- "$CONSOLE_PID"
error "Serial console relay exited unexpectedly!"
return 1
fi
sleep 0.02
cnt=$((cnt + 1))
if (( cnt > 100 )); then
error "Failed to start serial console relay!"
return 1
fi
done
return 0
}
stopConsole() {
mKill "$CONSOLE_PID"
return 0
}
finish() {
local reason=$1
@@ -276,7 +331,7 @@ waitForShutdown() {
local name="$APP"
local slp
while (( cnt <= wait_until )); do
while (( cnt <= wait_until && SHUTDOWN_SKIP == 0 )); do
sleep 1 &
slp=$!
@@ -296,7 +351,7 @@ waitForShutdown() {
sendAcpiShutdown
wait "$slp"
wait "$slp" || :
(( cnt++ ))
done
@@ -315,20 +370,29 @@ graceful_shutdown() {
code=$(signalCode "$sig")
if [ -f "$QEMU_END" ]; then
echo && info "Received $1 signal while already shutting down..."
if (( code == 130 && SHUTDOWN_SIGNAL == code )); then
SHUTDOWN_SKIP=1
echo && info "Received SIGINT again, forcing shutdown..."
return
fi
echo && info "Received $sig signal while already shutting down..."
return
fi
set +e
SHUTDOWN_SIGNAL=$code
touch "$QEMU_END"
echo && info "Received $1 signal, sending ACPI shutdown signal..."
echo && info "Received $sig signal, sending ACPI shutdown signal..."
if ! readQemuPid pid; then
warn "QEMU PID file ($QEMU_PID) does not exist?"
finish "$code"
fi
if ! isAlive "$pid"; then
if [ -z "$pid" ] || ! isAlive "$pid"; then
warn "QEMU process with PID $pid does not exist?"
finish "$code"
fi
@@ -346,6 +410,10 @@ graceful_shutdown() {
! enabled "$SHUTDOWN" && return 0
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
if interactive; then
_trap graceful_shutdown SIGINT
fi
_trap graceful_shutdown SIGTERM SIGHUP SIGABRT SIGQUIT
return 0