Loading src/power.sh +68 −51 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ set -Eeuo pipefail : "${SHUTDOWN:="Y"}" # Graceful ACPI shutdown : "${TIMEOUT:="115"}" # QEMU termination timeout : "${API_TIMEOUT:="100"}" # Single API call timeout : "${API_TIMEOUT:="90"}" # External API call timeout # Configure QEMU for graceful shutdown Loading @@ -24,86 +24,89 @@ _trap() { done } app() { echo "$APP" && return 0 } finish() { local pid local cnt=0 local i=0 local pid="" local reason=$1 local pids=( "${HOST_PID:-}" "${WSD_PID:-}" \ "${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" ) touch "$QEMU_END" if [ -s "$QEMU_PID" ]; then pid=$(<"$QEMU_PID") echo && error "Forcefully terminating Virtual DSM, reason: $reason..." { kill -15 "$pid" || true; } 2>/dev/null while isAlive "$pid"; do sleep 1 (( cnt++ )) # Workaround for zombie pid [ ! -s "$QEMU_PID" ] && break if [ "$cnt" -eq 5 ]; then echo && error "QEMU did not terminate itself, forcefully killing process..." { kill -9 "$pid" || true; } 2>/dev/null if read -r pid <"$QEMU_PID"; then if [ -n "$pid" ] && isAlive "$pid"; then local display="$reason" case "$reason" in 129 ) display="SIGHUP" ;; 130 ) display="SIGINT" ;; 131 ) display="SIGQUIT" ;; 134 ) display="SIGABRT" ;; 143 ) display="SIGTERM" ;; esac error "Forcefully terminating $(app), reason: $display..." { disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null fi fi done fi mKill "${pids[@]}" fKill "print.sh" fKill "host.bin" closeNetwork sleep 1 echo && echo "❯ Shutdown completed!" if ! waitPidFile "$QEMU_PID" 10; then warn "Timed out while waiting for $(app) to exit!" fi (( reason != 1 )) && echo && echo "❯ Shutdown completed!" exit "$reason" } graceful_shutdown() { local sig="$1" local pid="" local code=0 local pid url response local start url response elapsed [[ $BASHPID != "$TRAP_PID" ]] && return case "$sig" in SIGTERM) code=143 ;; SIGINT) code=130 ;; SIGHUP) code=129 ;; SIGABRT) code=134 ;; SIGINT) code=130 ;; SIGQUIT) code=131 ;; SIGABRT) code=134 ;; SIGTERM) code=143 ;; esac if [ -f "$QEMU_END" ]; then echo && info "Received $1 signal while already shutting down..." echo && info "Received $1 while already shutting down..." return fi set +e start=$SECONDS touch "$QEMU_END" echo && info "Received $1 signal, sending shutdown command..." if [ ! -s "$QEMU_PID" ]; then echo && error "QEMU PID file does not exist?" finish "$code" && return "$code" if [ ! -s "$QEMU_PID" ] || ! read -r pid <"$QEMU_PID"; then warn "QEMU PID file ($QEMU_PID) does not exist?" finish "$code" fi pid=$(<"$QEMU_PID") if ! isAlive "$pid"; then echo && error "QEMU process does not exist?" finish "$code" && return "$code" if [ -z "$pid" ] || ! isAlive "$pid"; then warn "QEMU process with PID $pid does not exist?" finish "$code" fi # Don't send the powerdown signal because vDSM ignores ACPI signals # echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null # nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || : # Send shutdown command to guest agent via serial port url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT" Loading @@ -118,31 +121,45 @@ graceful_shutdown() { response="${response#*message\"\: \"}" [ -z "$response" ] && response="second signal" echo && error "Forcefully terminating because of: ${response%%\"*}" { kill -15 "$pid" || true; } 2>/dev/null { kill -15 -- "$pid" || :; } 2>/dev/null fi local cnt=0 local cnt=0 offset=3 min max name while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do [[ "$TIMEOUT" =~ ^[0-9]+$ ]] || TIMEOUT=115 [ "$TIMEOUT" -ge 15 ] && offset=4 [ "$TIMEOUT" -ge 30 ] && offset=5 min=$((offset + 1)) [ "$TIMEOUT" -lt "$min" ] && TIMEOUT="$min" elapsed=$(( $SECONDS - $start )) max=$(( TIMEOUT - offset - elapsed )) [ "$max" -lt 1 ] && max=1 name="$(app)" ! isAlive "$pid" && break while [ "$cnt" -le "$max" ]; do sleep 1 (( cnt++ )) [[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)" sleep 1 & local slp=$! ! isAlive "$pid" && break # Workaround for zombie pid [ ! -s "$QEMU_PID" ] && break if [ "$cnt" -gt 0 ]; then [[ "$DEBUG" == [Yy1]* ]] && info "Waiting for $name to shut down... ($cnt/$max)" fi wait $slp (( cnt++ )) done if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then if [ "$cnt" -ge "$max" ]; then echo && error "Shutdown timeout reached, aborting..." fi finish "$code" && return "$code" finish "$code" } [[ "$SHUTDOWN" != [Yy1]* ]] && return 0 Loading Loading
src/power.sh +68 −51 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ set -Eeuo pipefail : "${SHUTDOWN:="Y"}" # Graceful ACPI shutdown : "${TIMEOUT:="115"}" # QEMU termination timeout : "${API_TIMEOUT:="100"}" # Single API call timeout : "${API_TIMEOUT:="90"}" # External API call timeout # Configure QEMU for graceful shutdown Loading @@ -24,86 +24,89 @@ _trap() { done } app() { echo "$APP" && return 0 } finish() { local pid local cnt=0 local i=0 local pid="" local reason=$1 local pids=( "${HOST_PID:-}" "${WSD_PID:-}" \ "${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" ) touch "$QEMU_END" if [ -s "$QEMU_PID" ]; then pid=$(<"$QEMU_PID") echo && error "Forcefully terminating Virtual DSM, reason: $reason..." { kill -15 "$pid" || true; } 2>/dev/null while isAlive "$pid"; do sleep 1 (( cnt++ )) # Workaround for zombie pid [ ! -s "$QEMU_PID" ] && break if [ "$cnt" -eq 5 ]; then echo && error "QEMU did not terminate itself, forcefully killing process..." { kill -9 "$pid" || true; } 2>/dev/null if read -r pid <"$QEMU_PID"; then if [ -n "$pid" ] && isAlive "$pid"; then local display="$reason" case "$reason" in 129 ) display="SIGHUP" ;; 130 ) display="SIGINT" ;; 131 ) display="SIGQUIT" ;; 134 ) display="SIGABRT" ;; 143 ) display="SIGTERM" ;; esac error "Forcefully terminating $(app), reason: $display..." { disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null fi fi done fi mKill "${pids[@]}" fKill "print.sh" fKill "host.bin" closeNetwork sleep 1 echo && echo "❯ Shutdown completed!" if ! waitPidFile "$QEMU_PID" 10; then warn "Timed out while waiting for $(app) to exit!" fi (( reason != 1 )) && echo && echo "❯ Shutdown completed!" exit "$reason" } graceful_shutdown() { local sig="$1" local pid="" local code=0 local pid url response local start url response elapsed [[ $BASHPID != "$TRAP_PID" ]] && return case "$sig" in SIGTERM) code=143 ;; SIGINT) code=130 ;; SIGHUP) code=129 ;; SIGABRT) code=134 ;; SIGINT) code=130 ;; SIGQUIT) code=131 ;; SIGABRT) code=134 ;; SIGTERM) code=143 ;; esac if [ -f "$QEMU_END" ]; then echo && info "Received $1 signal while already shutting down..." echo && info "Received $1 while already shutting down..." return fi set +e start=$SECONDS touch "$QEMU_END" echo && info "Received $1 signal, sending shutdown command..." if [ ! -s "$QEMU_PID" ]; then echo && error "QEMU PID file does not exist?" finish "$code" && return "$code" if [ ! -s "$QEMU_PID" ] || ! read -r pid <"$QEMU_PID"; then warn "QEMU PID file ($QEMU_PID) does not exist?" finish "$code" fi pid=$(<"$QEMU_PID") if ! isAlive "$pid"; then echo && error "QEMU process does not exist?" finish "$code" && return "$code" if [ -z "$pid" ] || ! isAlive "$pid"; then warn "QEMU process with PID $pid does not exist?" finish "$code" fi # Don't send the powerdown signal because vDSM ignores ACPI signals # echo 'system_powerdown' | nc -q 1 -w 1 localhost "$MON_PORT" > /dev/null # nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || : # Send shutdown command to guest agent via serial port url="http://$API_HOST/read?command=$API_CMD&timeout=$API_TIMEOUT" Loading @@ -118,31 +121,45 @@ graceful_shutdown() { response="${response#*message\"\: \"}" [ -z "$response" ] && response="second signal" echo && error "Forcefully terminating because of: ${response%%\"*}" { kill -15 "$pid" || true; } 2>/dev/null { kill -15 -- "$pid" || :; } 2>/dev/null fi local cnt=0 local cnt=0 offset=3 min max name while [ "$cnt" -lt "$QEMU_TIMEOUT" ]; do [[ "$TIMEOUT" =~ ^[0-9]+$ ]] || TIMEOUT=115 [ "$TIMEOUT" -ge 15 ] && offset=4 [ "$TIMEOUT" -ge 30 ] && offset=5 min=$((offset + 1)) [ "$TIMEOUT" -lt "$min" ] && TIMEOUT="$min" elapsed=$(( $SECONDS - $start )) max=$(( TIMEOUT - offset - elapsed )) [ "$max" -lt 1 ] && max=1 name="$(app)" ! isAlive "$pid" && break while [ "$cnt" -le "$max" ]; do sleep 1 (( cnt++ )) [[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)" sleep 1 & local slp=$! ! isAlive "$pid" && break # Workaround for zombie pid [ ! -s "$QEMU_PID" ] && break if [ "$cnt" -gt 0 ]; then [[ "$DEBUG" == [Yy1]* ]] && info "Waiting for $name to shut down... ($cnt/$max)" fi wait $slp (( cnt++ )) done if [ "$cnt" -ge "$QEMU_TIMEOUT" ]; then if [ "$cnt" -ge "$max" ]; then echo && error "Shutdown timeout reached, aborting..." fi finish "$code" && return "$code" finish "$code" } [[ "$SHUTDOWN" != [Yy1]* ]] && return 0 Loading