1
0
réplica de https://github.com/dockur/windows.git synced 2026-06-10 11:59:33 +08:00

feat: Improved start and stop logic (#1758)

Este commit está contenido en:
Kroese
2026-06-04 22:37:18 +02:00
cometido por GitHub
padre bcae867d68
commit 8d2f27bd67
Se han modificado 3 ficheros con 120 adiciones y 138 borrados
+26 -12
Ver fichero
@@ -29,21 +29,35 @@ cd /run
trap - ERR trap - ERR
version=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1 | awk '{ print $NF }') cmd=(qemu-system-x86_64)
version=$("${cmd[@]}" --version | awk 'NR==1 { print $4 }')
info "Booting ${APP}${BOOT_DESC} using QEMU v$version..." info "Booting ${APP}${BOOT_DESC} using QEMU v$version..."
{ qemu-system-x86_64 ${ARGS:+ $ARGS} >"$QEMU_OUT" 2>"$QEMU_LOG"; rc=$?; } || : if [[ "$SHUTDOWN" != [Yy1]* ]]; then
(( rc != 0 )) && error "$(<"$QEMU_LOG")" && exit 15 exec "${cmd[@]}" ${ARGS:+ $ARGS}
fi
terminal pipe="$QEMU_DIR/qemu.pipe"
rm -f "$pipe" && mkfifo "$pipe"
tee "$QEMU_PTY" <"$pipe" |
sed -u \
-e 's/\x1B\[[=0-9;]*[a-z]//gi' \
-e 's/\x1B\x63//g' \
-e 's/\x1B\[[=?]7l//g' \
-e '/^$/d' \
-e 's/\x44\x53\x73//g' \
-e 's/failed to load Boot/skipped Boot/g' \
-e 's/0): Not Found/0)/g' &
"${cmd[@]}" ${ARGS:+ $ARGS} >"$pipe" &
pid=$!
( sleep 30; boot ) & ( sleep 30; boot ) &
tail -fn +0 "$QEMU_LOG" --pid=$$ 2>/dev/null &
cat "$QEMU_TERM" 2> /dev/null | tee "$QEMU_PTY" | \ rc=0
sed -u -e 's/\x1B\[[=0-9;]*[a-z]//gi' \ wait "$pid" || rc=$?
-e 's/\x1B\x63//g' -e 's/\x1B\[[=?]7l//g' \ [ -f "$QEMU_END" ] && exit "$rc"
-e '/^$/d' -e 's/\x44\x53\x73//g' \
-e 's/failed to load Boot/skipped Boot/g' \
-e 's/0): Not Found/0)/g' & wait $! || :
sleep 1 & wait $! sleep 1 & wait $!
[ ! -f "$QEMU_END" ] && finish 0 finish "$rc"
+88 -121
Ver fichero
@@ -1,23 +1,28 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: "${QEMU_TIMEOUT:="110"}" # QEMU Termination timeout : "${SHUTDOWN:="Y"}" # Graceful ACPI shutdown
: "${TIMEOUT:="115"}" # QEMU termination timeout
# Configure QEMU for graceful shutdown # Configure QEMU for graceful shutdown
QEMU_TERM=""
QEMU_PTY="$QEMU_DIR/qemu.pty" QEMU_PTY="$QEMU_DIR/qemu.pty"
QEMU_LOG="$QEMU_DIR/qemu.log"
QEMU_OUT="$QEMU_DIR/qemu.out"
QEMU_END="$QEMU_DIR/qemu.end" QEMU_END="$QEMU_DIR/qemu.end"
_trap() { _trap() {
local func="$1" ; shift local func="$1"; shift
for sig ; do local sig
TRAP_PID=$BASHPID
for sig; do
trap "$func $sig" "$sig" trap "$func $sig" "$sig"
done done
} }
app() {
echo "$APP" && return 0
}
boot() { boot() {
[ -f "$QEMU_END" ] && return 0 [ -f "$QEMU_END" ] && return 0
@@ -30,17 +35,14 @@ boot() {
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && fail="y" grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && fail="y"
fi fi
if [ -z "$fail" ]; then if [ -z "$fail" ]; then
info "Windows started successfully, visit http://127.0.0.1:8006/ to view the screen..." info "$(app) started successfully, visit http://127.0.0.1:8006/ to view the screen..."
return 0 return 0
fi fi
fi fi
fi fi
error "Timeout while waiting for QEMU to boot the machine!" error "Timeout while waiting for QEMU to boot the machine, aborting..."
sKill "$QEMU_PID"
local pid
pid=$(<"$QEMU_PID")
{ kill -15 "$pid" || true; } 2>/dev/null
return 0 return 0
} }
@@ -68,39 +70,29 @@ ready() {
finish() { finish() {
local pid local i=0
local cnt=0 local pid=""
local reason=$1 local reason=$1
local pids=( local pids=( "${SMB_PID:-}" "${NMB_PID:-}" "${DDN_PID:-}" "${TPM_PID:-}" "${WSD_PID:-}" \
"/var/run/tpm.pid" "${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" "${BALLOONING_PID:-}" )
"/var/run/wsdd.pid"
"/var/run/samba/nmbd.pid"
"/var/run/samba/smbd.pid"
)
touch "$QEMU_END" touch "$QEMU_END"
if [ -s "$QEMU_PID" ]; then if [ -s "$QEMU_PID" ]; then
if read -r pid <"$QEMU_PID"; then
pid=$(<"$QEMU_PID") if [ -n "$pid" ] && isAlive "$pid"; then
echo && error "Forcefully terminating Windows, reason: $reason..." local display="$reason"
{ kill -15 "$pid" || true; } 2>/dev/null case "$reason" in
129 ) display="SIGHUP" ;;
while isAlive "$pid"; do 130 ) display="SIGINT" ;;
131 ) display="SIGQUIT" ;;
sleep 1 134 ) display="SIGABRT" ;;
(( cnt++ )) 143 ) display="SIGTERM" ;;
esac
# Workaround for zombie pid error "Forcefully terminating $(app), reason: $display..."
[ ! -s "$QEMU_PID" ] && break { disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null
if [ "$cnt" -eq 5 ]; then
echo && error "QEMU did not terminate itself, forcefully killing process..."
{ kill -9 "$pid" || true; } 2>/dev/null
fi fi
fi
done
fi fi
if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$BOOT" ]; then if [ ! -f "$STORAGE/windows.boot" ] && [ -f "$BOOT" ]; then
@@ -115,131 +107,106 @@ finish() {
fi fi
fi fi
for pid in "${pids[@]}"; do mKill "${pids[@]}"
if [[ -s "$pid" ]]; then
pKill "$(<"$pid")"
fi
rm -f "$pid"
done
closeNetwork closeNetwork
sleep 0.5 if ! waitPidFile "$QEMU_PID" 10; then
echo " Shutdown completed!" warn "Timed out while waiting for $(app) to exit!"
fi
(( reason != 1 )) && echo && echo " Shutdown completed!"
exit "$reason" exit "$reason"
} }
terminal() { graceful_shutdown() {
local dev=""
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 "$MON_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 sig="$1" local sig="$1"
local pid=""
local code=0 local code=0
[[ $BASHPID != "$TRAP_PID" ]] && return
case "$sig" in case "$sig" in
SIGTERM) code=143 ;;
SIGINT) code=130 ;;
SIGHUP) code=129 ;; SIGHUP) code=129 ;;
SIGABRT) code=134 ;; SIGINT) code=130 ;;
SIGQUIT) code=131 ;; SIGQUIT) code=131 ;;
SIGABRT) code=134 ;;
SIGTERM) code=143 ;;
esac esac
if [ -f "$QEMU_END" ]; then if [ -f "$QEMU_END" ]; then
info "Received $1 while already shutting down..." echo && info "Received $1 while already shutting down..."
return return
fi fi
set +e set +e
touch "$QEMU_END" touch "$QEMU_END"
info "Received $1, sending ACPI shutdown signal..." echo && info "Received $1, sending ACPI shutdown signal..."
if [ ! -s "$QEMU_PID" ]; then if [ ! -s "$QEMU_PID" ] || ! read -r pid <"$QEMU_PID"; then
error "QEMU PID file does not exist?" warn "QEMU PID file ($QEMU_PID) does not exist?"
finish "$code" && return "$code" finish "$code"
fi fi
local pid="" if [ -z "$pid" ] || ! isAlive "$pid"; then
pid=$(<"$QEMU_PID") warn "QEMU process with PID $pid does not exist?"
finish "$code"
if ! isAlive "$pid"; then
error "QEMU process does not exist?"
finish "$code" && return "$code"
fi fi
if ! ready; then if ! ready; then
info "Cannot send ACPI signal during Windows setup, aborting..." info "Cannot send ACPI signal during $(app) setup, aborting..."
finish "$code" && return "$code" sKill "$QEMU_PID"
if ! waitPidFile "$QEMU_PID" 5; then
warn "Timed out while waiting for $(app) to exit!"
fi
finish "$code"
fi fi
# Send ACPI shutdown signal local cnt=0 abort=0 factor=3 offset=3 min max name
echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null
local cnt=0 [[ "$TIMEOUT" =~ ^[0-9]+$ ]] || TIMEOUT=115
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do [ "$TIMEOUT" -ge 15 ] && factor=4 && offset=4
[ "$TIMEOUT" -ge 30 ] && factor=5 && offset=5
min=$((factor + offset + 1))
[ "$TIMEOUT" -lt "$min" ] && TIMEOUT="$min"
max=$(( TIMEOUT - offset ))
abort=$(( max - factor ))
name="$(app)"
sleep 1 while [ "$cnt" -le "$max" ]; do
(( cnt++ ))
sleep 1 &
local slp=$!
! isAlive "$pid" && break ! isAlive "$pid" && break
# Workaround for zombie pid # Workaround for zombie pid
[ ! -s "$QEMU_PID" ] && break [ ! -s "$QEMU_PID" ] && break
info "Waiting for Windows to shutdown... ($cnt/$QEMU_TIMEOUT)" if [ "$cnt" -ne "$abort" ]; then
if [ "$cnt" -gt 0 ]; then
info "Waiting for $name to shut down... ($cnt/$max)"
fi
else
info "${name^} is still running, sending SIGTERM... ($cnt/$max)"
{ kill -15 -- "$pid" || :; } 2>/dev/null
fi
# Send ACPI shutdown signal # Send ACPI shutdown signal
echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null if [ -S "$QEMU_DIR/monitor.sock" ]; then
nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || :
fi
wait $slp
(( cnt++ ))
done done
if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then finish "$code"
error "Shutdown timeout reached, aborting..."
fi
finish "$code" && return "$code"
} }
touch "$QEMU_LOG" [[ "$SHUTDOWN" != [Yy1]* ]] && return 0
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
SERIAL="pty" _trap graceful_shutdown SIGTERM SIGHUP SIGABRT SIGQUIT
MONITOR="telnet:localhost:$MON_PORT,server,nowait,nodelay -daemonize -D $QEMU_LOG"
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
return 0 return 0
+6 -5
Ver fichero
@@ -7,9 +7,11 @@ set -Eeuo pipefail
tmp="/tmp/smb" tmp="/tmp/smb"
rm -rf "$tmp" rm -rf "$tmp"
rm -f /var/run/wsdd.pid DDN_PID="/var/run/wsdd.pid"
rm -f /var/run/samba/nmbd.pid NMB_PID="/var/run/samba/nmbd.pid"
rm -f /var/run/samba/smbd.pid SMB_PID="/var/run/samba/smbd.pid"
rm -f "$SMB_PID" "$NMB_PID" "$DDN_PID"
[[ "$SAMBA" == [Nn]* ]] && return 0 [[ "$SAMBA" == [Nn]* ]] && return 0
[[ "$NETWORK" == [Nn]* ]] && return 0 [[ "$NETWORK" == [Nn]* ]] && return 0
@@ -206,10 +208,9 @@ else
# Enable Web Service Discovery on Vista and up # Enable Web Service Discovery on Vista and up
[[ "$DEBUG" == [Yy1]* ]] && echo "Starting wsddn daemon..." [[ "$DEBUG" == [Yy1]* ]] && echo "Starting wsddn daemon..."
rm -f /var/log/wsddn.log rm -f /var/log/wsddn.log
if ! wsddn -i "${interfaces%%,*}" -H "$hostname" --unixd --log-file=/var/log/wsddn.log --pid-file=/var/run/wsdd.pid; then if ! wsddn -i "${interfaces%%,*}" -H "$hostname" --unixd --log-file=/var/log/wsddn.log --pid-file="$DDN_PID"; then
SAMBA_DEBUG="Y" SAMBA_DEBUG="Y"
error "Failed to start wsddn daemon!" error "Failed to start wsddn daemon!"
fi fi