Linux/Debian - Proper start/stop script (BASH)


Recommended Posts

Greetings everyone,

I recently created a kind-of "proper" bash script which I use to start/stop/update my Don't Starve Together dedicated server and I wanted to share it with the rest of you. There some additional features. For example, you can pass commands to the server and there is a verification function which will check some basic settings before continuing. There are probably some bugs and there's probably people out there who know more about this than I do, so by all means: If you have suggestions/criticism -> I'm all ears (no, seriously, I am). Also, don't let my name fool you. This script is clean and won't install malware or whatever ;).

#!/bin/sh

### BEGIN INIT INFO
# Provides:				dst_server
# Required-Start:		$local_fs $network $remote_fs
# Required-Stop:		$local_fs $network $remote_fs
# Should-Start:			$network
# Should-Stop:			$network
# Default-Start:		3 4 5
# Default-Stop:			0 1 2 6
# Short-Description:	Don't Starve Together Dedicated Server
# Description:			Starts the Don't Starve Together Dedicated Server
### END INIT INFO

################################################################################
#    HOW TO INSTALL THIS SCRIPT?                                               #
#     1. Copy the contents of this script and run commands:                    #
#     2. echo "" > /etc/init.d/start_dst_server                                #
#     3. nano /etc/init.d/start_dst_server                                     #
#     4. chown root /etc/init.d/start_dst_server                               #
#     5. chgrp root /etc/init.d/start_dst_server                               #
#     6. Right click to paste. CTRL + O to write, CTRL + X to quit.            #
#     7. chmod +x /etc/init.d/start_dst_server; exit                           #
#     8. update-rc.d start_dst_server defaults                                 #
#                                                                              #
################################################################################

################################################################################
#    OPTIONAL: CRONTAB:                                                        #
#0 7 * * *       /etc/init.d/start_dst_server restart --force > /dev/null 2>&1 #
#                                                                              #
################################################################################

################################################################################
#    CONFIGURATION: Needs to be completed by the person managing the server.   #
################################################################################

# What user account should be used to run the dedicated server?
RUN_AS_USER="steam"
# What's the location of steam?
STEAM_PATH="/home/steam"
# What's the location of Don't Starve Together?
GAME_PATH="/home/steam/steamapps/DST"
# What's the location of the binary file?
BIN_FILE_PATH="/home/steam/steamapps/DST/bin"
# What's the name of the binary file?
BIN_FILE_NAME="dontstarve_dedicated_server_nullrenderer"
# What's the name of the cluster?
DST_CLUSTER_NAME="Cluster_1"
# What's the name of the overworld?
DST_SHARD_MASTER_NAME="Master"
# What's the name of the cave? (Optional: Leave empty if you don't use caves).
DST_SHARD_CAVE_NAME="Caves"
# Additional arguments for the overworld (Optional).
RUN_ARGUMENTS_MASTER="-threaded_render -threaded_physics"
# Additional arguments for the cave (Optional).
RUN_ARGUMENTS_CAVE="-threaded_render -threaded_physics"


################################################################################
#                   SETTINGS: Don't touch these please!                        #
################################################################################

HUMAN_READIBLE_NAME="Dont Starve Together"
BIN_FILE="${BIN_FILE_PATH}/${BIN_FILE_NAME}"
RUN_ARGUMENTS="-console -cluster ${DST_CLUSTER_NAME} -shard"
if [ -n "${RUN_ARGUMENTS_MASTER}" ]; then RUN_ARGUMENTS_MASTER="${RUN_ARGUMENTS} ${DST_SHARD_MASTER_NAME} ${RUN_ARGUMENTS_MASTER}"; else RUN_ARGUMENTS_MASTER="${RUN_ARGUMENTS} ${DST_SHARD_MASTER_NAME}"; fi
if [ -n "${RUN_ARGUMENTS_CAVE}" ]; then RUN_ARGUMENTS_CAVE="${RUN_ARGUMENTS} ${DST_SHARD_CAVE_NAME} ${RUN_ARGUMENTS_CAVE}"; else RUN_ARGUMENTS_CAVE="${RUN_ARGUMENTS} ${DST_SHARD_CAVE_NAME}"; fi
SCREEN_MASTER_REFERENCE="DST_M"
SCREEN_CAVE_REFERENCE="DST_C"
STOP_TIMEOUT=60 # Maximum time to wait for server to stop. Recommended value: 60
KILL_TIMEOUT=10 # Maximum time to wait for server to stop after kill command. Recommended value: 10
START_TIMEOUT=30 # Maximum time to wait for server to start. Recommended value: 30
FORCE_PROCEED=0 # Automatically proceed when prompted (1 for YES, 0 for NO).


