Skip to content

Instantly share code, notes, and snippets.

@mrdaemon
Created May 25, 2011 20:37
Show Gist options
  • Save mrdaemon/991894 to your computer and use it in GitHub Desktop.
Save mrdaemon/991894 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# ###### ####### ###### ## ## ######## ## ####### ## ##
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# ## ## ## ## ## ## ## ## ## ## ## ## ##
# ## ## ## ## ##### ######## ## ## ## ###
# ## ## ## ## ## ## ## ## ## ## ## ## ##
# ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# ###### ####### ###### ## ## ######## ######## ####### ## ##
#
# Minecraft Server Maintenance Script
# - https://github.com/mrdaemon/cockblox
#
# Author: Alexandre Gauthier (mr_daemon)
# alex at lab dot underwares dot org
#
# Version 1.1a
#
# Dependencies:
# Please ensure they are available before running script.
# * tmux - terminal multiplexer (http://tmux.sourceforge.net/)
# * GNU Bash shell (http://www.gnu.org/software/bash/)
#
# Optional Dependencies:
# The following dependencies are optional, for ramdisk suppport.
#
# * rsync - fast incremential file transfer utility (http://rsync.samba.org/)
# * Linux 2.6 as server operating system, with /dev/shm ramdisk support.
#
# ----------------------------------------------------------------------------
### BEGIN INIT INFO
# Provides: minecraft
# 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: Minecraft server
# Description: Control script for Minecraft game server (optional mods)
### END INIT INFO
# ----------------------------------------------------------------------------
# -*-*-*- Configuration Settings -*-*-*-
#
# Please review the following settings and ensure they suit your setup
# and tastes. The script has been configured with Sane Defaults (tm) whenever
# possible. If you are unsure about a particular setting, leave it at default.
#
# -*-*-*-
# -------------------------- Server/World Settings ---------------------------
# Server name and URL - set those to representative values for your server.
# If you multiplex this script, ensure it is **unique**
SERVER_NAME="cockblox"
SERVER_URL="http://cockblox.underwares.org"
USING_MOD=1 # Use a server mod? (1 = on, 0 = off)
# Affects update/run logic
MOD_JAR_NAME="craftbukkit.jar" # If using mod, jar filename used to boot
SERVER_USER="minecraft" # user to run server as
SERVER_WARN_DELAY=30 # Amount of time between in-game warnings and
# actual operations.
# TODO: I should perhaps make this more
# granular, but I don't see the immediate use.
# I mean, this is minecraft.
#
# ** Affects stop, restart, update **
#
# NOTE: If you wish to skip the delay
# altogether on certain occasions, just use
# "nowarn", i.e. "./minecraft.sh stop nowarn"
USE_RAMDISK=0 # Write world to ramdisk, to be commited to
# actual disk on an arbitrary interval via
# commodity file replication. Reduces lag, but
# at the cost of any memory you may have
# left. I don't recommend it unless you have
# plenty of free pages in memory to spare,
# have equipment to deal with sudden power
# losses, and resources to spare.
# ** MAY INCUR DATA LOSS **
RAMDISK='/dev/shm' # Path to the mounted ramdisk.
# This is a sane default for ubuntu.
# Has no effect unless USE_RAMDISK=1
# ------------------------------ Path settings -------------------------------
# Tools and misc, sane autoguess, first-in-path defaults
TMUX=$(which tmux) # Path to tmux binary
RSYNC=$(which rsync) # Path to rsync binary
JVM=$(which java) # path to jvm binary (java - it would help to
# have JAVA_HOME declared in global variables.
MC_HOME=/opt/minecraft # Path to minecraft's root dir
PLUG_HOME=${MC_HOME}/plugins # Where mod plugins live, if any
DATASTORE=${MC_HOME}/diskstore # Path to disk store.
# Only has effect **if ramdisk is in use**
CARTO_PATH=$MC_HOME/cartograph # Path to cartograph binary
MAPS_PATH=$MC_HOME/www/world # Where cartograph maps are saved
LOG_TDIR=$MC_HOME/www/logs # Where logs are archived
BKUP_PATH=$MC_HOME/backup # Where backups are stored
# --------------- Java Settings (Min/Max Memory, JVM Arguments ---------------
MEMALOC=1024 # Max Java Heap (allocatable memory)
MEMALOCMIN=750 # Min Java Heap (default allocated memory)
JVMARGS="-XX:+UseConcMarkSweepGC \
-XX:+CMSIncrementialPacing \
-XX:ParallelGCThreads=$CPU_COUNT \
-XX:+AggressiveOpts"
# --------------------------- Start/Stop Settings ----------------------------
AUTO_REMOVE_STALE_LOCK=0 # Set to 1 to automatically remove stale .lck files
AUTO_FORCE_QUIT=0 # Set to 1 to forcefully shutdown the server if it fails
# to gracefully shut down within a reasonable time span
# (defined below)
STOP_WAIT=120 # Amount of time to wait (in seconds) before considering
# the server hung/stuck. On a very slow/busy server,
# you might want to increase this value, especially
# if
# a) you have large worlds
# b) ESPECIALLY if you use AUTO_FORCE_QUIT.
#
# Do note that regardless of this setting,
# the script will ALWAYS wait at least 30 seconds,
# for safety. No one likes missing chunks.
# --------------------------- Backups and Archives ---------------------------
# Log rotation settings
LOGS_DAYS=7 # Keep X days of logs
# Backup Settings
BKUP_DAYS_INCR=2 # Incremential backups every X days
BKUP_DAYS_FULL=5 # Full backup every X days
# Symlink names for backup latest full/incr. backup sets
BACKUP_FULL_LINK=${BKUP_PATH}/${WORLD_NAME}_full.tgz
BACKUP_INCR_LINK=${BKUP_PATH}/${WORLD_NAME}_incr.tgz
# ----------------------- Broadcast Messages Contents ------------------------
#
# Variable names should be self-descriptive.
# For messages where a variable is used, use %s as a specifier.
# What will end up there should be fairly specific.
# Example:
# MSG_SERVER_RESTART="Server will restart in %s seconds."
#
# Feel free to localize/adapt/change as you wish.
#
MSG_SERVER_STOP="Arret du serveur dans %s secondes :("
MSG_SERVER_RESTART="Redémarrage du serveur dans %s secondes."
MSG_SERVER_UPDATE="Mise à jour du serveur dans %s secondes. In b4 catastrophic failure..."
MSG_BACKUP_WARN="Backup de la map dans %s secondes..."
MSG_BACKUP_BEGIN="Demarrage du backup OH GOD"
MSG_BACKUP_END="Backup terminé! TEH BLOX ARE SAFE!... Peut-être!"
MSG_CARTOGRAPHY_BEGIN="Le moine juif albinos cartographe sors ses crayons... "
MSG_CARTOGRAPHY_END="Le moine juif albinos cartographe à updaté la carte du monde!"
MSG_CARTOGRAPHY_SITE="Checkez la carte du monde sur: %s"
# ---------- Nebulous, esoteric and internal settings, dirty hacks -----------
# *** Please only edit the settings below if you know what the hell
# you are doing. Chances are, you don't. Settings are still documented.
USE_CRAPPY_CONSOLE_CLEAR=0 # Potentially unsafe. Will send an extra
# carriage return before each command to the
# server. This will ensure there are no
# leftover characters on the console,
# at the cost of possibly executing whatever
# command was entered there without enter
# being pressed. Highly crappy, dirty and
# inelegant. You decide if you need this.
ALLOW_MULTIPLE_INSTANCES=0 # Allow multiple instances of the script to run
# at the same time, with potentially disastrous
# results. (i.e, restarting the server while a
# backup is running). Normally the script
# checks to see if another copy is running.
#
# Set this to '1' if you wish to disable this behaviour.
# ** NOT RECOMMENDED **
WAIT_FOR_EXISTING_INSTANCES=1 # By default, if the script detects another
# copy of itself running, it will politely wait
# until that instance terminates before
# running.
#
# Change this to 0 to disable this behaviour,
# at the cost of potentially enduring a million
# scripts suddendly queued for execution.
#
# The script will then simply abort if an
# existing instance is already running.
#
# This setting has no effect if
# ALLOW_MULTIPLE_INSTANCES is set to 1.
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
# ---------------- END OF CONFIGURATION. DO NOT EDIT FURTHER! -----------------
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
# Script must be ran as root, in order to use su.
# FIXME: Make it so it doesn't require root.
[[ "$(uid -u)" -eq 0 ]] || { echo "Sorry. Please run this as root." ; exit 1 ;}
# ----------------------------- Global Variables -----------------------------
RUNNING=0
THIS_USER=$(whoami)
# -*-*-*- Functions and Subroutines -*-*-*-
# ---------------------- Utilitarian Functions / Tools -----------------------
# Echoes argument to STDERR.
# Useful for cronjobs where you only want to receive
# emails on errors/warnings.
# (i.e. minecraft.sh > /dev/null)
#
# $1 - String to echo
#
echoerr() {
echo "$1" >&2
}
# Formats a string
# Obscenely simplistic, pseudo printf()-like routine
# that simply replaces a single specifier (which is
# more of a placeholder) in $1 with the contents of $2.
# Did not want to deal with printf(1) for various
# portability/complexity reasons.
#
# $1 - Source String with %s specifier
# $2 - String to insert into $1
#
format_string() {
echo "${1/"%s"/"$2"}"
}
# Run shell command as server user
# Does the right thing regardless of current uid.
#
# $1 - Shell command line
# returns: Command return code
#
run() {
retval=""
# Determine if we need to su to the server user profile.
# Allows the script to function wether ran as root or as $SERVER_USER
if [[ "$THIS_USER" == "$SERVER_USER" ]] ; then
bash -c "$1"
retval=$?
else
su - $SERVER_USER -c "$1"
retval=$?
fi
# Pass on the command's return value
return $retval
}
# Bootstrap tmux session
# Initializes the tmux server and session they don't already exist
bootstrap_tmux() {
# Launch a new server if none exists.
if ! $TMUX list-sessions ; then
echo -n "Starting terminal multiplexer server..."
run "cd $MC_HOME && $TMUX -u start-server"
if [[ "$?" -ne 0 ]] ; then
echo "\t[FAIL]"
else
echo "\t[ OK ]"
fi
fi
# Begin setting up our tmux session
echo -n "Setting up Server envrionment..."
if $($TMUX has-session -t $SERVER_NAME) ; then
echo "\t[SKIP]"
echoerr "Skipped session init, session already running."
else
echo -n "Setting up session..."
$TMUX new-session -d -s $SERVER_NAME || { echo "\t[FAIL]" ; exit 1 ;}
echo "\t[ OK ]"
fi
}
# ------------------ Minecraft Server Maintenance Functions ------------------
# Send command to minecraft server inside tmux
#
# $1 - Minecraft server command
#
server_cmd() {
cmd="`printf "$1\r"`"
[[ "$USE_CRAPPY_CONSOLE_CLEAR" -ne 0 ]] && cmd="\r""$cmd"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$cmd\""
}
# Broadcast message to players in-game
#
# $1 - Message to broadcast
#
server_msg() {
msg="say $1"
server_cmd "$msg"
}
## Validate is multiuser support is enabled in screen
## and properly configured. Used by the console attach
## feature and sanity checks.
##
## returns: 0 on success (multiuser available and properly set up),
## 1 on failure
##
#check_screen_mu_config() {
# screenrc="$(su - $SERVER_USER -c 'echo $HOME')/.screenrc"
# if [ -e $screenrc ] ; then
# if [[ $(grep "multiuser on" $screenrc)\
# && $(grep "acladd root" $screenrc) ]] ; then
# return 0
# fi
# fi
# return 1
#}
# Run server inside set up tmux session
server_start() {
# Construct startup line
if run "$TMUX list-sessions" ; then
run "$TMUX neww -d -n minecraft -t $SERVER_NAME \"$target\""
}
# Check status routine, sets the RUNNING
# global based on misc. checks.
# Include paranoid check for multiple instances.
# (common when "stop" failed somehow and an eager
# admit forces a start.)
#
# Returns: the pid of the server process, whenever applicable.
#
server_status() {
# If there's no lock, mark server down and fail early.
[[ -e $MC_HOME/server.log.lck ]] || { RUNNING=0 ; return 1 ;}
}
check_status() {
# Naive checks first -- check the lock file, then try to locate the process.
if [ -e $MC_HOME/server.log.lck ] ; then
$pid = `ps -ef | grep -i -v screen | grep java | grep -i minecraft | awk '{ print $2 }'`
if [ -z $pid ] ; then
echoerr "Lock file found, but no running process."
echoerr "Server crashed or was shut down uncleanly"
if [[ $AUTO_REMOVE_STALE_LOCK -gt 0 ]] ; then
rm -f $MC_HOME/server.log.lck
echoerr "Stale lock file removed."
else
echoerr "You should remove $MC_HOME/server.log.lck before restarting."
exit 1
fi
# Set global status as not running.
$RUNNING=0
# Check for multiple running instances,
elif [ -n $(echo $pid | awk '{ print $2 }') ] ; then
echoerr "ALERT! ALERT! ALERT!"
echoerr "************************"
echoerr "FOUND MULTIPLE INSTANCES RUNNING!"
echoerr "pids: $pid"
echoerr ""
echoerr "THIS COULD POTENTIALLY BE DISASTROUS"
echoerr "(multiple worlds saving to the same file)"
echoerr ""
echoerr "Aborting execution so you can fix this."
echoerr "(Keep your backups within reach :( )"
exit 1
else
# Set global status as running.
$RUNNING=1
return $pid
fi
else
# Server isn't running at all. Update status.
$RUNNING=0
fi
}
# Attach to server console using screen session sharing,
# and ugly, ugly, terrible, nasty, insecure, tty permissions
# futzing as a fallback should screen multiuser support
# be available. Not that screen's multiuser support is
# that better, it's just not nearly as gaping a security
# hole. Lesser evil, I guess.
#
# Note that it's up to the user to do the futzing if they wish to.
# We just warn about how bad of an idea it is if it's detected.
#
#
attach_console() {
# check if current tty is writable by the user running
# the server. This is the ugly fallback.
# If it is the case, let the user know it's a terrible idea.
ttyrw=`su - $SERVER_USER -c "[[ ( -w $(tty) ) && ( -r $(tty) ) ]] && echo yes"`
if [ -n $ttyrw ] ; then
echoerr "WARNING: tty is writable by user \"$SERVER_USER\"! "
echoerr "This could potentially be a security risk! "
echoerr "Permissions of your tty:"
echoerr `ls -lh $(tty)`
echoerr ""
fi
# Try both methods, offer useful advice whenever possible.
if check_screen_mu_config ; then
[[ -n $ttyrw ]] && echo "Press enter to continue" && read
su - $SERVER_USER -c "screen -x ${SERVER_USER}/${SCREEN_NAME}"
elif [ -n $ttyrw ] ; then
echoerr "WARNING: Screen is not correctly configured."
echoerr "Not using multiuser screen sharing."
echoerr ""
echoerr "Nevertheless, attaching to console will work because of the insecure \
tty permissions."
echoerr "Just be sure you know what you are doing."
echoerr "The recommended way to attach would be using Screen sharing."
echoerr "Run:"
echoerr "$0 sanitycheck"
echoerr "For more information."
echoerr ""
echoerr "Press enter to continue."
read
su - $SERVER_USER -c "screen -R $SCREEN_NAME"
else
echoerr "Unable to attach to screen console."
echoerr "Screen is not correctly configured for this to work."
echoerr "Make sure ${SERVER_USER}'s .screenrc contains at least:"
echoerr ""
echoerr " multiuser on"
echoerr " acladd root"
echoerr ""
echoerr "Run: "
echoerr "$0 sanitycheck"
echoerr "For more information."
exit 1
fi
}
# Launch the server process, with or without mods.
# Performs extra status checks to ensure it was successful.
#
start_server() {
echo -n "Attempting to start minecraft server"
binaries="minecraft_server.jar"
cd $MC_HOME
if [ $USING_MOD -eq 1 ] ; then
echo -n " (+mods)"
binaries="Minecraft_Mod.jar"
fi
echo -n " ..."
# Run the server. yum, screen.
su - $SERVER_USER -c \
"screen -m -d -S $SCREEN_NAME \
java -Xms${MEMALOCMIN}M -Xmx${MEMALOC}M -Djava.net.preferIPv4Stack=true -jar $binaries nogui"
if [ $? -ne 0 ] ; then
echo -e "\t[FAIL]"
echoerr "ERROR: Screen failed to launch server process."
exit 1
fi
# Wait some time for the server to actually boot.
sleep 5
# Perform extra status check
check_status
if [ $RUNNING -eq 1 ] ; then
echo -e "\t[OK]"
else
echo -e "\t[FAIL]"
echoerr "Server failed to launch/not running."
if [ -e $MC_HOME/server.log ] ; then
echoerr "Last 5 lines from log file:"
for line in $(tail -n 5 $MC_HOME/server.log) ; do
echoerr $line
done
fi
exit 1
fi
}
# Stops the running server.
# Rather careful about it, checks for status to make sure
# it did go down, depending on configuration, may or may not
# forcefully terminate te server.
#
stop_server() {
# This will be set to 1 if the server went into
# timeout countdown, but the server shut down at the
# last moment. Completely useless, but amusing.
# Also reduces confusion should an email or message read
# "OH GOD SERVER IS PERMASTUCK FFFFFFFF PANIC, PANIC!"
# immediately followed by "Server stopped".
#
# It sure as hell would confuse *me*.
#
potential_miracle=0
while [ $RUNNING -ne 0 ] ; do
echo -n "Attempting to stop minecraft server cleanly..."
server_cmd "stop"
# Give minecraft some time to clean up and quit
sleep 5
check_status
echo -e "\nWaiting for server..."
sleep 10
check_status
echo "Still waiting for server."
check_status
echo "Waiting for 10 more seconds..."
sleep 10
check_status
echo "Resending stop command..."
server_cmd "stop"
echo "Waiting for 15 more seconds..."
sleep 15
check_status
echoerr "WARNING: Server is taking an abnormally long time to shut down."
if [ -e $MC_HOME/server.log ] ; then
echoerr "Last 5 lines from log file:"
for line in $(tail -n 5 $MC_HOME/server.log) ; do
echoerr $line
done
fi
check_status
echoerr "WARNING: Server took too long to respond."
echoerr "Assuming stuck in $STOP_WAIT seconds."
sleep $STOP_WAIT
check_status
echoerr "WARNING: Server seems stuck."
# A clean shutdown is unlikely at this point.
# Should that happen, point out it's a miracle.
potential_miracle=1
if [ $AUTO_FORCE_QUIT -eq 1 ] ; then
pid=check_status
while [ $RUNNING -eq 1 ] ; do
echoerr "Sending SIGTERM to $pid..."
kill $pid
sleep 5
check_status
echoerr "Sending SIGKILL to $pid..."
kill -9 $pid
sleep 5
check_status
echoerr "ERROR: Minecraft Server completely hung."
echoerr "Not responding to kill signals."
echo -e "\t[FAIL]"
exit 1
done
fi
# Last ditch check, should AUTO_FORCE_QUIT
# succeed or some miracle occur.
# Fairly certain this is completely unecessary,
# since this while loop would exit, but...
check_status
echo -e "\t[FAIL]"
echoerr "Failed to stop server. Please investigate."
exit 1
done
echo -e "\t[OK]"
if [ $potential_miracle -eq 1 ] ; then
echoerr "The server suddendly stopped out of the blue."
echoerr "IT'S A CHRISTMAS MIRACLE!"
fi
}
# Sends an in-game warning message with a
# countdown based on SERVER_WARN_DELAY.
# Takes a message as an argument.
# To make use of the amount of time remaining,
# it should use the %s specifier. See options
# at the top of this script for details.
#
# Also, because I hate math in general, and wish to
# get it over with as quickly as possible, I'm going
# to go in full compact bash mode here, in contrast
# to the overly verbose style employed through this script.
#
# Sorry if any confusion results from this.
#
# $1 - Message to send (preferably containing %s specifier)
#
warn_countdown() {
msg=$1
steps=1
# Prefer 3 warnings over 2, if that can't happen,
# just print the warning once.
# Mmm, basic maths. :|
for step in 2 3 ; do
(( $SERVER_WARN_DELAY % $step )) && steps=$step
done
sleepval=$(( $SERVER_WARN_DELAY / $steps ))
remaining=$SERVER_WARN_DELAY
for (( i=1; i<=$steps; i++ )) ; do
# Shave off two seconds off sleep value
# on last step, to make it useful.
[[ ( $i -eq $steps ) && ($steps -ne 1 ) ]] && \
sleepval=$(( $sleepval - 2 ))
# Send warning to server
m=format_string $msg $remaining
server_msg $m
remaining=$(( $remaining - $sleepval ))
sleep $sleepval
done
}
# Script entry point
# status | start | stop [msg|nowarn] | restart [nowarn] | backup | logs | broadcast <msg|file> | cartography | update [nowarn] | selfupdate | sanitycheck
if [ $# -gt 0 ] ; then
case $1 in
"status")
pid=check_status
if [ $RUNNING -eq 1 ] ; then
echo "Minecraft server is currently running. ($pid)"
exit 0
else
echo "Minecraft server is currently stopped."
exit 1
fi
;;
"start")
pid=check_status
if [ $RUNNING -eq 1 ] ; then
echoerr "A minecraft server is already running! ($pid)"
exit 1
fi
start_server
;;
"stop")
pid=check_status
immediate=0
if [ $RUNNING -eq 0 ] ; then
echo "No server currently running."
else
case $2 in
"nowarn")
immediate=1
;;
*)
[[ -n $2 ]] && server_msg "$2"
sleep 3
warn_countdown "$MSG_SERVER_STOP"
;;
esac
echo -n "Shutting down minecraft server "
[[ $immediate -eq 1 ]] && echo -n "(without warning)"
echo "..."
stop_server
fi
;;
"restart")
pid=check_status
immediate=0
case $2 in
"nowarn")
immediate=1
;;
*)
[[ -n $2 ]] && server_msg "$2"
sleep 3
warn_countdown "$MSG_SERVER_RESTART"
;;
esac
echo -n "Restarting minecraft server "
[[ $immediate -eq 1 ]] && echo -n "(without warning)"
echo "..."
stop_server && start_server
# If we reach here, we assume everything went well.
# The script will abort entirely if something goes wrong anyways...
echo "Minecraft Server sucessfully restarted."
;;
"backup")
echo "UNINMPLEMENTED. :("
;;
"logs")
echo "UNINMPLEMENTED. :("
;;
"broadcast")
if [ -n $2 ] ; then
# I'm a lazy ass. At least getting the main structure
# working, I'll implement the small details later.
[[ -r $2 ]] && echo "UNIMPLEMENTED. :(" && exit 1
msg="[CONSOLE] $1"
server_msg "$2"
echo "$msg"
else
#TODO: Write and call usage()
exit 1
fi
;;
"cartography")
echo "UNIMPLEMENTED. :("
;;
"update")
echo "UNIMPLEMENTED. :("
;;
"selfupdate")
echo "UNIMPLEMENTED. :("
;;
"sanitycheck")
echo "UNIMPLEMENTED. :("
;;
*)
#TODO: write and call usage()
echo "Usage: ..."
exit 1
;;
esac
fi
if [ $# -gt 0 ]
then
case $1 in
"status")
if [ $RUNNING -eq 1 ]
then
echo "Minecraft server running."
else
echo "Minecraft server OFFLINE ZOMG!!!1"
fi;;
#################################################################
"start")
if [ $RUNNING -eq 1 ]
then
echo "Server already running, or so it seems."
case $2 in
"force")
kill `ps -e | grep java | cut -d " " -f 1`
rm -fr $MC_HOME/*.log.lck 2> /dev/null/;;
esac
else
server_launch
if [ $ATTACH_ON_LAUNCH -eq 1 ]
then
attach_console
fi
fi;;
#################################################################
"stop")
if [ $RUNNING -eq 1 ]
then
server_stop
else
case $2 in
"force")
kill `ps -e | grep java | grep minecraft | cut -d " " -f 1`
rm -fr $MC_HOME/*.log.lck 2> /dev/null/;;
*)
echo "Server seems to be offline OH GOD";;
esac
fi;;
#################################################################
"restart")
if [ $RUNNING -eq 1 ]
then
case $2 in
"warn")
msg1="`printf "say Le serveur repart dans 30s!\r"`"
msg2="`printf "say Le server repart dans 10s! ZOMG!\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg1\""; sleep 30
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg2\""; sleep 10;;
esac
server_stop
fi
server_launch
if [ $ATTACH_ON_LAUNCH -eq 1 ]
then
attach_console
fi;;
#################################################################
"logs")
mkdir -p $LOG_TDIR
cd $LOG_TDIR
case $2 in
"clean")
DATE=$(date +%d-%m --date "$LOGS_DAYS day ago")
if [ -e logs-$DATE ]
then
mkdir -p $BKUP_PATH/logs
mv logs-$DATE $BKUP_PATH/logs/
fi
;;
esac
DATE=$(date +%d-%m)
LOG_NEWDIR=logs-$DATE
if [ -e $LOG_TDIR/$LOG_NEWDIR ]
then
rm $LOG_TDIR/$LOG_NEWDIR/*
else
mkdir $LOG_TDIR/$LOG_NEWDIR
fi
DATE=$(date +%d-%m-%Hh%M)
LOG_TFILE=logs-$DATE.log
if [ $USING_MOD -eq 1 ]
then
if [ $RUNNING -eq 1 ]
then
LOG_LCK=$(basename $MC_HOME/logs/*.log.lck .log.lck)
echo "Found a log lock : $LOG_LCK"
else
LOG_LCK=""
fi
cd $MC_HOME/logs/
for i in *
do
if [ $i != $LOG_LCK.log.lck ] # skip du fichier lck
then
cat $i >> $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE
if [ $i != $LOG_LCK.log ] # On ne supprime pas le fichier log courant, si le serv est en route
then
rm $i
fi
fi
done
else
cd $MC_HOME
cat server.log >> $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE
fi
if [ -e $LOG_TDIR/ip-list.log ]
then
cat $LOG_TDIR/ip-list.log | sort | uniq > $LOG_TDIR/templist.log
fi
cat $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE | egrep '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+.+logged in' | sed -e 's/.*\[INFO\]\s//g' -e 's/\[\//\t/g' -e 's/:.*//g' >> $LOG_TDIR/templist.log
cat $LOG_TDIR/templist.log | sort | uniq -w 4 > $LOG_TDIR/ip-list.log
rm $LOG_TDIR/templist.log
cat $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE | egrep 'logged in|lost connection' | sed -e 's/.*\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\).\[INFO\].\([a-zA-Z0-9_]\{1,\}\).\{1,\}logged in/\1\t\2 : connected/g' -e 's/.*\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\).\[INFO\].\([a-zA-Z0-9_]\{1,\}\).lost connection.*/\1\t\2 : disconnected/g' >> $LOG_TDIR/$LOG_NEWDIR/connexions-$DATE.log
cat $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE | egrep '<[a-zA-Z0-9_]+>|\[CONSOLE\]' | sed -e 's/.*\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\).\[INFO\]./\1 /g' >> $LOG_TDIR/$LOG_NEWDIR/chat-$DATE.log
cat $LOG_TDIR/$LOG_NEWDIR/$LOG_TFILE | egrep 'Internal exception|error' | sed -e 's/.*\([0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}\).\[INFO\]./\1\t/g' >> $LOG_TDIR/$LOG_NEWDIR/errors-$DATE.log
;;
#################################################################
"backup")
mkdir -p $BKUP_PATH
if [ -e $MC_HOME/$WORLD_NAME ]
then
if [ $RUNNING -eq 1 ]
then
echo "Server running, warning players : backup in 10s."
msg="`printf "say Backup de la map dans 10s OH GOD\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg\""; sleep 10
msg="`printf "say Backup de la map en cours... p-e...\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg\""
echo "Issuing save-all command, wait 5s..."
cmd="`printf "save-all\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 5
cmd="`printf "save-off\r"`"
echo "Issuing save-off command..."
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 1
fi
cd $BKUP_PATH
DATE=$(date +%Y-%m-%d-%Hh%M)
FILENAME=$WORLD_NAME-$DATE
BACKUP_FILES=$BKUP_PATH/list.$DATE
if test `date +%H` -eq 0 -o ! -f $BACKUP_FULL_LINK
then
# Make full backup, and remove old incrementals
FILENAME=$FILENAME-full.tgz
# Remove incrementals older than $BKUP_DAYS_INCR
# Remove full archives older than $BKUP_DAYS_FULL
find ./$WORLD_NAME-*-incr.tgz -type f -mtime +$BKUP_DAYS_INCR -print > purgelist
find ./$WORLD_NAME-*-full.tgz -type f -mtime +$BKUP_DAYS_FULL -print >> purgelist
rm -f `cat purgelist`
rm -f purgelist
# Now make our full backup
pushd $MC_HOME
find $WORLD_NAME -type f -print > $BACKUP_FILES
tar -zcvf $BKUP_PATH/$FILENAME --files-from=$BACKUP_FILES
popd
rm -f $BACKUP_FULL_LINK $BACKUP_INCR_LINK
ln -s $FILENAME $BACKUP_FULL_LINK
else
# Make incremental backup
FILENAME=$FILENAME-incr.tgz
pushd $MC_HOME
find $WORLD_NAME -newer $BACKUP_FULL_LINK -type f -print > $BACKUP_FILES
tar -zcvf $BKUP_PATH/$FILENAME --files-from=$BACKUP_FILES
popd
rm -f $BACKUP_INCR_LINK
ln -s $FILENAME $BACKUP_INCR_LINK
fi
rm -f $BACKUP_FILES
if [ $RUNNING -eq 1 ]
then
echo "Issuing save-on command..."
cmd="`printf "save-on\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 1
cmd="`printf "say Le backup est fini! REJOICE!\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$cmd\""
fi
echo "Backup process is over."
else
echo "The world \"$WORLD_NAME\" does not exist.";
fi;;
#################################################################
"cartography")
# This should be properly fixed, but right now I am too tired.
# When ran from cron, this may or may not have the proper working directory.
# A simple fix is, pushing into the directory, then pop'ing out, as to not break anything
# else.
# TODO: One day, make this shit use absolute path or try to untagle the mess.
if [ -e $CARTO_PATH ]
then
if [ -e $MC_HOME/$WORLD_NAME ]
then
# FIXME: Temp Fix, until not tired as dick.
pushd $MC_HOME
if [ $RUNNING -eq 1 ]
then
echo "Issuing save-all command, wait 5s...";
cmd="`printf "save-all\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 5
echo "Issuing save-off command...";
cmd="`printf "save-off\r"`"
msg="`printf "say Le moine juif cartomancien sors ses crayons.\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 1
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg\""
fi
mkdir -p $MAPS_PATH
DATE=$(date +%d-%m-%Y-%Hh%M)
FILENAME=$WORLD_NAME-map-$DATE
echo "Le moine cheque ca..."
for mode in topview color ore gray oblique angled ; do
$CARTO_PATH -R=$mode -O=$FILENAME-$mode.png $WORLD_NAME
done
$CARTO_PATH -c -O=$FILENAME-caves.png $WORLD_NAME
mv *.png $MAPS_PATH
cd $MC_HOME
echo "Cartography is done."
if [ $RUNNING -eq 1 ]
then
echo "Issuing save-on command..."
cmd="`printf "save-on\r"`"
msg="`printf "say Le moine juif cartomancien a fini son oeuvre.\r"`"
msg2="`printf "say Map Update: $SERVER_URL\r"`"
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff $cmd"; sleep 1
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg\""
su - $SERVER_USER -c "screen -S $SCREEN_NAME -p 0 -X stuff \"$msg2\""
fi
#FIXME: Temp fix. Again.
popd
else
echo "The world \"$WORLD_NAME\" does not exist.";
fi
else
echo "The path to cartographier seems to be wrong."
fi;;
#################################################################
"update")
if [ $RUNNING -eq 1 ]
then
server_stop
fi
mkdir -p $BKUP_PATH
echo "Backing up current binaries..."
DATE=$(date +%d-%m-%Y)
modfile=mcmod.zip
cd $MC_HOME
if [ $USING_MOD -eq 1 ]
then
tar -czf minecraft_server-$DATE.tar.gz minecraft_server.jar Minecraft_Mod.jar
if [ $? -eq 0 ] ; then
rm Minecraft_Mod.jar
else
echo "FATAL ERROR WHILE ARCHIVING PREVIOUS BINARIES!"
echo "Oh god, dying -- better you handling this than me, dumb script."
exit 1
fi
else
tar -czf minecraft_server-$DATE.tar.gz minecraft_server.jar
fi
mv minecraft_server-$DATE.tar.gz $BKUP_PATH
echo "Downloading new binaries..."
wget -N http://www.minecraft.net/download/minecraft_server.jar
if [ $USING_MOD -eq 1 ]
then
wget -O $modfile http://hey0.net/get.php?dl=serverbeta
if [ $? -eq 0 ] ; then
mkdir -p $MC_HOME/tmp
mv $modfile $MC_HOME/tmp
pushd $MC_HOME/tmp
unzip $modfile
cp bin/*.jar $MC_HOME/
popd
fi
fi
server_launch
if [ $ATTACH_ON_LAUNCH -eq 1 ]
then
attach_console
fi;;
#################################################################
*)
echo "Usage : minecraft <status | start [force] | stop | restart [warn] | logs [clean] | backup [clean] | cartography | update>";
esac
else
if [ $RUNNING -eq 1 ]
then
attach_console
else
echo "Minecraft server seems to be offline..."
fi
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment