windows/src/power.sh

214 lines
4.0 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
set -Eeuo pipefail
# Configure QEMU for graceful shutdown
QEMU_TERM=""
QEMU_PORT=7100
QEMU_TIMEOUT=110
2024-04-27 10:05:28 +00:00
QEMU_DIR="/run/shm"
QEMU_PID="$QEMU_DIR/qemu.pid"
QEMU_PTY="$QEMU_DIR/qemu.pty"
QEMU_LOG="$QEMU_DIR/qemu.log"
QEMU_OUT="$QEMU_DIR/qemu.out"
QEMU_END="$QEMU_DIR/qemu.end"
rm -f "$QEMU_DIR/qemu.*"
touch "$QEMU_LOG"
_trap() {
func="$1" ; shift
for sig ; do
trap "$func $sig" "$sig"
done
}
boot() {
[ -f "$QEMU_END" ] && return 0
if [ -s "$QEMU_PTY" ]; then
2024-05-04 11:28:12 +00:00
if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then
info "Windows started succesfully, visit http://localhost:8006/ to view the screen..."
return 0
fi
fi
error "Timeout while waiting for QEMU to boot the machine!"
return 0
}
2024-02-06 02:47:32 +00:00
ready() {
[ -f "$STORAGE/windows.boot" ] && return 0
2024-04-16 14:22:28 +00:00
[ ! -s "$QEMU_PTY" ] && return 1
2024-02-06 02:47:32 +00:00
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
2024-02-06 02:47:32 +00:00
local last
2024-02-07 22:48:38 +00:00
local bios="Booting from Hard"
last=$(grep "^Booting.*" "$QEMU_PTY" | tail -1)
2024-02-06 02:47:32 +00:00
if [[ "${last,,}" == "${bios,,}"* ]]; then
return 0
fi
return 1
fi
local line="Windows Boot Manager"
if grep -Fq "$line" "$QEMU_PTY"; then
return 0
fi
return 1
}
finish() {
local pid
local reason=$1
touch "$QEMU_END"
2024-04-16 14:22:28 +00:00
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID")
error "Forcefully terminating Windows, reason: $reason..."
{ kill -15 "$pid" || true; } 2>/dev/null
while isAlive "$pid"; do
sleep 1
# Workaround for zombie pid
2024-04-16 14:22:28 +00:00
[ ! -s "$QEMU_PID" ] && break
done
fi
2024-05-05 19:24:47 +00:00
if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$BOOT" ]; then
2024-02-06 02:47:32 +00:00
# Remove CD-ROM ISO after install
if ready; then
2024-05-05 19:24:47 +00:00
touch "$STORAGE/windows.boot"
if [[ "$REMOVE" != [Nn]* ]]; then
rm -f "$BOOT" 2>/dev/null || true
2024-04-27 10:05:28 +00:00
fi
2024-02-06 02:47:32 +00:00
fi
fi
pid="/var/run/tpm.pid"
2024-04-16 14:22:28 +00:00
[ -s "$pid" ] && pKill "$(<"$pid")"
2024-05-04 11:28:12 +00:00
pid="/var/run/wsdd.pid"
[ -s "$pid" ] && pKill "$(<"$pid")"
2024-02-07 22:48:38 +00:00
fKill "smbd"
closeNetwork
sleep 0.5
echo " Shutdown completed!"
exit "$reason"
}
terminal() {
local dev=""
2024-04-16 14:22:28 +00:00
if [ -s "$QEMU_OUT" ]; then
local msg
msg=$(<"$QEMU_OUT")
if [ -n "$msg" ]; then
if [[ "${msg,,}" != "char"* || "$msg" != *"serial0)" ]]; then
echo "$msg"
fi
dev="${msg#*/dev/p}"
dev="/dev/p${dev%% *}"
fi
fi
if [ ! -c "$dev" ]; then
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$QEMU_PORT" | tr -d '\000')
dev="${dev#*serial0}"
dev="${dev#*pty:}"
dev="${dev%%$'\n'*}"
dev="${dev%%$'\r'*}"
fi
if [ ! -c "$dev" ]; then
error "Device '$dev' not found!"
finish 34 && return 34
fi
QEMU_TERM="$dev"
return 0
}
_graceful_shutdown() {
local code=$?
set +e
if [ -f "$QEMU_END" ]; then
info "Received $1 while already shutting down..."
return
fi
touch "$QEMU_END"
info "Received $1, sending ACPI shutdown signal..."
2024-04-16 14:22:28 +00:00
if [ ! -s "$QEMU_PID" ]; then
error "QEMU PID file does not exist?"
finish "$code" && return "$code"
fi
local pid=""
pid=$(<"$QEMU_PID")
if ! isAlive "$pid"; then
error "QEMU process does not exist?"
finish "$code" && return "$code"
fi
2024-02-06 02:47:32 +00:00
if ! ready; then
info "Cannot send ACPI signal during Windows setup, aborting..."
finish "$code" && return "$code"
fi
# Send ACPI shutdown signal
echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null
local cnt=0
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
sleep 1
cnt=$((cnt+1))
! isAlive "$pid" && break
# Workaround for zombie pid
2024-04-16 14:22:28 +00:00
[ ! -s "$QEMU_PID" ] && break
info "Waiting for Windows to shutdown... ($cnt/$QEMU_TIMEOUT)"
# Send ACPI shutdown signal
echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null
done
if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then
error "Shutdown timeout reached, aborting..."
fi
finish "$code" && return "$code"
}
SERIAL="pty"
MONITOR="telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
MONITOR="$MONITOR -daemonize -D $QEMU_LOG -pidfile $QEMU_PID"
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
return 0