mirror of
https://github.com/dockur/windows.git
synced 2026-07-07 05:07:26 +01:00
feat: Refactor shutdown logic (#1804)
This commit is contained in:
+186
-90
@@ -23,18 +23,67 @@ app() {
|
|||||||
echo "$APP" && return 0
|
echo "$APP" && return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signalCode() {
|
||||||
|
local sig="$1"
|
||||||
|
|
||||||
|
case "$sig" in
|
||||||
|
SIGHUP) echo 129 ;;
|
||||||
|
SIGINT) echo 130 ;;
|
||||||
|
SIGQUIT) echo 131 ;;
|
||||||
|
SIGABRT) echo 134 ;;
|
||||||
|
SIGTERM) echo 143 ;;
|
||||||
|
*) echo 0 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
displayReason() {
|
||||||
|
local reason="$1"
|
||||||
|
|
||||||
|
case "$reason" in
|
||||||
|
129 ) echo "SIGHUP" ;;
|
||||||
|
130 ) echo "SIGINT" ;;
|
||||||
|
131 ) echo "SIGQUIT" ;;
|
||||||
|
134 ) echo "SIGABRT" ;;
|
||||||
|
143 ) echo "SIGTERM" ;;
|
||||||
|
* ) echo "$reason" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
readQemuPid() {
|
||||||
|
local file="$1"
|
||||||
|
local __var="$2"
|
||||||
|
local pid=""
|
||||||
|
|
||||||
|
[ -s "$file" ] || return 1
|
||||||
|
read -r pid <"$file" || return 1
|
||||||
|
[ -n "$pid" ] || return 1
|
||||||
|
|
||||||
|
printf -v "$__var" '%s' "$pid"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bootFailed() {
|
||||||
|
local fail=""
|
||||||
|
|
||||||
|
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
||||||
|
grep -Fq "No bootable device." "$QEMU_PTY" && fail="y"
|
||||||
|
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && fail="y"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -n "$fail" ]
|
||||||
|
}
|
||||||
|
|
||||||
boot() {
|
boot() {
|
||||||
|
|
||||||
[ -f "$QEMU_END" ] && return 0
|
[ -f "$QEMU_END" ] && return 0
|
||||||
|
|
||||||
if [ -s "$QEMU_PTY" ]; then
|
if [ -s "$QEMU_PTY" ]; then
|
||||||
if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then
|
if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then
|
||||||
local fail=""
|
if ! bootFailed; then
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
|
||||||
grep -Fq "No bootable device." "$QEMU_PTY" && fail="y"
|
|
||||||
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && fail="y"
|
|
||||||
fi
|
|
||||||
if [ -z "$fail" ]; then
|
|
||||||
info "$(app) started successfully, visit http://127.0.0.1:8006/ to view the screen..."
|
info "$(app) started successfully, visit http://127.0.0.1:8006/ to view the screen..."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -47,19 +96,26 @@ boot() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
legacyBootReady() {
|
||||||
|
local last
|
||||||
|
local bios="Booting from Hard"
|
||||||
|
|
||||||
|
last=$(grep "^Booting.*" "$QEMU_PTY" | tail -1)
|
||||||
|
[[ "${last,,}" != "${bios,,}"* ]] && return 1
|
||||||
|
grep -Fq "No bootable device." "$QEMU_PTY" && return 1
|
||||||
|
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
ready() {
|
ready() {
|
||||||
|
|
||||||
[ -f "$STORAGE/windows.boot" ] && return 0
|
[ -f "$STORAGE/windows.boot" ] && return 0
|
||||||
[ ! -s "$QEMU_PTY" ] && return 1
|
[ ! -s "$QEMU_PTY" ] && return 1
|
||||||
|
|
||||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
||||||
local last
|
legacyBootReady && return 0
|
||||||
local bios="Booting from Hard"
|
return 1
|
||||||
last=$(grep "^Booting.*" "$QEMU_PTY" | tail -1)
|
|
||||||
[[ "${last,,}" != "${bios,,}"* ]] && return 1
|
|
||||||
grep -Fq "No bootable device." "$QEMU_PTY" && return 1
|
|
||||||
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && return 1
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local line="\"Windows Boot Manager\""
|
local line="\"Windows Boot Manager\""
|
||||||
@@ -68,48 +124,65 @@ ready() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
finish() {
|
forceKillQemu() {
|
||||||
|
local reason="$1"
|
||||||
local i=0
|
|
||||||
local pid=""
|
local pid=""
|
||||||
local reason=$1
|
local display
|
||||||
local pids=( "${SMB_PID:-}" "${NMB_PID:-}" "${DDN_PID:-}" "${TPM_PID:-}" "${WSD_PID:-}" \
|
|
||||||
"${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" "${BALLOONING_PID:-}" )
|
|
||||||
|
|
||||||
touch "$QEMU_END"
|
if readQemuPid "$QEMU_PID" pid; then
|
||||||
|
if isAlive "$pid"; then
|
||||||
if [ -s "$QEMU_PID" ]; then
|
display=$(displayReason "$reason")
|
||||||
if read -r pid <"$QEMU_PID"; then
|
|
||||||
if [ -n "$pid" ] && isAlive "$pid"; then
|
|
||||||
local display="$reason"
|
|
||||||
case "$reason" in
|
|
||||||
129 ) display="SIGHUP" ;;
|
|
||||||
130 ) display="SIGINT" ;;
|
|
||||||
131 ) display="SIGQUIT" ;;
|
|
||||||
134 ) display="SIGABRT" ;;
|
|
||||||
143 ) display="SIGTERM" ;;
|
|
||||||
esac
|
|
||||||
error "Forcefully terminating $(app), reason: $display..."
|
error "Forcefully terminating $(app), reason: $display..."
|
||||||
{ disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null
|
{ disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
markWindowsBooted() {
|
||||||
|
local file="$STORAGE/windows.boot"
|
||||||
|
|
||||||
|
if [ -f "$file" ] || [ ! -f "$BOOT" ]; then
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$BOOT" ]; then
|
|
||||||
# Remove CD-ROM ISO after install
|
# Remove CD-ROM ISO after install
|
||||||
if ready; then
|
if ready; then
|
||||||
local file="$STORAGE/windows.boot"
|
|
||||||
touch "$file"
|
touch "$file"
|
||||||
! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
|
! setOwner "$file" && error "Failed to set the owner for \"$file\" !"
|
||||||
if ! disabled "$REMOVE"; then
|
if ! disabled "$REMOVE"; then
|
||||||
rm -f "$BOOT" 2>/dev/null || true
|
rm -f "$BOOT" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupHelpers() {
|
||||||
|
local pids=( "${SMB_PID:-}" "${NMB_PID:-}" "${DDN_PID:-}" "${TPM_PID:-}" "${WSD_PID:-}" \
|
||||||
|
"${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" "${BALLOONING_PID:-}" )
|
||||||
|
|
||||||
mKill "${pids[@]}"
|
mKill "${pids[@]}"
|
||||||
closeNetwork
|
closeNetwork
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
finish() {
|
||||||
|
|
||||||
|
local reason=$1
|
||||||
|
|
||||||
|
touch "$QEMU_END"
|
||||||
|
|
||||||
|
forceKillQemu "$reason"
|
||||||
|
|
||||||
|
if [ ! -f "$STORAGE/windows.boot" ]; then
|
||||||
|
markWindowsBooted
|
||||||
|
fi
|
||||||
|
|
||||||
|
cleanupHelpers
|
||||||
|
|
||||||
if ! waitPidFile "$QEMU_PID" 10; then
|
if ! waitPidFile "$QEMU_PID" 10; then
|
||||||
warn "Timed out while waiting for $(app) to exit!"
|
warn "Timed out while waiting for $(app) to exit!"
|
||||||
fi
|
fi
|
||||||
@@ -118,55 +191,11 @@ finish() {
|
|||||||
exit "$reason"
|
exit "$reason"
|
||||||
}
|
}
|
||||||
|
|
||||||
graceful_shutdown() {
|
normalizeTimeout() {
|
||||||
|
local min
|
||||||
|
|
||||||
local sig="$1"
|
term_grace=3 # seconds before loop ends to send SIGTERM
|
||||||
local pid=""
|
cleanup_grace=3 # seconds reserved after the loop for cleanup
|
||||||
local code=0
|
|
||||||
|
|
||||||
[[ $BASHPID != "$TRAP_PID" ]] && return
|
|
||||||
|
|
||||||
case "$sig" in
|
|
||||||
SIGHUP) code=129 ;;
|
|
||||||
SIGINT) code=130 ;;
|
|
||||||
SIGQUIT) code=131 ;;
|
|
||||||
SIGABRT) code=134 ;;
|
|
||||||
SIGTERM) code=143 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -f "$QEMU_END" ]; then
|
|
||||||
echo && info "Received $1 signal while already shutting down..."
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
|
||||||
touch "$QEMU_END"
|
|
||||||
echo && info "Received $1 signal, sending ACPI shutdown signal..."
|
|
||||||
|
|
||||||
if [ ! -s "$QEMU_PID" ] || ! read -r pid <"$QEMU_PID"; then
|
|
||||||
warn "QEMU PID file ($QEMU_PID) does not exist?"
|
|
||||||
finish "$code"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$pid" ] || ! isAlive "$pid"; then
|
|
||||||
warn "QEMU process with PID $pid does not exist?"
|
|
||||||
finish "$code"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! ready; then
|
|
||||||
info "Cannot send ACPI signal during $(app) setup, aborting..."
|
|
||||||
sKill "$QEMU_PID"
|
|
||||||
if ! waitPidFile "$QEMU_PID" 5; then
|
|
||||||
warn "Timed out while waiting for $(app) to exit!"
|
|
||||||
fi
|
|
||||||
finish "$code"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local name
|
|
||||||
name="$(app)"
|
|
||||||
|
|
||||||
local term_grace=3 # seconds before loop ends to send SIGTERM
|
|
||||||
local cleanup_grace=3 # seconds reserved after the loop for cleanup
|
|
||||||
|
|
||||||
TIMEOUT=$(strip "$TIMEOUT")
|
TIMEOUT=$(strip "$TIMEOUT")
|
||||||
if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]]; then
|
if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]]; then
|
||||||
@@ -181,18 +210,45 @@ graceful_shutdown() {
|
|||||||
cleanup_grace=4
|
cleanup_grace=4
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local cnt=0 sigterm_at=0 min wait_until
|
|
||||||
|
|
||||||
min=$((term_grace + cleanup_grace + 1))
|
min=$((term_grace + cleanup_grace + 1))
|
||||||
(( TIMEOUT < min )) && (( TIMEOUT = min ))
|
(( TIMEOUT < min )) && (( TIMEOUT = min ))
|
||||||
|
|
||||||
wait_until=$((TIMEOUT - cleanup_grace))
|
wait_until=$((TIMEOUT - cleanup_grace))
|
||||||
sigterm_at=$((wait_until - term_grace))
|
sigterm_at=$((wait_until - term_grace))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAcpiShutdown() {
|
||||||
|
# Send ACPI shutdown signal
|
||||||
|
if [ -S "$QEMU_DIR/monitor.sock" ]; then
|
||||||
|
nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || :
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
abortDuringSetup() {
|
||||||
|
local code="$1"
|
||||||
|
|
||||||
|
info "Cannot send ACPI signal during $(app) setup, aborting..."
|
||||||
|
sKill "$QEMU_PID"
|
||||||
|
if ! waitPidFile "$QEMU_PID" 5; then
|
||||||
|
warn "Timed out while waiting for $(app) to exit!"
|
||||||
|
fi
|
||||||
|
finish "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForShutdown() {
|
||||||
|
local cnt=0
|
||||||
|
local name="$1"
|
||||||
|
local pid="$2"
|
||||||
|
local slp
|
||||||
|
|
||||||
while (( cnt <= wait_until )); do
|
while (( cnt <= wait_until )); do
|
||||||
|
|
||||||
sleep 1 &
|
sleep 1 &
|
||||||
local slp=$!
|
slp=$!
|
||||||
|
|
||||||
# Stop waiting if the process has exited
|
# Stop waiting if the process has exited
|
||||||
! isAlive "$pid" && break
|
! isAlive "$pid" && break
|
||||||
@@ -207,16 +263,56 @@ graceful_shutdown() {
|
|||||||
info "Waiting for $name to shut down... ($cnt/$wait_until)"
|
info "Waiting for $name to shut down... ($cnt/$wait_until)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Send ACPI shutdown signal
|
sendAcpiShutdown
|
||||||
if [ -S "$QEMU_DIR/monitor.sock" ]; then
|
|
||||||
nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || :
|
|
||||||
fi
|
|
||||||
|
|
||||||
wait "$slp"
|
wait "$slp"
|
||||||
(( cnt++ ))
|
(( cnt++ ))
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
graceful_shutdown() {
|
||||||
|
|
||||||
|
local sig="$1"
|
||||||
|
local pid=""
|
||||||
|
local code=0
|
||||||
|
local name
|
||||||
|
local term_grace cleanup_grace
|
||||||
|
local sigterm_at=0 wait_until=0
|
||||||
|
|
||||||
|
[[ $BASHPID != "$TRAP_PID" ]] && return
|
||||||
|
|
||||||
|
code=$(signalCode "$sig")
|
||||||
|
|
||||||
|
if [ -f "$QEMU_END" ]; then
|
||||||
|
echo && info "Received $1 signal while already shutting down..."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
touch "$QEMU_END"
|
||||||
|
echo && info "Received $1 signal, sending ACPI shutdown signal..."
|
||||||
|
|
||||||
|
if ! readQemuPid "$QEMU_PID" pid; then
|
||||||
|
warn "QEMU PID file ($QEMU_PID) does not exist?"
|
||||||
|
finish "$code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! isAlive "$pid"; then
|
||||||
|
warn "QEMU process with PID $pid does not exist?"
|
||||||
|
finish "$code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! ready; then
|
||||||
|
abortDuringSetup "$code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
name="$(app)"
|
||||||
|
normalizeTimeout
|
||||||
|
waitForShutdown "$name" "$pid"
|
||||||
|
|
||||||
finish "$code"
|
finish "$code"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user