mirror of
				https://github.com/dockur/windows.git
				synced 2025-10-27 03:15:49 +00:00 
			
		
		
		
	feat: Implement graceful shutdown (#81)
This commit is contained in:
		
							parent
							
								
									8474b917b2
								
							
						
					
					
						commit
						08f040a819
					
				
					 5 changed files with 169 additions and 23 deletions
				
			
		
							
								
								
									
										16
									
								
								src/entry.sh
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								src/entry.sh
									
										
									
									
									
								
							|  | @ -2,23 +2,31 @@ | |||
| set -Eeuo pipefail | ||||
| 
 | ||||
| APP="Windows" | ||||
| export BOOT_MODE=windows | ||||
| BOOT_MODE="windows" | ||||
| SUPPORT="https://github.com/dockur/windows" | ||||
| 
 | ||||
| cd /run | ||||
| 
 | ||||
| . reset.sh      # Initialize system | ||||
| . install.sh    # Get bootdisk | ||||
| . install.sh    # Run installation | ||||
| . disk.sh       # Initialize disks | ||||
| . display.sh    # Initialize graphics | ||||
| . network.sh    # Initialize network | ||||
| . boot.sh       # Configure boot | ||||
| . proc.sh       # Initialize processor | ||||
| . power.sh      # Configure shutdown | ||||
| . config.sh     # Configure arguments | ||||
| 
 | ||||
| trap - ERR | ||||
| 
 | ||||
| info "Booting $APP using $VERS..." | ||||
| [[ "$DEBUG" == [Yy1]* ]] && echo "Arguments: $ARGS" && echo | ||||
| 
 | ||||
| [[ "$DEBUG" == [Yy1]* ]] && set -x | ||||
| exec qemu-system-x86_64 ${ARGS:+ $ARGS} | ||||
| { qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || : | ||||
| (( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15 | ||||
| 
 | ||||
| terminal | ||||
| tail -fn +0 "$QEMU_LOG" 2>/dev/null & | ||||
| cat "$QEMU_TERM" 2>/dev/null & wait $! || : | ||||
| 
 | ||||
| sleep 1 && finish 0 | ||||
|  |  | |||
|  | @ -31,14 +31,6 @@ set -Eeuo pipefail | |||
| [[ "${VERSION,,}" == "win16" ]] && VERSION="win2016-eval" | ||||
| [[ "${VERSION,,}" == "win2016" ]] && VERSION="win2016-eval" | ||||
| 
 | ||||
| if [[ "${VERSION,,}" == "tiny10" ]]; then | ||||
|   VERSION="https://archive.org/download/tiny-10-23-h2/tiny10%20x64%2023h2.iso" | ||||
| fi | ||||
| 
 | ||||
| if [[ "${VERSION,,}" == "tiny11" ]]; then | ||||
|   VERSION="https://archive.org/download/tiny-11-core-x-64-beta-1/tiny11%20core%20x64%20beta%201.iso" | ||||
| fi | ||||
| 
 | ||||
| CUSTOM="custom.iso" | ||||
| 
 | ||||
| [ ! -f "$STORAGE/$CUSTOM" ] && CUSTOM="Custom.iso" | ||||
|  | @ -91,14 +83,9 @@ else | |||
| fi | ||||
| 
 | ||||
| html "$MSG" | ||||
| 
 | ||||
| TMP="$STORAGE/tmp" | ||||
| 
 | ||||
| if [ -z "$MANUAL" ]; then | ||||
| 
 | ||||
|   MANUAL="N" | ||||
|   [[ "${BASE,,}" == "tiny10"* ]] && MANUAL="Y" | ||||
| 
 | ||||
| fi | ||||
| [ -z "$MANUAL" ] && MANUAL="N" | ||||
| 
 | ||||
| if [ -f "$STORAGE/$BASE" ]; then | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										151
									
								
								src/power.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/power.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,151 @@ | |||
| #!/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 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Kroese
						Kroese