123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #!/usr/bin/env bash
- set -Eeuo pipefail
- # Configure QEMU for graceful shutdown
- QEMU_TERM=""
- QEMU_PORT=7100
- QEMU_TIMEOUT=110
- QEMU_PID="/run/shm/qemu.pid"
- QEMU_LOG="/run/shm/qemu.log"
- QEMU_OUT="/run/shm/qemu.out"
- QEMU_END="/run/shm/qemu.end"
- rm -f /run/shm/qemu.*
- touch "$QEMU_LOG"
- _trap() {
- func="$1" ; shift
- for sig ; do
- trap "$func $sig" "$sig"
- done
- }
- finish() {
- local pid
- local reason=$1
- if [ -f "$QEMU_PID" ]; then
- pid=$(<"$QEMU_PID")
- echo && error "Forcefully terminating Windows, reason: $reason..."
- { kill -15 "$pid" || true; } 2>/dev/null
- while isAlive "$pid"; do
- sleep 1
- # Workaround for zombie pid
- [ ! -f "$QEMU_PID" ] && break
- done
- fi
- pid="/var/run/tpm.pid"
- [ -f "$pid" ] && pKill "$(<"$pid")"
- closeNetwork
- sleep 1
- echo && echo "❯ Shutdown completed!"
- exit "$reason"
- }
- terminal() {
- local dev=""
- if [ -f "$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
- echo && info "Received $1 while already shutting down..."
- return
- fi
- touch "$QEMU_END"
- echo && info "Received $1, sending ACPI shutdown signal..."
- if [ ! -f "$QEMU_PID" ]; then
- echo && error "QEMU PID file does not exist?"
- finish "$code" && return "$code"
- fi
- local pid=""
- pid=$(<"$QEMU_PID")
- if ! isAlive "$pid"; then
- echo && error "QEMU process does not exist?"
- 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
- [ ! -f "$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
- echo && 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
|