command_stop.sh 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #!/bin/bash
  2. # LinuxGSM command_stop.sh function
  3. # Author: Daniel Gibbs
  4. # Contributors: UltimateByte
  5. # Website: https://linuxgsm.com
  6. # Description: Stops the server.
  7. commandname="STOP"
  8. commandaction="Stopping"
  9. functionselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")"
  10. # Attempts graceful shutdown by sending 'CTRL+c'.
  11. fn_stop_graceful_ctrlc(){
  12. fn_print_dots "Graceful: CTRL+c"
  13. fn_script_log_info "Graceful: CTRL+c"
  14. # Sends quit.
  15. tmux send-keys -t "${selfname}" C-c > /dev/null 2>&1
  16. # Waits up to 30 seconds giving the server time to shutdown gracefuly.
  17. for seconds in {1..30}; do
  18. check_status.sh
  19. if [ "${status}" == "0" ]; then
  20. fn_print_ok "Graceful: CTRL+c: ${seconds}: "
  21. fn_print_ok_eol_nl
  22. fn_script_log_pass "Graceful: CTRL+c: OK: ${seconds} seconds"
  23. break
  24. fi
  25. sleep 1
  26. fn_print_dots "Graceful: CTRL+c: ${seconds}"
  27. done
  28. check_status.sh
  29. if [ "${status}" != "0" ]; then
  30. fn_print_error "Graceful: CTRL+c: "
  31. fn_print_fail_eol_nl
  32. fn_script_log_error "Graceful: CTRL+c: FAIL"
  33. fi
  34. fn_sleep_time
  35. }
  36. # Attempts graceful shutdown by sending a specified command.
  37. # Usage: fn_stop_graceful_cmd "console_command" "timeout_in_seconds"
  38. # e.g.: fn_stop_graceful_cmd "quit" "30"
  39. fn_stop_graceful_cmd(){
  40. fn_print_dots "Graceful: sending \"${1}\""
  41. fn_script_log_info "Graceful: sending \"${1}\""
  42. # Sends specific stop command.
  43. tmux send -t "${selfname}" "${1}" ENTER > /dev/null 2>&1
  44. # Waits up to ${seconds} seconds giving the server time to shutdown gracefully.
  45. for ((seconds=1; seconds<=${2}; seconds++)); do
  46. check_status.sh
  47. if [ "${status}" == "0" ]; then
  48. fn_print_ok "Graceful: sending \"${1}\": ${seconds}: "
  49. fn_print_ok_eol_nl
  50. fn_script_log_pass "Graceful: sending \"${1}\": OK: ${seconds} seconds"
  51. break
  52. fi
  53. sleep 1
  54. fn_print_dots "Graceful: sending \"${1}\": ${seconds}"
  55. done
  56. check_status.sh
  57. if [ "${status}" != "0" ]; then
  58. fn_print_error "Graceful: sending \"${1}\": "
  59. fn_print_fail_eol_nl
  60. fn_script_log_error "Graceful: sending \"${1}\": FAIL"
  61. fi
  62. fn_sleep_time
  63. }
  64. # Attempts graceful shutdown of goldsrc using rcon 'quit' command.
  65. # There is only a 3 second delay before a forced a tmux shutdown
  66. # as GoldSrc servers 'quit' command does a restart rather than shutdown.
  67. fn_stop_graceful_goldsrc(){
  68. fn_print_dots "Graceful: sending \"quit\""
  69. fn_script_log_info "Graceful: sending \"quit\""
  70. # sends quit
  71. tmux send -t "${selfname}" quit ENTER > /dev/null 2>&1
  72. # Waits 3 seconds as goldsrc servers restart with the quit command.
  73. for seconds in {1..3}; do
  74. sleep 1
  75. fn_print_dots "Graceful: sending \"quit\": ${seconds}"
  76. done
  77. fn_print_ok "Graceful: sending \"quit\": ${seconds}: "
  78. fn_print_ok_eol_nl
  79. fn_script_log_pass "Graceful: sending \"quit\": OK: ${seconds} seconds"
  80. }
  81. # telnet command for sdtd graceful shutdown.
  82. fn_stop_graceful_sdtd_telnet(){
  83. if [ -z "${telnetpass}" ]||[ "${telnetpass}" == "NOT SET" ]; then
  84. sdtd_telnet_shutdown=$( expect -c '
  85. proc abort {} {
  86. puts "Timeout or EOF\n"
  87. exit 1
  88. }
  89. spawn telnet '"${telnetip}"' '"${telnetport}"'
  90. expect {
  91. "session." { send "shutdown\r" }
  92. default abort
  93. }
  94. expect { eof }
  95. puts "Completed.\n"
  96. ')
  97. else
  98. sdtd_telnet_shutdown=$( expect -c '
  99. proc abort {} {
  100. puts "Timeout or EOF\n"
  101. exit 1
  102. }
  103. spawn telnet '"${telnetip}"' '"${telnetport}"'
  104. expect {
  105. "password:" { send "'"${telnetpass}"'\r" }
  106. default abort
  107. }
  108. expect {
  109. "session." { send "shutdown\r" }
  110. default abort
  111. }
  112. expect { eof }
  113. puts "Completed.\n"
  114. ')
  115. fi
  116. }
  117. # Attempts graceful shutdown of 7 Days To Die using telnet.
  118. fn_stop_graceful_sdtd(){
  119. fn_print_dots "Graceful: telnet"
  120. fn_script_log_info "Graceful: telnet"
  121. if [ "${telnetenabled}" == "false" ]; then
  122. fn_print_info_nl "Graceful: telnet: DISABLED: Enable in ${servercfg}"
  123. elif [ "$(command -v expect 2>/dev/null)" ]; then
  124. # Tries to shutdown with both localhost and server IP.
  125. for telnetip in 127.0.0.1 ${ip}; do
  126. fn_print_dots "Graceful: telnet: ${telnetip}:${telnetport}"
  127. fn_script_log_info "Graceful: telnet: ${telnetip}:${telnetport}"
  128. fn_stop_graceful_sdtd_telnet
  129. completed=$(echo -en "\n ${sdtd_telnet_shutdown}" | grep "Completed.")
  130. refused=$(echo -en "\n ${sdtd_telnet_shutdown}" | grep "Timeout or EOF")
  131. if [ "${refused}" ]; then
  132. fn_print_error "Graceful: telnet: ${telnetip}:${telnetport} : "
  133. fn_print_fail_eol_nl
  134. fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL"
  135. elif [ "${completed}" ]; then
  136. break
  137. fi
  138. done
  139. # If telnet shutdown was successful will use telnet again to check
  140. # the connection has closed, confirming that the tmux session can now be killed.
  141. if [ "${completed}" ]; then
  142. for seconds in {1..30}; do
  143. fn_stop_graceful_sdtd_telnet
  144. refused=$(echo -en "\n ${sdtd_telnet_shutdown}" | grep "Timeout or EOF")
  145. if [ "${refused}" ]; then
  146. fn_print_ok "Graceful: telnet: ${telnetip}:${telnetport} : "
  147. fn_print_ok_eol_nl
  148. fn_script_log_pass "Graceful: telnet: ${telnetip}:${telnetport} : ${seconds} seconds"
  149. break
  150. fi
  151. sleep 1
  152. fn_print_dots "Graceful: telnet: ${seconds}"
  153. done
  154. # If telnet shutdown fails tmux shutdown will be used, this risks loss of world save.
  155. else
  156. if [ "${refused}" ]; then
  157. fn_print_error "Graceful: telnet: "
  158. fn_print_fail_eol_nl
  159. fn_script_log_error "Graceful: telnet: ${telnetip}:${telnetport} : FAIL"
  160. else
  161. fn_print_error_nl "Graceful: telnet: Unknown error"
  162. fn_script_log_error "Graceful: telnet: Unknown error"
  163. fi
  164. echo -en "\n" | tee -a "${lgsmlog}"
  165. echo -en "Telnet output:" | tee -a "${lgsmlog}"
  166. echo -en "\n ${sdtd_telnet_shutdown}" | tee -a "${lgsmlog}"
  167. echo -en "\n\n" | tee -a "${lgsmlog}"
  168. fi
  169. else
  170. fn_print_warn "Graceful: telnet: expect not installed: "
  171. fn_print_fail_eol_nl
  172. fn_script_log_warn "Graceful: telnet: expect not installed: FAIL"
  173. fi
  174. fn_sleep_time
  175. }
  176. # Attempts graceful shutdown by sending /save /stop.
  177. fn_stop_graceful_avorion(){
  178. fn_print_dots "Graceful: /save /stop"
  179. fn_script_log_info "Graceful: /save /stop"
  180. # Sends /save.
  181. tmux send-keys -t "${selfname}" /save ENTER > /dev/null 2>&1
  182. sleep 5
  183. # Sends /quit.
  184. tmux send-keys -t "${selfname}" /stop ENTER > /dev/null 2>&1
  185. # Waits up to 30 seconds giving the server time to shutdown gracefuly.
  186. for seconds in {1..30}; do
  187. check_status.sh
  188. if [ "${status}" == "0" ]; then
  189. fn_print_ok "Graceful: /save /stop: ${seconds}: "
  190. fn_print_ok_eol_nl
  191. fn_script_log_pass "Graceful: /save /stop: OK: ${seconds} seconds"
  192. break
  193. fi
  194. sleep 1
  195. fn_print_dots "Graceful: /save /stop: ${seconds}"
  196. done
  197. check_status.sh
  198. if [ "${status}" != "0" ]; then
  199. fn_print_error "Graceful: /save /stop: "
  200. fn_print_fail_eol_nl
  201. fn_script_log_error "Graceful: /save /stop: FAIL"
  202. fi
  203. fn_sleep_time
  204. }
  205. fn_stop_graceful_select(){
  206. if [ "${stopmode}" == "1" ]; then
  207. fn_stop_tmux
  208. elif [ "${stopmode}" == "2" ]; then
  209. fn_stop_graceful_ctrlc
  210. elif [ "${stopmode}" == "3" ]; then
  211. fn_stop_graceful_cmd "quit" 30
  212. elif [ "${stopmode}" == "4" ]; then
  213. fn_stop_graceful_cmd "quit" 120
  214. elif [ "${stopmode}" == "5" ]; then
  215. fn_stop_graceful_cmd "stop" 30
  216. elif [ "${stopmode}" == "6" ]; then
  217. fn_stop_graceful_cmd "q" 30
  218. elif [ "${stopmode}" == "7" ]; then
  219. fn_stop_graceful_cmd "exit" 30
  220. elif [ "${stopmode}" == "8" ]; then
  221. fn_stop_graceful_sdtd
  222. elif [ "${stopmode}" == "9" ]; then
  223. fn_stop_graceful_goldsrc
  224. elif [ "${stopmode}" == "10" ]; then
  225. fn_stop_graceful_avorion
  226. fi
  227. }
  228. fn_stop_tmux(){
  229. fn_print_dots "${servername}"
  230. fn_script_log_info "tmux kill-session: ${servername}"
  231. # Kill tmux session.
  232. tmux kill-session -t "${selfname}" > /dev/null 2>&1
  233. fn_sleep_time
  234. check_status.sh
  235. if [ "${status}" == "0" ]; then
  236. fn_print_ok_nl "${servername}"
  237. fn_script_log_pass "Stopped ${servername}"
  238. else
  239. fn_print_fail_nl "Unable to stop ${servername}"
  240. fn_script_log_fatal "Unable to stop ${servername}"
  241. fi
  242. }
  243. # Checks if the server is already stopped.
  244. fn_stop_pre_check(){
  245. if [ "${status}" == "0" ]; then
  246. fn_print_info_nl "${servername} is already stopped"
  247. fn_script_log_error "${servername} is already stopped"
  248. else
  249. # Select graceful shutdown.
  250. fn_stop_graceful_select
  251. fi
  252. # Check status again, a kill tmux session if graceful shutdown failed.
  253. check_status.sh
  254. if [ "${status}" != "0" ]; then
  255. fn_stop_tmux
  256. fi
  257. }
  258. check.sh
  259. fn_print_dots "${servername}"
  260. info_config.sh
  261. fn_stop_pre_check
  262. # Remove lockfile.
  263. if [ -f "${lockdir}/${selfname}.lock" ]; then
  264. rm -f "${lockdir:?}/${selfname}.lock"
  265. fi
  266. if [ -z "${exitbypass}" ]; then
  267. core_exit.sh
  268. fi