Created
May 25, 2011 20:37
-
-
Save mrdaemon/991894 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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