################################################################################
#                        TEST: Please Ignore!                                  #
################################################################################

# BIN_FILE_NAME="test.sh"
# BIN_FILE_PATH="/home/steam/steamapps/DST"
# BIN_FILE="${BIN_FILE_PATH}/${BIN_FILE_NAME}"


################################################################################
#   RUN AS USER: This function will run commands with the predefined user.     #
################################################################################

# Run command as the predefined user as configured in the settings above:
as_user() {
	if [ `whoami` = $RUN_AS_USER ] ; then bash -c "$1"; else su - $RUN_AS_USER -c "$1"; fi
}

################################################################################
#   PID FUNCTION: This function will try to retrieve the PID of the process.   #
################################################################################

# This function will return the process IDs of all related, running processes
# of the game.
pid() {
	pid=""
	if [ -n "${1}" ]; then pid=`ps ax | grep -v grep | grep -i SCREEN | grep ${BIN_FILE_NAME} | grep ${1} | awk '{print $1}'`; fi
}


################################################################################
#          STATUS: Checks whether or not the server is running.                #
################################################################################

# Returns 0 if the server is running.
# Returns 1 if the server is not running.
status() {
	pid_of_master=""
	pid_of_cave=""
	pid ${SCREEN_MASTER_REFERENCE} && pid_of_master=${pid}
	pid ${SCREEN_CAVE_REFERENCE} && pid_of_cave=${pid}
	if [ -n "${pid_of_master}" ] || [ -n "${pid_of_cave}" ]; then
		# Correct: Master shard is running, and Cave shard isn't.
		if ([ -n "${pid_of_master}" ] && [ -z "${pid_of_cave}" ]) && [ -z "${DST_SHARD_CAVE_NAME}" ]; then
			return 0
		# Correct: Both Master shard and Cave shard are running.
		elif ([ -n "${pid_of_master}" ] && [ -n "${pid_of_cave}" ]) && [ -n "${DST_SHARD_CAVE_NAME}" ]; then
			return 0
		# Impossible: Cave shard is running, but Master shard isn't.
		# This should have been caught by the "verify" function!
		# If it isn't, then something went horribly wrong!	
		elif [ -z "${pid_of_master}" ] && [ -n "${pid_of_cave}" ]; then
			# Even though this is a SEVERE ERROR, we can't halt the script at this point.
			return 0
		# Anyting else is wrong, but we can't halt the script at this point.
		else
			return 0
		fi
	else
		return 1
	fi
}


################################################################################
#  COMMAND FUNCTION: With this function, you can pass commands to the server.  #
################################################################################

# Sends commands to the active servers.
# A shard can be specified to only send the command to one of the shards.
# Commands themselves MUST be encapsulated with single quotes.
# Example: ./start_dst_server command master 'c_announce("Example")'
command() {
	local command=""
	local shard=""
	if status; then
		if [ -n "${@}" ]; then
			shard=`echo "${@}" | head -n1 | awk '{print $1;}'`
			if [ "${shard}" = "master" ] || [ "${shard}" = "cave" ]; then
				command=`echo "${@}" | cut -d' ' -f2-`
				if [ "${shard}" = "${command}" ]; then command=""; fi
			else
				command=${@}
			fi
			if [ -n "${command}" ]; then
				if ([ -n "${pid_of_master}" ] && [ "${shard}" = "master" ]) || ([ -n "${pid_of_master}" ] && [ "${shard}" != "cave" ]); then
					printf "\tRunning command \"\033[1m${command}\033[0m\" on the Master shard server.\n"
					as_user "screen -S ${SCREEN_MASTER_REFERENCE} -X stuff $'${command}\r'"
				fi
				if ([ -n "${pid_of_cave}" ] && [ "${shard}" = "cave" ]) || ([ -n "${pid_of_cave}" ] && [ "${shard}" != "master" ]); then
					printf "\tRunning command \"\033[1m${command}\033[0m\" on the Cave shard server.\n"
					as_user "screen -S ${SCREEN_CAVE_REFERENCE} -X stuff $'${command}\r'"
				fi
				printf "\n"
			else
				printf "\t\033[1mNo command argument provided for shard \"${shard}\". Please try again.\033[0m\n\n"
			fi
		else
			printf "\t\033[1mNo command argument provided. Please try again.\033[0m\n\n"
		fi
	else
		printf "\t\033[1mUnable to send command \"${command}\". Server hasn't been started yet.\033[0m\n\n"
	fi
}


