Unverified Commit a2b024b1 authored by Kroese's avatar Kroese Committed by GitHub
Browse files

Update power.sh

parent fa20990b
Loading
Loading
Loading
Loading
+68 −51
Original line number Diff line number Diff line
@@ -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

@@ -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"
@@ -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