94 lines
2.5 KiB
Bash
Executable file
94 lines
2.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# qvm-stop - Gracefully shut down the QEMU VM
|
|
#
|
|
# This script stops the running VM by sending SIGTERM first for graceful
|
|
# shutdown, waiting up to 30 seconds, then sending SIGKILL if necessary.
|
|
# It cleans up state files (vm.pid, ssh.port) after shutdown completes.
|
|
#
|
|
# Usage: qvm stop
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Source common library
|
|
readonly QVM_LIB_DIR="${QVM_LIB_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)}"
|
|
source "${QVM_LIB_DIR}/common.sh"
|
|
|
|
# Timeout for graceful shutdown in seconds
|
|
readonly SHUTDOWN_TIMEOUT=30
|
|
|
|
#
|
|
# wait_for_process_exit - Wait for process to terminate
|
|
# Args: $1 - PID to wait for
|
|
# $2 - timeout in seconds
|
|
# Returns: 0 if process exits, 1 on timeout
|
|
#
|
|
wait_for_process_exit() {
|
|
local pid="$1"
|
|
local timeout="$2"
|
|
local elapsed=0
|
|
|
|
while (( elapsed < timeout )); do
|
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
(( elapsed++ ))
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# main - Main shutdown orchestration
|
|
#
|
|
main() {
|
|
# Check if VM is running
|
|
if ! is_vm_running; then
|
|
log_info "VM is not running"
|
|
exit 0
|
|
fi
|
|
|
|
# Get VM process PID
|
|
local vm_pid
|
|
vm_pid=$(cat "$QVM_PID_FILE")
|
|
|
|
log_info "Shutting down VM (PID: $vm_pid)..."
|
|
|
|
# Send SIGTERM for graceful shutdown
|
|
if kill -TERM "$vm_pid" 2>/dev/null; then
|
|
log_info "Sent SIGTERM, waiting up to ${SHUTDOWN_TIMEOUT}s for graceful shutdown..."
|
|
|
|
if wait_for_process_exit "$vm_pid" "$SHUTDOWN_TIMEOUT"; then
|
|
log_info "VM shut down gracefully"
|
|
else
|
|
log_warn "Graceful shutdown timeout, forcefully terminating..."
|
|
|
|
# Send SIGKILL to force termination
|
|
if kill -KILL "$vm_pid" 2>/dev/null; then
|
|
# Wait briefly to ensure process is dead
|
|
sleep 1
|
|
|
|
# Verify process is actually dead
|
|
if kill -0 "$vm_pid" 2>/dev/null; then
|
|
die "Failed to kill VM process $vm_pid"
|
|
fi
|
|
|
|
log_info "VM forcefully terminated"
|
|
else
|
|
log_warn "Process $vm_pid already terminated"
|
|
fi
|
|
fi
|
|
else
|
|
log_warn "Process $vm_pid already terminated (could not send SIGTERM)"
|
|
fi
|
|
|
|
# Clean up state files
|
|
log_info "Cleaning up state files..."
|
|
rm -f "$QVM_PID_FILE" "$QVM_SSH_PORT_FILE"
|
|
|
|
log_info "VM stopped successfully"
|
|
}
|
|
|
|
main "$@"
|