################################################################################
#   KILL FUNCTION: This function will kill processes securely, if possible.    #
################################################################################

# This function will attempt to kill one or multiple processes.
kill() {
	local pid=""
	# printf %s "$*" | while IFS= read -r line || [ -n "$line" ]; do
		# printf "${line}\n"
	# done
	for pid in ${*}; do
		if ! [ "`echo ${pid} | egrep ^[[:digit:]]+$`" = "" ]; then
			printf "\t\tAttempting to kill process \033[1m${pid}\033[0m ... "
			# Attempt to gracefully kill the process:
			if [ `whoami` = "root" ]; then bash -c "kill -15 ${pid} > /dev/null 2>&1"
			else as_user "kill -15 ${pid} > /dev/null 2>&1"; fi
			local timeout=${KILL_TIMEOUT}
			# Give the process time to finish up:
			while [ `ps -p $pid | wc -l` -gt 1 ] && [ ${timeout} -ne 0 ]; do
				timeout=$((timeout-1)); sleep 1
			done
			# If the above fails, aggressively kill the process:
			if [ `ps -p ${pid} | wc -l` -gt 1 ]; then
				if [ `whoami` = "root" ]; then bash -c "kill -9 ${pid} > /dev/null 2>&1"
				else as_user "kill -9 ${pid} > /dev/null 2>&1"; fi
			fi
			if [ `ps -p ${pid} | wc -l` -gt 1 ]; then printf "\e[1;31mFAILED!\e[0m\n"; else printf "\e[1;32mSUCCESS!\e[0m\n"; as_user "screen -wipe > /dev/null 2>&1"; fi
		else
			printf "\t\e[1;31mERROR\e[0m: Non-numeric process ID \"\033[1m${pid}\033[0m\" was passed to the \"\033[1mkill\033[0m\" function!\n"
		fi
	done
}


################################################################################
# STOP: This function will try to stop the server, without killing the process.#
################################################################################

# This function will try to send a shutdown signal to the running screen
# session. If that isn't possible, it will resort to killing to server
# process instead.
stop() {
	if status; then
		printf "\t\033[1mStopping the server\033[0m ..."
		# Send the shutdown command to the active server & announce the shutdown:
		command 'c_announce("Shutting down the '"${HUMAN_READIBLE_NAME}"' server!")' > /dev/null 2>&1
		command 'c_shutdown(true)' > /dev/null 2>&1
		# Give the server time to shutdown gracefully:
		local timeout=${STOP_TIMEOUT}
		local user_input=""
		while status && [ ${timeout} -ne 0 ]; do
			sleep 1
			if [ $(( ${timeout} % 2 )) -eq 0 ]; then printf "."; fi
			timeout=$((timeout-1))
		done
		# Verify and report the status of the server:
		if status; then
			if [ ${FORCE_PROCEED} -gt 0 ]; then
				user_input="y"
			else
				printf "\e[1;31m FAILED!\e[0m\n\tWould you like to try and kill process instead? (\e[1;37mY\e[0m/N) "
				read user_input
			fi
			if [ "$user_input" != "" ]; then user_input=`echo $user_input | cut -c1`; else user_input="y"; fi
			if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then kill "${pid_of_master} ${pid_of_cave}"; fi
		else printf "\e[1;32m SUCCESS!\e[0m\n"; as_user "screen -wipe > /dev/null 2>&1"; fi
		if status; then printf "\t\e[1;31mFAILED!\e[0m Unable to kill the process! Please try running this script again as \033[1mroot\033[0m!\n\n"; exit 1
		else printf "\t\e[1;32mSUCCESS!\e[0m Stopped the server!\n\n"; fi
	else
		printf "\t\033[1mUnable to stop. Server hasn't been started yet.\033[0m\n\n"
	fi
}

################################################################################
#             START: This function will try to start the server.               #
################################################################################

