msm/msm

575 lines
16 KiB
Plaintext
Raw Normal View History

#!/bin/bash
### BEGIN INIT INFO
# Provides: msm
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description:
# Description:
### END INIT INFO
# See http://www.debian.org/doc/debian-policy/ch-opersys.html#s-sysvinit for
# more information on debain init.d scripts, which may help you understand
# this script.
### Source the configuration file
source "/etc/msm.conf"
2012-05-20 11:48:13 +00:00
### Config variables the user should need/want to change
2012-05-20 12:40:46 +00:00
# Minecraft's whitelist file
declare -r WHITELIST="white-list.txt"
# Minecraft's banned ips file
declare -r BANNED_IPS="banned-ips.txt"
# Minecraft's banned players file
declare -r BANNED_PLAYERS="banned-players.txt"
# Jar group file which contains the download target URL
declare -r JARGROUP_TARGET="target.txt"
# Jar group directory name to download new jars to, is deleted afterwards
declare -r JARGROUP_DOWNLOAD_DIR="downloads"
2012-05-20 12:40:46 +00:00
### Utility Functions
# Executes the command "$1" as SERVER_USER
2012-05-20 12:40:46 +00:00
as_user() {
if [ $(whoami) == $SERVER_USER ] ; then
bash -c "$1"
else
su - $SERVER_USER -s /bin/bash -c "$1"
fi
}
# Executes the command "$1" as SERVER_USER but returns stderr instead
as_user_stderr() {
as_user "$1" > /dev/null 2>&1
}
# Echo to stderr
echoerr() {
echo "$@" 1>&2
}
# Determines whether "$1" is a valid name for a server or jar group directory
# It must only contain upper or lower case letters, digits, dashes or
# underscores.
# It must also not be one of a list of reserved names.
is_valid_name() {
local valid="^[a-zA-Z0-9\_\-]+$"
local invalid="^server|jargroup|start|stop|restart$"
if [[ "$1" =~ $valid ]]; then
if [[ "$1" =~ $invalid ]]; then
echoerr "Invalid name \"$1\": A name may not be any of the following reserved worlds \"start\", \"stop\", \"restart\", \"server\" or \"jargroup\"."
return 1
else
return 0
fi
else
echoerr "Invalid name \"$1\": A name may only contain letters, numbers, dashes and unscores."
return 1
fi
}
# Gets the latest jar from a jar group, based upon the date and time encoded
# in the file name.
get_latest_file() {
local best_time=0
local best_file=""
for file in "$1/*"; do
# Remove the path, leaving just the file name
local name=$(basename "$file")
local date_time=$(echo $name | awk -F '-' '{print $1 "-" $2 "-" $3 " " $4 ":" $5 ":" $6}')
# Get the time in seconds since 1970 from file name
local seconds=$(date -d "$date_time" "+%s" 2> /dev/null)
# If that is newer than the current best, override variables
if [[ $seconds > $best_time ]]; then
best_time=$seconds
best_file=$file
fi
done
echo $best_file
}
2012-05-21 17:34:12 +00:00
### Server Functions
# Echos a list of servers in the SERVER_STORAGE_PATH
2012-05-21 17:34:12 +00:00
server_list() {
echo "Servers:"
for server in "$SERVER_STORAGE_PATH/*"; do
echo " $(basename $server)"
done
}
# Creates a new server
# $1: The server name to create
2012-05-21 17:34:12 +00:00
server_create() {
if is_valid_name "$1"; then
if [[ -e "$SERVER_STORAGE_PATH/$1" ]]; then
echo "A server with that name already exists."
return 1
else
printf "Creating server directory... "
as_user "mkdir -p '$SERVER_STORAGE_PATH/$1'"
as_user "touch '$SERVER_STORAGE_PATH/$1/$WHITELIST'"
as_user "touch '$SERVER_STORAGE_PATH/$1/$BANNED_IPS'"
as_user "touch '$SERVER_STORAGE_PATH/$1/$BANNED_PLAYERS'"
echo "Done."
fi
else
return 1
fi
}
# Deletes an existing server
# $2: The server name to delete
2012-05-21 17:34:12 +00:00
server_delete() {
if is_valid_name "$1"; then
if [[ -e "$SERVER_STORAGE_PATH/$1" ]]; then
printf "Are you sure you want to delete this server and its worlds (note: backups are preserved) [y/N]: "
read answer
if [[ "$answer" =~ ^y|Y|yes$ ]]; then
# TODO: stop the server if running first
as_user "rm -rf '$SERVER_STORAGE_PATH/$1'"
echo "Server deleted."
else
echo "Server was NOT deleted."
fi
else
echo "There is no server with the name \"$1\"."
return 1
fi
else
return 1
2012-05-21 15:13:24 +00:00
fi
}
# Renames an existing server
# $1: The server name to change
# $2: The new name for the server
2012-05-21 17:34:12 +00:00
server_rename() {
if is_valid_name "$1"; then
if [[ -e "$SERVER_STORAGE_PATH/$1" ]]; then
# If the server name is valid and exists
2012-05-21 15:13:24 +00:00
# TODO: Check that the server is not running first, return if it is
2012-05-21 15:13:24 +00:00
if is_valid_name "$2"; then
# If the server name is valid
if [[ -e "$SERVER_STORAGE_PATH/$2" ]]; then
# and there is not already a server with the name $2
echo "Could not be renamed, there is already a server with the name \"$2\"."
return 1
else
as_user "mv '$SERVER_STORAGE_PATH/$1' '$SERVER_STORAGE_PATH/$2'"
echo "Renamed server \"$1\" to \"$2\"."
fi
2012-05-21 15:13:24 +00:00
else
return 1
2012-05-21 15:13:24 +00:00
fi
else
echo "There is no server with the name \"$1\"."
return 1
fi
else
return 1
fi
}
2012-05-21 17:34:12 +00:00
### Jar Group Functions
# Lists the jar files grouped by jar groups.
jargroup_list() {
for group in $(ls -1 "$JAR_STORAGE_PATH"); do
echo "${group}:"
for jar in $(ls -1r $JAR_STORAGE_PATH/$group); do
if [[ "$jar" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}- ]]; then
echo " $jar"
fi
done
done
}
# Creates a new jargroup
# $1: The name for the jargroup
jargroup_create() {
if is_valid_name "$1"; then
if [[ ! -e "$JAR_STORAGE_PATH/$1" ]]; then
printf "Creating jar group... "
local error=$(as_user_stderr "mkdir -p '$JAR_STORAGE_PATH/$1'")
if [[ "$error" != "" ]]; then
echo "Failed."
echo "Reason: $error"
return 1
fi
error=$(as_user "echo \"$2\" > '$JAR_STORAGE_PATH/$1/$JARGROUP_TARGET'")
if [[ "$error" != "" ]]; then
echo "Failed."
echo "Reason: $error"
return 1
fi
echo "Done."
# Download the latest version now
jargroup_getlatest "$1"
else
echo "A jar group with that name already exists."
return 1
fi
else
return 1
fi
}
# Downloads the latest version for a jargroup, using the target URL for that
# group. Saves the download with the date and time encoded in the start of the
# file name, in the jar group directory in question. Removes the file if there
# is no difference between it and the current version.
# $1: The jargroup name to download the latest version for
jargroup_getlatest() {
if is_valid_name "$1"; then
if [[ -e "$JAR_STORAGE_PATH/$1" ]]; then
if [[ -e "$JAR_STORAGE_PATH/$1/$JARGROUP_TARGET" ]]; then
printf "Downloading latest version... "
2012-05-21 13:39:59 +00:00
# Try and make
local error=$(as_user_stderr "mkdir -p '$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR'")
if [[ "$error" != "" ]]; then
echo "Failed."
echo "Reason: $error"
return 1
fi
2012-05-21 13:39:59 +00:00
as_user "wget --quiet --input-file='$JAR_STORAGE_PATH/$1/$JARGROUP_TARGET' --directory-prefix='$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR' --no-check-certificate"
echo "Done."
2012-05-21 13:39:59 +00:00
local num_files=$(as_user "ls -1 '$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR' | wc -l")
2012-05-21 13:39:59 +00:00
if [[ $num_files == 1 ]]; then
# There was 1 file downloaded
local file_name=$(ls -1 "$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR")
local new_name="$(date +%F-%H-%M-%S)-$file_name"
local most_recent_jar=$(get_latest_file "$JAR_STORAGE_PATH/$1")
if [[ ! -e "$most_recent_jar" ]] || ! diff "$most_recent_jar" "$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR/$file_name"; then
# There is not a previous version to do a comparison against, or
# The previous version is different:
# Add it to the group
2012-05-21 13:39:59 +00:00
[[ -e "$most_recent_jar" ]]
local was_previous=$?
as_user "mv '$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR/$file_name' '$JAR_STORAGE_PATH/$1/$new_name'"
if [[ $was_previous == 0 ]]; then
echo "Downloaded version was different to previous latest. Saved as \"$1/$new_name\"."
else
echo "Saved as \"$JAR_STORAGE_PATH/$1/$new_name\"."
fi
else
echo "Existing version \"$JAR_STORAGE_PATH/$1/$new_name\" was already up to date."
fi
elif [[ $num_files == 0 ]]; then
# No file was downloaded
echo "Failed. No files were downloaded."
else
# Multiple files were
echo "Error. URL downloads multiple files."
fi
# Clean up the temp download folder
as_user "rm -fr '$JAR_STORAGE_PATH/$1/$JARGROUP_DOWNLOAD_DIR'"
else
echo "Target URL not found, use $0 jargroup seturl <download-url>"
return 1
fi
2012-05-21 13:39:59 +00:00
else
echo "There is no jar group with the name \"$1\"."
return 1
fi
else
return 1
2012-05-21 13:39:59 +00:00
fi
}
# Deletes an existing jargroup
# $1: The name of the existing jargroup
jargroup_delete() {
if is_valid_name "$1"; then
if [[ -e "$JAR_STORAGE_PATH/$1" ]]; then
printf "Are you sure you want to delete this jar group [y/N]: "
2012-05-21 13:39:59 +00:00
read answer
if [[ "$answer" =~ ^y|Y|yes$ ]]; then
as_user "rm -rf $JAR_STORAGE_PATH/$1"
echo "Jar group deleted."
else
echo "Jar group was NOT deleted."
fi
else
echo "There is no jar group with the name \"$1\"."
return 1
fi
else
return 1
fi
2012-05-20 12:40:46 +00:00
}
# Renames an existing jargroup
# $1: The name of the existing jargroup
# $2: The new name
jargroup_rename() {
if is_valid_name "$1"; then
if [[ -e "$JAR_STORAGE_PATH/$1" ]]; then
# If the jar group name is valid,
# and there is no other jar group with the name $1
if is_valid_name "$2"; then
if [[ -e "$JAR_STORAGE_PATH/$2" ]]; then
echo "Could not be renamed, there is already a jar group with the name \"$2\"."
return 1
else
# TODO: Update any symbolic links which point to a jar in this directory
as_user "mv '$JAR_STORAGE_PATH/$1' '$JAR_STORAGE_PATH/$2'"
echo "Renamed jar group \"$1\" to \"$2\"."
fi
else
return 1
fi
else
echo "There is no jar group with the name \"$1\"."
return 1
fi
else
return 1
fi
}
2012-05-20 12:40:46 +00:00
### Script Options
case "$1" in
start)
# Required start option, for debian init.d scripts
;;
stop)
# Required stop option, for debian init.d scripts
;;
restart)
# Required restart option, for debian init.d scripts
;;
server)
case "$2" in
list)
# Lists the existing servers
2012-05-21 17:34:12 +00:00
server_list
;;
create)
if [ -z "$3" ]; then
# If a server name is not provided
echo "Invalid command."
else
# Create a new server
2012-05-21 17:34:12 +00:00
server_create "$3"
fi
;;
delete)
if [ -z "$3" ]; then
# If a server name is not provided
echo "Invalid command."
else
# Delete an existing server, with confirmation
2012-05-21 17:34:12 +00:00
server_delete "$3"
fi
;;
rename)
if [ -z "$3" ] || [ -z "$4" ]; then
# If a server name is not provided
echo "Invalid command."
else
# Rename an existing server
2012-05-21 17:34:12 +00:00
server_rename "$3" "$4"
fi
;;
*)
# "server" is not a valid command
echo "Invalid command."
;;
esac
;;
jargroup)
case "$2" in
list)
# Lists the jars grouped by jargroup
jargroup_list
;;
create)
if [ -z "$3" ] || [ -z "$4" ]; then
echo "Invlaid command."
else
jargroup_create "$3" "$4"
fi
;;
delete)
if [ -z "$3" ]; then
echo "Invalid command."
else
jargroup_delete "$3"
fi
;;
rename)
if [ -z "$3" ] || [ -z "$4" ]; then
echo "Invalid command."
else
jargroup_rename $3 $4
fi
;;
changetarget)
if [ -z "$3" ] || [ -z "$4" ]; then
echo "Invalid command."
else
jargroup_settarget "$3" "$4"
fi
;;
getlatest)
if [ -z "$3" ]; then
echo "Invalid command."
else
jargroup_getlatest "$3"
fi
;;
*)
# "jargroup" is not a valid command
echo "Invalid command."
;;
esac
;;
help)
# Outputs a list of all commands
echo -e "Usage: $0 command:"
echo -e
echo -e "--Setup Commands------------------------------------------------"
echo -e " server list \t\t\t\t\tList servers"
echo -e " server create <name> \t\t\t\tCreates a new Minecraft server"
echo -e " server delete <name> \t\t\t\tDeletes an existing Minecraft server"
echo -e " server rename <name> <new-name> \t\tRenames an existing Minecraft server"
echo -e
echo -e "--Server Mangement Commands-------------------------------------"
echo -e " <server> start \t\t\t\tStarts a server"
echo -e " <server> stop [now] \t\t\t\tStops a server after warning players, or right now"
echo -e " <server> restart [now] \t\t\tRestarts a server after warning players, or right now"
echo -e " <server> status \t\t\t\tShow the running/stopped status of a server"
echo -e " <server> connected \t\t\t\tList a servers connected players"
echo -e " <server> worlds list \t\t\t\tLists the worlds a server has"
echo -e " <server> worlds load \t\t\t\tCreates links to wolrds in storage for a server"
echo -e " <server> worlds ram <world> \t\t\tToggles a world's \"in RAM\" status"
echo -e " <server> worlds toram \t\t\tSynchronises any RAM enabled worlds to RAM a server has"
echo -e " <server> worlds todisk \t\t\tSynchronises any \"in RAM\" worlds to disk a server has"
echo -e " <server> worlds backup \t\t\tMakes a backup of all worlds a server has"
echo -e " <server> logroll \t\t\t\tMove a server log to a gziped archive, to reduce lag"
echo -e " <server> backup \t\t\t\tMakes a backup of an entire server directory"
echo -e
echo -e "--Server Pass Through Commands----------------------------------"
echo -e " <server> wl on|off <player> \t\t\tEnabled/disable server whitelist check"
echo -e " <server> wl add|remove <player> \t\tAdd/remove a player to/from a server's whitelist"
echo -e " <server> wl list \t\t\t\tList the players whitelisted for a server"
echo -e " <server> bl player add|remove <player> \tBan/pardon a player from/for a server"
echo -e " <server> bl ip add|remove <ip address> \tBan/pardon an IP address from/for a server"
echo -e " <server> bl list \t\t\t\tLists the banned players and IP address for a server"
echo -e " <server> op add|remove <player> \t\tAdd/remove operator status for a player on a server"
echo -e " <server> gm survival|creative <player> \tChange the game mode for a player on a server"
echo -e " <server> kick <player> \t\t\tForcibly disconnect a player from a server"
echo -e " <server> say <message> \t\t\tBroadcast a (pink) message to all players on a server"
echo -e " <server> time set|add <number> \t\tSet/increment time on a server (0-24000)"
echo -e " <server> toggledownfall \t\t\tToggles rain and snow on a server"
echo -e " <server> save on|off \t\t\t\tEnable/disable writing world changes to file"
echo -e " <server> save all \t\t\t\tForce the writing of all non-saved world changes to file"
echo -e " <server> cmd <command> \t\t\tSend a command string to the server and return"
echo -e " <server> cmdlog <command> \t\t\tSame as 'cmd' but shows log output afterwards (Ctrl+C to exit)"
echo -e
echo -e "--Jar Commands--------------------------------------------------"
echo -e " jargroup list \t\t\t\tList the stored jar files."
echo -e " jargroup create <name> <download-url> \tCreate a new jar group, with a URL for new downloads"
echo -e " jargroup delete <name> \t\t\tDelete a jar group"
echo -e " jargroup rename <name> <new-name> \t\tRename a jar group"
echo -e " jargroup changeurl <name> <download-url> \tChange the download URL for a jar group"
echo -e " jargroup getlatest <name> \t\t\tDownload the latest jar file for a jar group"
echo -e
echo -e "--Global Commands-----------------------------------------------"
echo -e " start \t\t\t\t\tStarts all active servers"
echo -e " stop [now]\t\t\t\t\tStops all running servers"
echo -e " restart [now]\t\t\t\t\tRestarts all active servers"
;;
"")
echo "No such command see: $0 help"
;;
*)
if is_valid_name "$1" && [[ -e "$SERVER_STORAGE_PATH/$1" ]]; then
case "$2" in
start)
;;
stop)
;;
restart)
;;
worlds)
;;
backup)
;;
logroll)
;;
connected)
;;
status)
;;
whitelist|wl)
;;
blacklist|bl)
;;
operator|op)
;;
gamemode|gm)
;;
kick)
;;
say)
;;
"time")
;;
toggledownfall)
;;
save)
;;
cmd)
;;
cmdlog)
;;
esac
else
echo "No server with that name."
fi
;;
esac
exit 0