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:
+26
-12
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user