# This function will try to start the server.
start() {
	if ! status; then
		# update
		printf "\t\033[1mStarting the server\033[0m ..."
		# Attempt to start the Master shard:
		as_user "cd ${BIN_FILE_PATH} && screen -dmS ${SCREEN_MASTER_REFERENCE} ${BIN_FILE} ${RUN_ARGUMENTS_MASTER}"
		# Attempt to start the Cave shard, if the DST_SHARD_CAVE_NAME variable is populated:
		if [ -n "${DST_SHARD_CAVE_NAME}" ]; then as_user "cd ${BIN_FILE_PATH} && screen -dmS ${SCREEN_CAVE_REFERENCE} ${BIN_FILE} ${RUN_ARGUMENTS_CAVE}"; fi
		# Give the process time to start:
		local timeout=${START_TIMEOUT}
		local user_input=""
		while ! status && [ ${timeout} -ne 0 ]; do
			sleep 1
			if [ $(( ${timeout} % 2 )) -eq 0 ]; then printf "."; fi
			timeout=$((timeout-1))
		done
		# Verify and report the status of the server:
		if status; then
			 printf "\e[1;32m SUCCESS!\e[0m\n\n"
		else
			printf "\e[1;31m FAILED!\e[0m\n\tUnable to start the server! Exiting!\n\n"
			exit 1
		fi
	else
		printf "\t\033[1mUnable to start. Server is already running.\033[0m\n\n"
	fi
}


################################################################################
#      VERIFIER: This function will verify the configuration & settings.       #
################################################################################

