Skip to content

Instantly share code, notes, and snippets.

@PhrozenByte
Last active February 6, 2016 14:45
Show Gist options
  • Save PhrozenByte/8dc31b8645c22586c818 to your computer and use it in GitHub Desktop.
Save PhrozenByte/8dc31b8645c22586c818 to your computer and use it in GitHub Desktop.
Daemonize Multi Theft Auto (MTA) servers

PhrozenByte Multi Theft Auto (MTA)

Daemonize Multi Theft Auto (MTA) servers

Usage

  • Install screen (e.g. apt-get install screen)
  • Copy mta-server to /usr/local/bin and make it executable
  • Copy start-mta-server and cleanup-mta-server to your MTA server directory (default server should be at /opt/mta/default) and make them executable
  • Copy mta-server.env to your MTA server directory and adapt it to your own needs; you can comment/remove WWW_PATH if you don't want to use an external web server; see the MTA wiki for more details...
  • Execute /usr/local/bin/mta-server to see how you can use the script

License & Copyright

Copyright (C) 2006-2016 Daniel Rudolf http://www.daniel-rudolf.de/

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License only.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

#!/bin/bash
# PhrozenByte cleanup-mta-server
# Version 1.1
#
# SHORT DESCRIPTION:
# Multi Theft Auto (MTA) cleanup script
#
# COPYRIGHT AND LICENSING:
# Copyright (C) 2006-2015 Daniel Rudolf <http://www.daniel-rudolf.de/>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
EXIT=0
function print_error() {
ERROR=""
if [ -n "$SERVER_ID" ]; then
ERROR+="$SERVER_ID: "
fi
if [ -n "$1" ]; then
ERROR+="$1"
fi
echo "[$(date +"%F %T")] $ERROR" >> "/var/log/mta-server.log"
echo "$ERROR" >&2
}
# determine server path and resource-cache path
SERVER_PATH="$(dirname "$(readlink -fn "$0")")"
SERVER_TMP_DIR="$SERVER_PATH/mods/deathmatch/resource-cache"
# we must run this as root
if [ "$(id -u)" -ne 0 ]; then
print_error "You must run \`$0' as \`root'"
exit 1
fi
# check existance of environment file
if [ -h "$SERVER_PATH/mta-server.env" ] || [ ! -f "$SERVER_PATH/mta-server.env" ]; then
print_error "Server environment file \`$SERVER_PATH/mta-server.env' not found"
exit 1
fi
# include environment file
# we use a subshell, otherwise the environment file could do bad things with us...
ENV_VARS=( "SERVER_ID" "RUN_AS_USER" "RUN_AS_GROUP" "WWW_PATH" )
ENV_VAR_VALUES="$(
source "$SERVER_PATH/mta-server.env"
echo -n "$SERVER_ID" | xxd -p
echo -en "\0" | xxd -p
echo -n "$RUN_AS_USER" | xxd -p
echo -en "\0" | xxd -p
echo -n "$RUN_AS_GROUP" | xxd -p
echo -en "\0" | xxd -p
echo -n "$WWW_PATH" | xxd -p
echo -en "\0" | xxd -p
)"
while IFS="" read -r -u 4 -d $'\0' ENV_VAR_VALUE; do
eval "${ENV_VARS[$i]}=\"$ENV_VAR_VALUE\""
let "i++"
done 4< <(echo "$ENV_VAR_VALUES" | xxd -p -r)
# check validity of environment file
# www path can be empty
if [ -z "$SERVER_ID" ] || [ -z "$RUN_AS_USER" ] || [ -z "$RUN_AS_GROUP" ]; then
print_error "Server environment file \`$SERVER_PATH/mta-server.env' is invalid"
exit 1
fi
# determine tmp path
TMP_DIR="/tmp/mta-server.$SERVER_ID"
# remove the server out of the list of running servers
if [ -f /var/run/mta-server ]; then
CLEANED_SERVER_LIST="$(sed "/^$SERVER_ID$/d" /var/run/mta-server)"
if [ -n "$CLEANED_SERVER_LIST" ]; then
echo "$CLEANED_SERVER_LIST" > /var/run/mta-server
else
rm /var/run/mta-server
fi
elif [ -e /var/run/mta-server ]; then
print_error "Unable to remove server out of the list of running servers \`/var/run/mta-server': Not a file"
EXIT=1
else
print_error "Unable to remove server out of the list of running servers \`/var/run/mta-server': No such file or directory"
EXIT=1
fi
# remove resource-cache link
if [ -h "$SERVER_TMP_DIR" ]; then
rm "$SERVER_TMP_DIR"
elif [ -e "$SERVER_TMP_DIR" ]; then
print_error "Unable to remove resource-cache \`$SERVER_TMP_DIR': Not a symlink"
EXIT=1
else
print_error "Unable to remove resource-cache \`$SERVER_TMP_DIR': No such file or directory"
EXIT=1
fi
# remove tmp dir
if [ -d "$TMP_DIR" ]; then
rm -r "$TMP_DIR"
elif [ -e "$TMP_DIR" ]; then
print_error "Unable to remove server tmp dir \`$TMP_DIR': Not a directory"
EXIT=1
else
print_error "Unable to remove server tmp dir \`$TMP_DIR': No such file or directory"
EXIT=1
fi
# remove www path
if [ -n "$WWW_PATH" ]; then
if [ -h "$WWW_PATH" ]; then
rm "$WWW_PATH"
elif [ -e "$WWW_PATH" ]; then
print_error "Unable to remove resource download dir \`$WWW_PATH': Not a symmlink"
EXIT=1
else
print_error "Unable to remove resource download dir \`$WWW_PATH': No such file or directory"
EXIT=1
fi
fi
exit $EXIT
#!/bin/bash
# PhrozenByte mta-server
# Version 3.1
#
# SHORT DESCRIPTION:
# Manages Multi Theft Auto (MTA) server daemons
#
# COPYRIGHT AND LICENSING:
# Copyright (C) 2006-2016 Daniel Rudolf <http://www.daniel-rudolf.de/>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
LC_ALL=C
APP_NAME="$(basename "$0")"
function showUsage() {
echo "Usage:"
echo " $APP_NAME {start|attach|cleanup|stop|restart|status} MTA_EXEC_PATH"
}
# you must run this as root
if [ "$(id -u)" -ne "0" ]; then
echo "$APP_NAME: You must run this as \`root'" >&2
exit 1
fi
# check parameters
EXEC_PATH="/opt/mta"
if [ $# -ne 2 ]; then
showUsage
exit 1
else
if [ "${2:0:1}" != "/" ] && [ -d "/opt/mta/$2" ]; then
EXEC_PATH="/opt/mta/$2"
else
if [ ! -e "$2" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: No such file or directory" >&2
exit 1
elif [ ! -d "$2" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: Not a directory" >&2
exit 1
fi
EXEC_PATH="$2"
fi
fi
# validate exec path
ENVFILE="$EXEC_PATH/mta-server.env"
CMD_START="$EXEC_PATH/start-mta-server"
CMD_CLEANUP="$EXEC_PATH/cleanup-mta-server"
if [ ! -f "$ENVFILE" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: \`mta-server.env' not found" >&2
exit 1
elif [ ! -r "$ENVFILE" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: \`mta-server.env' not readable" >&2
exit 1
elif [ ! -x "$CMD_START" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: No executable environment" >&2
exit 1
elif [ ! -x "$CMD_CLEANUP" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: No executable environment (cleanup)" >&2
exit 1
fi
# get server id
SERVER_ID="$(source "$ENVFILE" ; echo -n "$SERVER_ID")"
if [ -z "$SERVER_ID" ]; then
echo "$APP_NAME: Invalid MTA_EXEC_PATH: Invalid \`mta-server.env'" >&2
exit 1
fi
# get PIDs of already running servers
SCREEN_PIDS="$(screen -list | awk "/^\t([0-9]+)\.mta-server-$SERVER_ID\t/ {print \$1}" | cut -d "." -f 1)"
case "$1" in
# start server
start)
# check if server is already running
if [ -n "$SCREEN_PIDS" ]; then
if [ "$(echo "$SCREEN_PIDS" | wc -l)" -eq "1" ]; then
echo "$APP_NAME: There is propably already a server running" >&2
else
echo "$APP_NAME: There are propably already $(echo "$SCREEN_PIDS" | wc -l) servers running" >&2
fi
exit 1
fi
# start server
echo -n "Starting server"
screen -dmS "mta-server-$SERVER_ID" "$CMD_START"
# wait for startup (don't wait for longer than 40 * 0.25 = 10 seconds)
SCREEN_PID_COUNT="$(echo -n "$SCREEN_PIDS" | wc -l)"
SERVER_RUNNING="no"
i=0
while [ "$i" -le 40 ]; do
CURRENT_SCREEN_PID_COUNT="$(screen -list | awk "/^\t([0-9]+)\.mta-server-$SERVER_ID\t/ {print \$1}" | wc -l)"
if [ "$CURRENT_SCREEN_PID_COUNT" -ne "$SCREEN_PID_COUNT" ]; then
if [ "$SERVER_RUNNING" == "no" ]; then
# screen session appeared
SCREEN_PID_COUNT="$CURRENT_SCREEN_PID_COUNT"
SERVER_RUNNING="yes"
else
# screen session disappeared
SERVER_RUNNING="error"
break
fi
fi
echo -n "."
sleep 0.25
let "i++"
done
echo
if [ "$SERVER_RUNNING" != "yes" ]; then
# startup failed
if [ "$SERVER_RUNNING" == "error" ]; then
echo "$APP_NAME: Server crashed immediately after startup" >&2
else
echo "$APP_NAME: Giving up; the server is probably not running" >&2
fi
echo "Maybe a previously started server crashed, try running \`$EXEC_PATH/cleanup-mta-server'" >&2
echo "You should also check the logfiles at \`/var/log/mta-server.log'" >&2
exit 1
fi
;;
attach)
if [ -z "$SCREEN_PIDS" ]; then
echo "$APP_NAME: There is probably no server running" >&2
exit 1
fi
if [ "$(echo "$SCREEN_PIDS" | wc -l)" -gt "1" ]; then
echo "There are currently $(echo "$SCREEN_PIDS" | wc -l) servers running"
echo "Attaching server with PID $(echo "$SCREEN_PIDS" | tail -n 1)..."
sleep 3
fi
screen -r "$(echo "$SCREEN_PIDS" | tail -n 1).mta-server-$SERVER_ID"
;;
cleanup)
if [ -z "$SCREEN_PIDS" ]; then
echo "Cleaning up environment..."
"$CMD_CLEANUP"
exit $?
else
echo "You can't cleanup while a server is running"
if [ "$(echo "$SCREEN_PIDS" | wc -l)" -gt "1" ]; then
echo "There are probably ($(echo "$SCREEN_PIDS" | wc -l) servers running"
fi
exit 1
fi
;;
stop)
# is a server running?
if [ -n "$SCREEN_PIDS" ]; then
echo -n "Stopping server"
# stop all running servers
EXIT=0
for SCREEN_PID in $SCREEN_PIDS; do
echo -n " (PID: $SCREEN_PID)"
# send shutdown command
screen -S "$SCREEN_PID.mta-server-$SERVER_ID" -p 0 \
-X stuff "$(printf '%80s' | tr ' ' '\b')$(printf '%80s\r')shutdown$(printf '\r')"
# wait for shutdown (don't wait for longer than 120 * 0.25 = 30 seconds)
i=0
while [ "$i" -le 120 ]; do
if [ "$(screen -list | awk "/^\t$SCREEN_PID\.mta-server-$SERVER_ID\t/ {print \$1}" | wc -l)" -gt "0" ]; then
echo -n "."
sleep 0.25
let "i++"
else
break
fi
done
echo
# when server is still running, ...
if [ "$(screen -list | awk "/^\t$SCREEN_PID\.mta-server-$SERVER_ID\t/ {print \$1}" | wc -l)" -ne "0" ]; then
EXIT=1
# quit the screen session
echo "$APP_NAME: Unable to shutdown server - quit screen session..." >&2
screen -S "$SCREEN_PID.mta-server-$SERVER_ID" -X quit
sleep 1
# when the server is still running, kill screen
if [ "$(screen -list | awk "/^\t$SCREEN_PID\.mta-server-$SERVER_ID\t/ {print \$1}" | wc -l)" -ne "0" ]; then
echo "$APP_NAME: Unable to quit screen session - killing screen session..." >&2
kill -KILL "$SCREEN_PID"
fi
fi
done
exit $EXIT
else
echo "$APP_NAME: There is probably no server running" >&2
exit 1
fi
;;
restart)
$0 stop "$EXEC_PATH"
if [ $? != 0 ]; then
exit $?
fi
$0 start "$EXEC_PATH"
if [ $? != 0 ]; then
exit $?
fi
;;
status)
if [ -n "$SCREEN_PIDS" ]; then
if [ "$(echo "$SCREEN_PIDS" | wc -l)" -eq "1" ]; then
echo "There is propably a server running"
else
echo "There are propably $(echo "$SCREEN_PIDS" | wc -l) servers running"
fi
else
echo "There is propably no server running"
fi
;;
*)
echo "$APP_NAME: Unknown parameter \`$1'" >&2
showUsage
exit 1
;;
esac
exit 0
SERVER_ID="default"
RUN_AS_USER="mta"
RUN_AS_GROUP="www-data"
WWW_PATH="/var/www/html/mta-resources"
#!/bin/bash
# PhrozenByte start-mta-server
# Version 1.1
#
# SHORT DESCRIPTION:
# Multi Theft Auto (MTA) startup script
#
# COPYRIGHT AND LICENSING:
# Copyright (C) 2006-2015 Daniel Rudolf <http://www.daniel-rudolf.de/>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
function print_msg() {
echo "[$(date +"%F %T")] $1" >> "/var/log/mta-server.log"
echo "$1"
}
function print_error() {
ERROR="Unable to start server"
if [ -n "$SERVER_ID" ]; then
ERROR+=" \`$SERVER_ID'"
fi
if [ -n "$1" ]; then
ERROR+=": $1"
fi
echo "[$(date +"%F %T")] $ERROR" >> "/var/log/mta-server.log"
echo "$ERROR" >&2
}
function print_running_server_error() {
print_error "Server is propably still running or has crashed"
echo "When your server crashed, run \`$SERVER_PATH/cleanup-mta-server'" >&2
}
# determine server path and resource-cache path
SERVER_PATH="$(dirname "$(readlink -fn "$0")")"
SERVER_TMP_DIR="$SERVER_PATH/mods/deathmatch/resource-cache"
# we must run this as root
if [ "$(id -u)" -ne 0 ]; then
print_error "You must run \`$0' as \`root'"
exit 1
fi
# check executable
if [ ! -f "$SERVER_PATH/mta-server" ]; then
print_error "Server executable \`$SERVER_PATH/mta-server' not found"
exit 1
fi
# check existance of environment file
if [ ! -f "$SERVER_PATH/mta-server.env" ]; then
print_error "Server environment file \`$SERVER_PATH/mta-server.env' not found"
exit 1
fi
# include environment file
# we use a subshell, otherwise the environment file could do bad things with us...
ENV_VARS=( "SERVER_ID" "RUN_AS_USER" "RUN_AS_GROUP" "WWW_PATH" )
ENV_VAR_VALUES="$(
source "$SERVER_PATH/mta-server.env"
echo -n "$SERVER_ID" | xxd -p
echo -en "\0" | xxd -p
echo -n "$RUN_AS_USER" | xxd -p
echo -en "\0" | xxd -p
echo -n "$RUN_AS_GROUP" | xxd -p
echo -en "\0" | xxd -p
echo -n "$WWW_PATH" | xxd -p
echo -en "\0" | xxd -p
)"
while IFS="" read -r -u 4 -d $'\0' ENV_VAR_VALUE; do
eval "${ENV_VARS[$i]}=\"$ENV_VAR_VALUE\""
let "i++"
done 4< <(echo "$ENV_VAR_VALUES" | xxd -p -r)
# check validity of environment file
# www path can be empty
if [ -z "$SERVER_ID" ] || [ -z "$RUN_AS_USER" ] || [ -z "$RUN_AS_GROUP" ]; then
print_error "Server environment file \`$SERVER_PATH/mta-server.env' is invalid"
exit 1
fi
# check permissions
if [ "$(find "$SERVER_PATH/mta-server" -uid "$(id -u "$RUN_AS_USER")" -executable -exec printf '.' \; | wc -c)" -eq "0" ]; then
print_error "\`$RUN_AS_USER' has no permission to execute \`$SERVER_PATH/mta-server'"
exit 1
fi
# determine tmp dir
TMP_DIR="/tmp/mta-server.$SERVER_ID"
# check that the server is not listed as running
if [ -e /var/run/mta-server ]; then
if [ ! -f /var/run/mta-server ] || [ "$(grep -e "^$SERVER_ID$" /var/run/mta-server | wc -l)" -ne "0" ]; then
print_running_server_error
exit 1
fi
fi
# check that there is no old resource-cache
if [ -h "$SERVER_TMP_DIR" ] || [ -e "$SERVER_TMP_DIR" ]; then
print_running_server_error
exit 1
fi
# check that there is no old tmp dir
if [ -h "$TMP_DIR" ] || [ -e "$TMP_DIR" ]; then
print_running_server_error
exit 1
fi
# check that the www dir doesn't exist
if [ -n "$WWW_DIR" ]; then
if [ -h "$WWW_DIR" ] || [ -e "$WWW_DIR" ]; then
print_running_server_error
exit 1
fi
fi
# create a tmp dir and make sure it is accessible
mkdir "$TMP_DIR"
chown "$RUN_AS_USER" "$TMP_DIR"
chgrp "$RUN_AS_GROUP" "$TMP_DIR"
chmod 2775 "$TMP_DIR"
# use the tmp dir as replacement for the resource-cache
ln -s "$TMP_DIR" "$SERVER_TMP_DIR"
# create a symlink from the tmp http-client-files to the www path
# note that this link will appear as broken until the server is running
if [ -n "$WWW_PATH" ]; then
ln -s "$SERVER_TMP_DIR/http-client-files" "$WWW_PATH"
fi
# list the server as running
if [ ! -f /var/run/mta-server ]; then
echo "$SERVER_ID" > /var/run/mta-server
else
echo "$SERVER_ID" >> /var/run/mta-server
fi
# prepare stderr logging
exec 3> >(
awk "{ printf \"[\"; system(\"echo -n \`date +'%F %T'\`\"); printf \"] [$SERVER_ID] \"; print \$0; fflush(); }" \
>> "/var/log/mta-server.log"
)
# start server
cd "$SERVER_PATH"
print_msg "Starting server \`$SERVER_ID'..."
sudo -u "$RUN_AS_USER" -- ./mta-server 2>&3
# the server has stopped (or startup failed), cleanup everything
print_msg "Server \`$SERVER_ID' stopped..."
./cleanup-mta-server
exec 3>&-
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment