From 7996bacb39fb61c4829a062476f6f72baaa7eb12 Mon Sep 17 00:00:00 2001 From: Kroese Date: Mon, 20 Jul 2026 16:18:19 +0200 Subject: [PATCH] fix: Prevent races during interactive shutdown (#1907) --- src/power.sh | 114 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 22 deletions(-) diff --git a/src/power.sh b/src/power.sh index dd1a41fa..6e510765 100644 --- a/src/power.sh +++ b/src/power.sh @@ -13,6 +13,7 @@ QEMU_PTY="$QEMU_DIR/qemu.pty" QEMU_END="$QEMU_DIR/qemu.end" CONSOLE_PID="$QEMU_DIR/console.pid" CONSOLE_SOCKET="$QEMU_DIR/console.sock" +QEMU_START_PID="$QEMU_DIR/qemu.start.pid" _trap() { @@ -65,11 +66,58 @@ displayReason() { readQemuPid() { local -n _pid="$1" + local file - if [ ! -s "$QEMU_PID" ] || ! read -r _pid <"$QEMU_PID"; then - return 1 - fi + for file in "$QEMU_START_PID" "$QEMU_PID"; do + if [ -s "$file" ] && read -r _pid < "$file"; then + return 0 + fi + done + return 1 +} + +qemuPidFile() { + + local -n _file="$1" + + _file="$QEMU_PID" + [ -s "$QEMU_START_PID" ] && _file="$QEMU_START_PID" + + return 0 +} + +terminateQemu() { + + local file="" + + qemuPidFile file + sKill "$file" + + return 0 +} + +waitQemuExit() { + + local timeout="${1:-10}" + local file="" + + qemuPidFile file + waitPidFile "$file" "$timeout" +} + +waitQemuPid() { + + local -n _pid="$1" + local cnt=0 value="" + + while ! readQemuPid value; do + sleep 0.02 + cnt=$((cnt + 1)) + (( cnt >= 50 )) && return 1 + done + + _pid="$value" return 0 } @@ -99,7 +147,7 @@ boot() { fi error "Timeout while waiting for QEMU to boot the machine, aborting..." - sKill "$QEMU_PID" + terminateQemu return 0 } @@ -136,8 +184,7 @@ ready() { forceKillQemu() { local reason="$1" - local pid="" - local display + local pid="" display ! readQemuPid pid && return 0 ! isAlive "$pid" && return 0 @@ -193,9 +240,8 @@ cleanupHelpers() { startConsole() { - local cnt=0 - local pid="" local output="${1:-/dev/tty}" + local cnt=0 pid="" rm -f -- "$CONSOLE_SOCKET" "$CONSOLE_PID" @@ -240,10 +286,34 @@ stopConsole() { return 0 } +startQemu() { + + rm -f -- "$QEMU_START_PID" + + ( + trap '' INT QUIT + + # shellcheck disable=SC2016 + exec setsid -f -w sh -c ' + file=$1 + shift + + "$@" & + pid=$! + printf "%s\n" "$pid" > "$file" || exit 1 + + rc=0 + wait "$pid" 2>/dev/null || rc=$? + exit "$rc" + ' sh "$QEMU_START_PID" "$@" + )