2023-04-02 21:38:34 +02:00
|
|
|
|
#!/usr/bin/env bash
|
2023-05-03 19:00:36 +02:00
|
|
|
|
set -Eeuo pipefail
|
2023-04-02 21:38:34 +02:00
|
|
|
|
|
|
|
|
|
# Configure QEMU for graceful shutdown
|
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
API_CMD=6
|
|
|
|
|
API_TIMEOUT=50
|
|
|
|
|
API_HOST="127.0.0.1:2210"
|
|
|
|
|
|
2023-12-28 16:08:12 +01:00
|
|
|
|
QEMU_TERM=""
|
2023-11-15 19:58:51 +01:00
|
|
|
|
QEMU_PORT=7100
|
2023-12-28 03:42:06 +01:00
|
|
|
|
QEMU_TIMEOUT=50
|
2024-01-13 20:25:57 +01:00
|
|
|
|
QEMU_PID="/run/shm/qemu.pid"
|
|
|
|
|
QEMU_LOG="/run/shm/qemu.log"
|
|
|
|
|
QEMU_OUT="/run/shm/qemu.out"
|
|
|
|
|
QEMU_END="/run/shm/qemu.end"
|
2023-04-02 21:38:34 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
if [[ "$KVM" == [Nn]* ]]; then
|
|
|
|
|
API_TIMEOUT=$(( API_TIMEOUT*2 ))
|
|
|
|
|
QEMU_TIMEOUT=$(( QEMU_TIMEOUT*2 ))
|
|
|
|
|
fi
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
touch "$QEMU_LOG"
|
2023-04-14 15:34:09 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
_trap() {
|
|
|
|
|
func="$1" ; shift
|
|
|
|
|
for sig ; do
|
|
|
|
|
trap "$func $sig" "$sig"
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finish() {
|
|
|
|
|
|
|
|
|
|
local pid
|
|
|
|
|
local reason=$1
|
|
|
|
|
|
|
|
|
|
if [ -f "$QEMU_PID" ]; then
|
|
|
|
|
|
|
|
|
|
pid="$(cat "$QEMU_PID")"
|
2023-12-28 05:26:53 +01:00
|
|
|
|
echo && error "Forcefully terminating QEMU process, reason: $reason..."
|
2023-12-28 03:42:06 +01:00
|
|
|
|
{ kill -15 "$pid" || true; } 2>/dev/null
|
|
|
|
|
|
|
|
|
|
while isAlive "$pid"; do
|
|
|
|
|
sleep 1
|
|
|
|
|
# Workaround for zombie pid
|
|
|
|
|
[ ! -f "$QEMU_PID" ] && break
|
2023-04-10 21:05:34 +02:00
|
|
|
|
done
|
2023-12-28 03:42:06 +01:00
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
fKill "print.sh"
|
|
|
|
|
fKill "host.bin"
|
|
|
|
|
|
|
|
|
|
closeNetwork
|
|
|
|
|
|
|
|
|
|
sleep 1
|
2023-12-28 05:26:53 +01:00
|
|
|
|
echo && echo "❯ Shutdown completed!"
|
2023-12-28 03:42:06 +01:00
|
|
|
|
|
|
|
|
|
exit "$reason"
|
2023-04-10 21:05:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 16:08:12 +01:00
|
|
|
|
terminal() {
|
|
|
|
|
|
2024-01-13 18:16:17 +01:00
|
|
|
|
local dev=""
|
2023-12-28 16:08:12 +01:00
|
|
|
|
|
2024-01-13 18:16:17 +01:00
|
|
|
|
if [ -f "$QEMU_OUT" ]; then
|
|
|
|
|
|
|
|
|
|
local msg
|
|
|
|
|
msg="$(cat "$QEMU_OUT")"
|
|
|
|
|
|
|
|
|
|
if [ -n "$msg" ]; then
|
2023-12-28 16:08:12 +01:00
|
|
|
|
|
2024-01-13 18:16:17 +01:00
|
|
|
|
if [[ "${msg,,}" != "char"* || "$msg" != *"serial0)" ]]; then
|
|
|
|
|
echo "$msg"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
dev="${msg#*/dev/p}"
|
|
|
|
|
dev="/dev/p${dev%% *}"
|
|
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
fi
|
2023-12-28 16:08:12 +01:00
|
|
|
|
|
|
|
|
|
if [ ! -c "$dev" ]; then
|
|
|
|
|
dev=$(echo 'info chardev' | nc -q 1 -w 1 localhost "$QEMU_PORT" | tr -d '\000')
|
2023-12-29 18:15:39 +01:00
|
|
|
|
dev="${dev#*serial0}"
|
2023-12-28 16:08:12 +01:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-21 18:23:25 +02:00
|
|
|
|
_graceful_shutdown() {
|
2023-04-02 21:38:34 +02:00
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
local cnt=0
|
2023-12-28 03:42:06 +01:00
|
|
|
|
local code=$?
|
2023-12-28 17:58:07 +01:00
|
|
|
|
local pid url response
|
2023-04-28 23:21:36 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
set +e
|
2023-12-28 05:04:40 +01:00
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
if [ -f "$QEMU_END" ]; then
|
|
|
|
|
echo && info "Received $1 signal while already shutting down..."
|
2023-12-28 05:04:40 +01:00
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
touch "$QEMU_END"
|
2023-12-10 15:58:37 +01:00
|
|
|
|
echo && info "Received $1 signal, sending shutdown command..."
|
2023-04-10 21:05:34 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
if [ ! -f "$QEMU_PID" ]; then
|
|
|
|
|
echo && error "QEMU PID file does not exist?"
|
|
|
|
|
finish "$code" && return "$code"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
pid="$(cat "$QEMU_PID")"
|
|
|
|
|
|
|
|
|
|
if ! isAlive "$pid"; then
|
|
|
|
|
echo && error "QEMU process does not exist?"
|
|
|
|
|
finish "$code" && return "$code"
|
|
|
|
|
fi
|
|
|
|
|
|
2023-04-11 20:29:09 +02:00
|
|
|
|
# Don't send the powerdown signal because vDSM ignores ACPI signals
|
2023-11-15 19:58:51 +01:00
|
|
|
|
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null
|
2023-04-02 21:38:34 +02:00
|
|
|
|
|
2023-05-05 17:24:06 +02:00
|
|
|
|
# Send shutdown command to guest agent via serial port
|
2023-12-28 03:42:06 +01:00
|
|
|
|
url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT"
|
|
|
|
|
response=$(curl -sk -m "$(( API_TIMEOUT+2 ))" -S "$url" 2>&1)
|
2023-04-11 20:29:09 +02:00
|
|
|
|
|
2023-12-10 15:58:37 +01:00
|
|
|
|
if [[ "$response" =~ "\"success\"" ]]; then
|
2023-04-11 20:29:09 +02:00
|
|
|
|
|
2023-12-10 15:58:37 +01:00
|
|
|
|
echo && info "Virtual DSM is now ready to shutdown..."
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
|
|
response="${response#*message\"\: \"}"
|
2023-12-28 03:42:06 +01:00
|
|
|
|
[ -z "$response" ] && response="second signal"
|
2023-12-28 05:26:53 +01:00
|
|
|
|
echo && error "Forcefully terminating because of: ${response%%\"*}"
|
2023-12-28 03:42:06 +01:00
|
|
|
|
{ kill -15 "$pid" || true; } 2>/dev/null
|
2023-10-17 19:24:42 +02:00
|
|
|
|
|
2023-04-10 21:05:34 +02:00
|
|
|
|
fi
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do
|
2023-04-10 21:05:34 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
! isAlive "$pid" && break
|
|
|
|
|
|
|
|
|
|
sleep 1
|
2023-12-28 17:58:07 +01:00
|
|
|
|
cnt=$((cnt+1))
|
2023-04-10 21:05:34 +02:00
|
|
|
|
|
2023-12-20 12:09:25 +01:00
|
|
|
|
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
|
2023-04-17 05:13:46 +02:00
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
# Workaround for zombie pid
|
|
|
|
|
[ ! -f "$QEMU_PID" ] && break
|
|
|
|
|
|
2023-04-02 21:38:34 +02:00
|
|
|
|
done
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then
|
|
|
|
|
echo && error "Shutdown timeout reached, aborting..."
|
2023-12-19 04:30:01 +01:00
|
|
|
|
fi
|
|
|
|
|
|
2023-12-28 03:42:06 +01:00
|
|
|
|
finish "$code" && return "$code"
|
2023-04-02 21:38:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 16:56:49 +01:00
|
|
|
|
MON_OPTS="\
|
|
|
|
|
-pidfile $QEMU_PID \
|
|
|
|
|
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
if [[ "$CONSOLE" != [Yy]* ]]; then
|
2023-12-29 16:56:49 +01:00
|
|
|
|
|
|
|
|
|
MON_OPTS="$MON_OPTS -daemonize -D $QEMU_LOG"
|
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT
|
2023-12-29 16:56:49 +01:00
|
|
|
|
|
2023-12-28 17:58:07 +01:00
|
|
|
|
fi
|
2023-04-02 21:38:34 +02:00
|
|
|
|
|
2023-12-29 16:56:49 +01:00
|
|
|
|
return 0
|