mirror of
https://github.com/dockur/windows.git
synced 2026-08-03 12:37:20 +01:00
217 lines
3.9 KiB
Bash
217 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
||
set -Eeuo pipefail
|
||
|
||
: "${SHUTDOWN:="Y"}" # Graceful ACPI shutdown
|
||
: "${TIMEOUT:="105"}" # QEMU termination timeout
|
||
|
||
# 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"
|
||
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
|
||
|
||
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() {
|
||
|
||
[ -f "$QEMU_END" ] && return 0
|
||
|
||
if [ -s "$QEMU_PTY" ]; then
|
||
if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then
|
||
if ! bootFailed; then
|
||
info "$(app) started successfully, visit http://127.0.0.1:8006/ to view the screen..."
|
||
return 0
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
error "Timeout while waiting for QEMU to boot the machine, aborting..."
|
||
terminateQemu
|
||
|
||
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() {
|
||
|
||
[ -f "$STORAGE/windows.boot" ] && return 0
|
||
[ ! -s "$QEMU_PTY" ] && return 1
|
||
|
||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
||
legacyBootReady && return 0
|
||
return 1
|
||
fi
|
||
|
||
local line="\"Windows Boot Manager\""
|
||
grep -Fq "$line" "$QEMU_PTY" && return 0
|
||
|
||
return 1
|
||
}
|
||
|
||
markWindowsBooted() {
|
||
|
||
local file="$STORAGE/windows.boot"
|
||
|
||
if [ -f "$file" ] || [ ! -f "$BOOT" ]; then
|
||
return 0
|
||
fi
|
||
|
||
# Remove CD-ROM ISO after install
|
||
! ready && return 0
|
||
|
||
if ! touch "$file"; then
|
||
warn "failed to create Windows installation marker!"
|
||
return 0
|
||
fi
|
||
|
||
if ! setOwner "$file"; then
|
||
rm -f "$file"
|
||
warn "failed to set the owner for \"$file\" !"
|
||
return 0
|
||
fi
|
||
|
||
if ! disabled "$REMOVE"; then
|
||
rm -f "$BOOT" 2>/dev/null || true
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
finish() {
|
||
|
||
local reason=$1 failed=0
|
||
|
||
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
|
||
failed=1
|
||
fi
|
||
|
||
touch "$QEMU_END"
|
||
|
||
forceKillQemu "$reason"
|
||
|
||
if [ ! -f "$STORAGE/windows.boot" ]; then
|
||
markWindowsBooted
|
||
fi
|
||
|
||
cleanupHelpers \
|
||
"${SMB_PID:-}" \
|
||
"${NMB_PID:-}" \
|
||
"${DDN_PID:-}"
|
||
|
||
if ! waitQemuExit 10; then
|
||
warn "Timed out while waiting for $(app) to exit!"
|
||
fi
|
||
|
||
echo
|
||
|
||
if (( failed == 0 )); then
|
||
echo "❯ Shutdown completed!"
|
||
else
|
||
error "QEMU exited unexpectedly!"
|
||
fi
|
||
|
||
exit "$reason"
|
||
}
|
||
|
||
abortDuringSetup() {
|
||
|
||
local code="$1"
|
||
|
||
info "Cannot send ACPI signal during $(app) setup, aborting..."
|
||
|
||
terminateQemu
|
||
|
||
if ! waitQemuExit 5; then
|
||
warn "Timed out while waiting for $(app) to exit!"
|
||
fi
|
||
|
||
finish "$code"
|
||
}
|
||
|
||
gracefulShutdown() {
|
||
|
||
local sig="$1"
|
||
local pid="" code=0
|
||
|
||
[[ $BASHPID != "$TRAP_PID" ]] && return
|
||
|
||
code=$(signalCode "$sig")
|
||
|
||
if [ -f "$QEMU_END" ]; then
|
||
|
||
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 $sig signal, sending ACPI shutdown signal..."
|
||
|
||
if ! readQemuPid pid; then
|
||
if ! interactive || ! waitQemuPid pid; then
|
||
warn "QEMU PID file does not exist?"
|
||
finish "$code"
|
||
fi
|
||
fi
|
||
|
||
if [ -z "$pid" ] || ! isAlive "$pid"; then
|
||
warn "QEMU process with PID $pid does not exist?"
|
||
finish "$code"
|
||
fi
|
||
|
||
if ! ready; then
|
||
abortDuringSetup "$code"
|
||
fi
|
||
|
||
normalizeTimeout 105
|
||
waitForShutdown "$pid"
|
||
|
||
finish "$code"
|
||
}
|
||
|
||
! enabled "$SHUTDOWN" && return 0
|
||
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
|
||
|
||
if interactive; then
|
||
_trap gracefulShutdown SIGINT
|
||
fi
|
||
|
||
_trap gracefulShutdown SIGTERM SIGHUP SIGABRT SIGQUIT
|
||
|
||
return 0
|