# This function will verify if the configuration & settings are correct.
# It is rather limited and will not be able to verify klei related settings,
# folders or files!
verify() {
	local error=0
	printf "\n"
	# Verify if the user (RUN_AS_USER) is present on the system:
	if ! getent passwd ${RUN_AS_USER} > /dev/null 2>&1; then printf "\t\e[1;31mERROR\e[0m: The user \"\033[1m${RUN_AS_USER}\033[0m\" was not found on the settings!\n"; error=1; fi
	# Verify if the binary file path (BIN_FILE_PATH) exists:
	if [ ! -d "${BIN_FILE_PATH}" ]; then printf "\t\e[1;31mERROR\e[0m: Directory \"\033[1m${BIN_FILE_PATH}\033[0m\" does not exist!\n"; error=1; fi
	# Verify if the binary file (BIN_FILE) exists:
	if [ ! -s "${BIN_FILE}" ]; then printf "\t\e[1;31mERROR\e[0m: Binary file \"\033[1m${BIN_FILE_NAME}\033[0m\" does not exist!\n"; error=1; fi
	# Verify if SCREEN is installed on the server:
	if [ "$(which screen)" = "" ]; then printf "\t\e[1;31mERROR\e[0m: \"\033[1mSCREEN\033[0m\" is not installed on server! Please run the \"\033[1mapt-get install screen\033[0m\" command!\n"; error=1; fi
	# Notify the user in case errors were found:
	if [ ${error} -ne 0 ]; then printf "\n\t\e[1;31mThe script encountered errors during the verification of the configuration.\n\tPlease open the script a fix the aforementioned errors!\n\tExiting!\e[0m\n\n"; exit 1; fi
	
	local pid_of_master=""
	local pid_of_cave=""
	local user_input=""
	pid ${SCREEN_MASTER_REFERENCE} && pid_of_master=${pid}
	pid ${SCREEN_CAVE_REFERENCE} && pid_of_cave=${pid}
	if [ -n "${pid_of_master}" ] || [ -n "${pid_of_cave}" ]; then
		# Verify if multiple processes are running (which could never be the case, unless a user attempted to start processes manually):
		if [ "$(echo "${pid_of_master}" | sed -re '/^$/d' | wc -l)" -gt 1 ] || [ "$(echo "${pid_of_cave}" | sed -re '/^$/d' | wc -l)" -gt 1 ]; then
			if [ ${FORCE_PROCEED} -gt 0 ]; then
				user_input="y"
			else
				printf "\t\e[1;31mERROR\e[0m: More than one process was found running already!\n\tWould you like to try and kill these processes? (\e[1;37mY\e[0m/N) "
				read user_input
			fi
			if [ "$user_input" != "" ]; then user_input=`echo $user_input | cut -c1`; else user_input="y"; fi
			if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then
				# Kill the processes if the user agrees:
				kill "${pid_of_master} ${pid_of_cave}"
				pid ${SCREEN_MASTER_REFERENCE} && pid_of_master=${pid}
				pid ${SCREEN_CAVE_REFERENCE} && pid_of_cave=${pid}
				# Verify if the processes are still running and notify the user:
				if [ "$(echo "${pid_of_master}" | sed -re '/^$/d' | wc -l)" -gt 1 ] || [ "$(echo "${pid_of_cave}" | sed -re '/^$/d' | wc -l)" -gt 1 ]; then
					printf "\t\e[1;31mFAILED!\e[0m Unable to kill the processes! Please try running this script again as \033[1mroot\033[0m!\n\n"
					exit 1
				else
					printf "\t\e[1;32mSUCCESS!\e[0m Killed all the processes!\n\n"
				fi
			else
				printf "\t\033[1mCannot continue without first killing the processes! Exiting!\033[0m\n\n"
				exit 1
			fi
		# Verify if Cave is running while Master isn't (which could never be the case, unless a user attempted to start processes manually):
		elif [ -z "${pid_of_master}" ] && [ -n "${pid_of_cave}" ]; then
			if [ ${FORCE_PROCEED} -gt 0 ]; then
				user_input="y"
			else
				printf "\t\e[1;31mERROR\e[0m: Found a process for the Cave shard (\033[1m${DST_SHARD_CAVE_NAME}\033[0m), but not for the Master shard (\033[1m${DST_SHARD_MASTER_NAME}\033[0m)!\n\tWould you like to try and stop the Cave shard process? (\e[1;37mY\e[0m/N) "
				read user_input
			fi
			if [ "$user_input" != "" ]; then user_input=`echo $user_input | cut -c1`; else user_input="y"; fi
			if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then
				# Try to stop Cave shard process if the user agrees:
				stop
				pid ${SCREEN_MASTER_REFERENCE} && pid_of_master=${pid}
				pid ${SCREEN_CAVE_REFERENCE} && pid_of_cave=${pid}
				# Verify if the Cave shard process is still running and notify the user:
				if [ -z "${pid_of_master}" ] && [ -n "${pid_of_cave}" ]; then
					printf "\t\e[1;31mFAILED!\e[0m Unable to kill the Cave shard process! Please try running this script again as \033[1mroot\033[0m!\n\n"
					exit 1
				else
					printf "\t\e[1;32mSUCCESS!\e[0m Killed the Cave shard process!\n\n"
				fi
			else
				printf "\t\033[1mCannot continue without first killing the Cave shard process! Exiting!\033[0m\n\n"
				exit 1
			fi
		# Verify if the Cave shard is running and whether or not it should be running:
		elif [ -n "${pid_of_master}" ]; then
			# The Cave shard was found running and shouldn't be:
			if [ -n "${pid_of_cave}" ] && [ -z "${DST_SHARD_CAVE_NAME}" ]; then
				printf "\t\e[1;31mERROR\e[0m: The Cave shard was found running and shouldn't be.\n"
			# The Cave shard is not running but should be:
			elif [ -z "${pid_of_cave}" ] && [ -n "${DST_SHARD_CAVE_NAME}" ]; then
				printf "\t\e[1;31mERROR\e[0m: The Cave shard is not running but should be.\n"
			fi
			if ([ -n "${pid_of_cave}" ] && [ -z "${DST_SHARD_CAVE_NAME}" ]) || ([ -z "${pid_of_cave}" ] && [ -n "${DST_SHARD_CAVE_NAME}" ]); then
				if [ ${FORCE_PROCEED} -gt 0 ]; then
					user_input="y"
				else
					printf "\tWould you like to try and restart the server? (\e[1;37mY\e[0m/N) "
					read user_input
				fi
				if [ "$user_input" != "" ]; then user_input=`echo $user_input | cut -c1`; else user_input="y"; fi
				if [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]; then
					# Try to stop Cave shard process if the user agrees:
					stop; start
					pid ${SCREEN_MASTER_REFERENCE} && pid_of_master=${pid}
					pid ${SCREEN_CAVE_REFERENCE} && pid_of_cave=${pid}
					# Verify if the issue is resolved and notify the user:
					if ([ -n "${pid_of_cave}" ] && [ -z "${DST_SHARD_CAVE_NAME}" ]) || ([ -z "${pid_of_cave}" ] && [ -n "${DST_SHARD_CAVE_NAME}" ]); then
						printf "\t\e[1;31mFAILED!\e[0m The issue wasn't resolved! Please try running this script again as \033[1mroot\033[0m!\n\n"
						exit 1
					else
						printf "\t\e[1;32mSUCCESS!\e[0m Issue resolved!\n\n"
					fi
				else
					printf "\t\033[1mCannot continue without first restarting the server! Exiting!\033[0m\n\n"
					exit 1
				fi
			fi
		fi
	fi
}
verify


