| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | #!/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" | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  | QEMU_PTY="/run/shm/qemu.pty" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 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") | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     error "Forcefully terminating Windows, reason: $reason..." | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     { 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 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |   sleep 0.5 | 
					
						
							|  |  |  |  |   echo "❯ Shutdown completed!" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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 | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     info "Received $1 while already shutting down..." | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     return | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   touch "$QEMU_END" | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |   info "Received $1, sending ACPI shutdown signal..." | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if [ ! -f "$QEMU_PID" ]; then | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     error "QEMU PID file does not exist?" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     finish "$code" && return "$code" | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   local pid="" | 
					
						
							|  |  |  |  |   pid=$(<"$QEMU_PID") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if ! isAlive "$pid"; then | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     error "QEMU process does not exist?" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     finish "$code" && return "$code" | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 16:15:18 +01:00
										 |  |  |  |   local remove_iso="" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if [ ! -f "$STORAGE/windows.old" ]; then | 
					
						
							|  |  |  |  |     if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$QEMU_PTY" ]; then | 
					
						
							|  |  |  |  |       if grep -Fq "Windows Boot Manager" "$QEMU_PTY"; then | 
					
						
							|  |  |  |  |         [ -f "$STORAGE/$BASE" ] && remove_iso="y" | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         info "Cannot send ACPI signal during Windows setup, aborting..." | 
					
						
							|  |  |  |  |         finish "$code" && return "$code" | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |       fi | 
					
						
							|  |  |  |  |     fi | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   # 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 | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     error "Shutdown timeout reached, aborting..." | 
					
						
							| 
									
										
										
										
											2024-01-25 16:15:18 +01:00
										 |  |  |  |   else | 
					
						
							|  |  |  |  |     if [ -n "$remove_iso" ]; then | 
					
						
							|  |  |  |  |       rm -f "$STORAGE/$BASE" | 
					
						
							|  |  |  |  |       touch "$STORAGE/windows.boot" | 
					
						
							|  |  |  |  |     fi | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   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 |