| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | #!/usr/bin/env bash
 | 
					
						
							|  |  |  |  | set -Eeuo pipefail | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-04 09:47:08 +02:00
										 |  |  |  | : "${QEMU_TIMEOUT:="110"}"  # QEMU Termination timeout | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | # Configure QEMU for graceful shutdown | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | QEMU_TERM="" | 
					
						
							| 
									
										
										
										
											2024-04-27 12:05:28 +02: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.*" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | touch "$QEMU_LOG" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | _trap() { | 
					
						
							|  |  |  |  |   func="$1" ; shift | 
					
						
							|  |  |  |  |   for sig ; do | 
					
						
							|  |  |  |  |     trap "$func $sig" "$sig" | 
					
						
							|  |  |  |  |   done | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 22:57:44 +02:00
										 |  |  |  | boot() { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   [ -f "$QEMU_END" ] && return 0 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if [ -s "$QEMU_PTY" ]; then | 
					
						
							| 
									
										
										
										
											2024-05-04 13:28:12 +02:00
										 |  |  |  |     if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then | 
					
						
							| 
									
										
										
										
											2024-05-27 12:40:19 +02:00
										 |  |  |  |       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 | 
					
						
							|  |  |  |  |       if [ -z "$fail" ]; then | 
					
						
							| 
									
										
										
										
											2025-05-26 23:52:50 +01:00
										 |  |  |  |         info "Windows started successfully, visit http://127.0.0.1:8006/ to view the screen..." | 
					
						
							| 
									
										
										
										
											2024-05-10 18:21:41 +02:00
										 |  |  |  |         return 0 | 
					
						
							|  |  |  |  |       fi | 
					
						
							| 
									
										
										
										
											2024-04-30 22:57:44 +02:00
										 |  |  |  |     fi | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   error "Timeout while waiting for QEMU to boot the machine!" | 
					
						
							| 
									
										
										
										
											2024-05-27 12:40:19 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   local pid | 
					
						
							|  |  |  |  |   pid=$(<"$QEMU_PID") | 
					
						
							|  |  |  |  |   { kill -15 "$pid" || true; } 2>/dev/null | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-30 22:57:44 +02:00
										 |  |  |  |   return 0 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  | ready() { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   [ -f "$STORAGE/windows.boot" ] && return 0 | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |   [ ! -s "$QEMU_PTY" ] && return 1 | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-27 18:46:09 +02:00
										 |  |  |  |   if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  |     local last | 
					
						
							| 
									
										
										
										
											2024-02-07 23:48:38 +01:00
										 |  |  |  |     local bios="Booting from Hard" | 
					
						
							|  |  |  |  |     last=$(grep "^Booting.*" "$QEMU_PTY" | tail -1) | 
					
						
							| 
									
										
										
										
											2024-05-27 12:40:19 +02:00
										 |  |  |  |     [[ "${last,,}" != "${bios,,}"* ]] && return 1 | 
					
						
							|  |  |  |  |     grep -Fq "No bootable device." "$QEMU_PTY" && return 1 | 
					
						
							|  |  |  |  |     grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && return 1 | 
					
						
							|  |  |  |  |     return 0 | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 21:26:10 +02:00
										 |  |  |  |   local line="\"Windows Boot Manager\"" | 
					
						
							| 
									
										
										
										
											2024-05-27 12:40:19 +02:00
										 |  |  |  |   grep -Fq "$line" "$QEMU_PTY" && return 0 | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return 1 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | finish() { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   local pid | 
					
						
							|  |  |  |  |   local reason=$1 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-16 16:00:21 +01:00
										 |  |  |  |   touch "$QEMU_END" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |   if [ -s "$QEMU_PID" ]; then | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |       [ ! -s "$QEMU_PID" ] && break | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     done | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-21 23:04:29 +02:00
										 |  |  |  |   if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$BOOT" ]; then | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  |     # Remove CD-ROM ISO after install | 
					
						
							|  |  |  |  |     if ready; then | 
					
						
							| 
									
										
										
										
											2024-05-05 21:24:47 +02:00
										 |  |  |  |       touch "$STORAGE/windows.boot" | 
					
						
							|  |  |  |  |       if [[ "$REMOVE" != [Nn]* ]]; then | 
					
						
							|  |  |  |  |         rm -f "$BOOT" 2>/dev/null || true | 
					
						
							| 
									
										
										
										
											2024-04-27 12:05:28 +02:00
										 |  |  |  |       fi | 
					
						
							| 
									
										
										
										
											2024-02-06 03:47:32 +01:00
										 |  |  |  |     fi | 
					
						
							|  |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   pid="/var/run/tpm.pid" | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |   [ -s "$pid" ] && pKill "$(<"$pid")" | 
					
						
							| 
									
										
										
										
											2025-10-06 13:22:28 +02:00
										 |  |  |  |   rm -f "$pid" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-04 13:28:12 +02:00
										 |  |  |  |   pid="/var/run/wsdd.pid" | 
					
						
							|  |  |  |  |   [ -s "$pid" ] && pKill "$(<"$pid")" | 
					
						
							| 
									
										
										
										
											2025-10-06 13:22:28 +02:00
										 |  |  |  |   rm -f "$pid" | 
					
						
							| 
									
										
										
										
											2024-05-04 13:28:12 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-06 13:22:28 +02:00
										 |  |  |  |   pid="/var/run/samba/nmbd.pid" | 
					
						
							|  |  |  |  |   [ -s "$pid" ] && pKill "$(<"$pid")" | 
					
						
							|  |  |  |  |   rm -f "$pid" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   pid="/var/run/samba/smbd.pid" | 
					
						
							|  |  |  |  |   [ -s "$pid" ] && pKill "$(<"$pid")" | 
					
						
							|  |  |  |  |   rm -f "$pid" | 
					
						
							| 
									
										
										
										
											2024-02-07 23:48:38 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   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="" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |   if [ -s "$QEMU_OUT" ]; then | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2025-10-04 09:47:08 +02:00
										 |  |  |  |     dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$MON_PORT" | tr -d '\000') | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |     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
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |   if [ ! -s "$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-02-06 03:47:32 +01:00
										 |  |  |  |   if ! ready; then | 
					
						
							|  |  |  |  |     info "Cannot send ACPI signal during Windows setup, aborting..." | 
					
						
							|  |  |  |  |     finish "$code" && return "$code" | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   # Send ACPI shutdown signal | 
					
						
							| 
									
										
										
										
											2025-10-04 09:47:08 +02:00
										 |  |  |  |   echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   local cnt=0 | 
					
						
							|  |  |  |  |   while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     sleep 1 | 
					
						
							|  |  |  |  |     cnt=$((cnt+1)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     ! isAlive "$pid" && break | 
					
						
							|  |  |  |  |     # Workaround for zombie pid | 
					
						
							| 
									
										
										
										
											2024-04-16 16:22:28 +02:00
										 |  |  |  |     [ ! -s "$QEMU_PID" ] && break | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     info "Waiting for Windows to shutdown... ($cnt/$QEMU_TIMEOUT)" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     # Send ACPI shutdown signal | 
					
						
							| 
									
										
										
										
											2025-10-04 09:47:08 +02:00
										 |  |  |  |     echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   done | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then | 
					
						
							| 
									
										
										
										
											2024-01-24 05:38:16 +01:00
										 |  |  |  |     error "Shutdown timeout reached, aborting..." | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  |   fi | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   finish "$code" && return "$code" | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | SERIAL="pty" | 
					
						
							| 
									
										
										
										
											2025-10-04 09:47:08 +02:00
										 |  |  |  | MONITOR="telnet:localhost:$MON_PORT,server,nowait,nodelay" | 
					
						
							| 
									
										
										
										
											2024-06-09 23:17:42 +02:00
										 |  |  |  | MONITOR+=" -daemonize -D $QEMU_LOG -pidfile $QEMU_PID" | 
					
						
							| 
									
										
										
										
											2024-01-23 22:38:17 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | _trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | return 0 |