################################################################################
#  UPDATE FUNCTION: This function will try to update the server and mod files. #
################################################################################

# This function will try to update the server and mod files.
update() {
	if status; then
		stop
		printf "\t\033[1mUpdating server files & mods:\033[0m\n"
		# Move the dedicated_server_mods_setup.lua to dedicated_server_mods_setup.lua.backup so that it does not get overwritten.
		as_user "mv ${GAME_PATH}/mods/dedicated_server_mods_setup.lua ${BIN_FILE_PATH}/../mods/dedicated_server_mods_setup.lua.backup"
		# Update and validate the game files.
		as_user "${STEAM_PATH}/steamcmd/steamcmd.sh +@ShutdownOnFailedCommand 1 +@NoPromptForPassword 1 +login anonymous +force_install_dir ${GAME_PATH} +app_update 343050 validate +quit"
		# Remove the dedicated_server_mods_setup.lua file and move the dedicated_server_mods_setup.lua.backup file to the dedicated_server_mods_setup.lua file.
		as_user "rm -f ${GAME_PATH}/mods/dedicated_server_mods_setup.lua"
		as_user "mv ${GAME_PATH}/mods/dedicated_server_mods_setup.lua.backup ${BIN_FILE_PATH}/../mods/dedicated_server_mods_setup.lua"
		# Update the mod files.
		as_user "cd ${BIN_FILE_PATH} && ${BIN_FILE} -only_update_server_mods"
		start
	else
		printf "\t\033[1mUpdating server files & mods:\033[0m\n"
		# Move the dedicated_server_mods_setup.lua to dedicated_server_mods_setup.lua.backup so that it does not get overwritten.
		as_user "mv ${GAME_PATH}/mods/dedicated_server_mods_setup.lua ${BIN_FILE_PATH}/../mods/dedicated_server_mods_setup.lua.backup"
		# Update and validate the game files.
		as_user "${STEAM_PATH}/steamcmd/steamcmd.sh +@ShutdownOnFailedCommand 1 +@NoPromptForPassword 1 +login anonymous +force_install_dir ${GAME_PATH} +app_update 343050 validate +quit"
		# Remove the dedicated_server_mods_setup.lua file and move the dedicated_server_mods_setup.lua.backup file to the dedicated_server_mods_setup.lua file.
		as_user "rm -f ${GAME_PATH}/mods/dedicated_server_mods_setup.lua"
		as_user "mv ${GAME_PATH}/mods/dedicated_server_mods_setup.lua.backup ${BIN_FILE_PATH}/../mods/dedicated_server_mods_setup.lua"
		# Update the mod files.
		as_user "cd ${BIN_FILE_PATH} && ${BIN_FILE} -only_update_server_mods"
	fi
}


################################################################################
# ARGUMENT HANDLER: Call the correct function based on user provided arguments.#
################################################################################

# This case will call the right function based on user input.
case "${1}" in
	'start')
		if ! status; then update; fi
		start
		;;
	'stop')
		if [ "${2}" = "--force" ] ; then FORCE_PROCEED=1; fi
		stop
		;;
	'restart')
		if [ "${2}" = "--force" ] ; then FORCE_PROCEED=1; fi
		if status; then stop; fi
		if ! status; then update; fi
		start
		;;
	'update')
		if [ "${2}" = "--force" ] ; then FORCE_PROCEED=1; fi
		update
		;;
	'command')
		shift
		command "${*}"
		printf "\t\e[3;37mA list of commands can be found here:\e[0m \n\t\t\e[4;34mhttp://dontstarve.wikia.com/wiki/Console/Don't_Starve_Together_Commands\e[0m\n\n"
		;;
	'status')
		if status; then printf "\t\e[1;32mThe ${HUMAN_READIBLE_NAME} server is running!\e[0m\n\n"
		else printf "\t\e[1;31mThe ${HUMAN_READIBLE_NAME} server is not running!\e[0m\n\n"; fi
		;;
	*)
		printf "\t\e[1;37mScript usage:\e[0m \n\t\e[1;33m Start\e[0m: Starts the server.\n\t\e[1;33m Stop\e[0m \e[3;33m(--force)\e[0m: Stops the server.\n\t\e[1;33m Restart\e[0m \e[3;33m(--force)\e[0m: Stops the server and then starts the server.\n\t\e[1;33m Update\e[0m \e[3;33m(--force)\e[0m: Stops the server and updates the game files and mods.\n\t\e[1;33m Command\e[0m \e[3;33m'command'\e[0m: Sends a command to both server shards.\n\t\e[1;33m Command master\e[0m \e[3;33m'command'\e[0m: Sends a command to the master shard.\n\t\e[1;33m Command cave\e[0m \e[3;33m'command'\e[0m: Sends a command to the cave shard.\n\n"
	exit 1
esac

exit 0

Here's a short summary of the different commands:

  1. Start: Checks if the server is running. If it isn't, attempts to update the server files & mods before starting the actual server.
  2. Stop (--force): Attempts to stop the server if it is indeed running. First, the script will send a "c_shutdown(true)" command to the running screen session. If that doesn't work, a "kill -15" command will be issued. If that fails as well, a "kill -9" command is issued. The --force option simply enables killing the process without asking the user for permission (useful when the script is called from another script or from crontab).
  3. Restart (--force): First it does everything the stop command does. Then it does everything the start command does.
  4. Update: First the server is stopped, if it is running. Then the server files & mods are updated. The server is then started, if it was running before the update command was issued.
  5. Command (master/cave) 'command': Send a Don't Starve Together command (http://dontstarve.wikia.com/wiki/Console/Don't_Starve_Together_Commands) to the running screen session (master/cave are optional, if left empty, the command will be send to both screen sessions). The commands need to be encapsulated with single quotes!

Let me know what you guys think! :)

Link to comment
Share on other sites

Hey!

Yeah the explanation in the script itself is a bit vague I noticed. So here is what you want to do.

Open up the terminal, and enter the following command:

echo "" > /etc/init.d/start_dst_server && nano /etc/init.d/start_dst_server

Copy paste the script contents into the newly created and open file. Press CTRL + O and CTRL + X to save and close the file.

Then enter these commands:

chown root /etc/init.d/start_dst_server && chgrp root /etc/init.d/start_dst_server && chmod +x /etc/init.d/start_dst_server && update-rc.d start_dst_server defaults

After that, you can try to run the script using the following command:

/etc/init.d/start_dst_server status

Obviously, you need to make sure all the klei related install files are correct. I noticed that the install instructions in the wiki (and pretty much any other source I checked are very vague and sometimes even completely outdated). The way I recommend doing it is to follow the basic install instructions (install SteamCMD and Don't Starve Together) and then copy paste the configuration files from an existing server you created in Windows.

Let me know what you're stuck with and I'll try to help as good as I can!

Link to comment
Share on other sites

Thks for your answer, sorry for my english i'm french ^^

So the file "start_dst_server" i ever created Chowned and chmoded, the only thing i needed is how to launch it :)

Now i've the answer :)

/etc/init.d/start_dst_server start

Ok, so first bug, i need the appropriate interpreter cause :

-bash: /etc/init.d/start_dst_server : /bin/sh^M : bad interpreter:

Link to comment
Share on other sites

I saw your:

pid() {
    pid=""
    if [ -n "${1}" ]; then pid=`ps ax | grep -v grep | grep -i SCREEN | grep ${BIN_FILE_NAME} | grep ${1} | awk '{print $1}'`; fi
}

function and you realize that you don't need to do ps ax and only ps x will suffice? That's because that a stands for all and you don't need that. I took a different approach and used screen -list instead:

steam@Delta:~$ screen -list | grep DST_M | cut -d "." -f1 | sed -e 's/^[ \t]*//'
6089

basically turning your function into:

pid() {
    pid=""
    if [ -n "${1}" ]; then pid=`screen -list | grep ${1} | cut -d "." -f1 | sed -e 's/^[ \t]*//'`; fi
}

What's with the

-threaded_render -threaded_physics

arguments? Do they help with anything?

Link to comment
Share on other sites

Hey! Thanks for responding. It's nice to see you found ways to improve the script. I based myself on a script I once wrote for minecraft, so I mindlessly copy pasted some of my old functions.

Those arguments were actually part of a test and I forgot to remove them. I wanted to see if this game supports multiprocessing, and I was testing a bunch of random arguments to make that happen (without luck, I might add). The first time those arguments made an appearance was in patch 127906.

 

EDIT: Quick note here: Those additional arguments are simply ignored it seems. They don't break the rest of the script, so leaving them in there causes no harm.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.