#!/bin/bash # # Minecraft Alpha SMP Server startup script # Version 1.0.2, released November 13th, 2010 # (c) 2010 Dagmar d'Surreal # Released under the terms of the GNU GPL 2.0. # Run this script with the argument 'licence' to read the licence. ############################################################################# ## ## ## DO NOT EDIT THIS FILE!!! Put your settings in the usual /etc directory ## ## or in ~/.minecraft.conf if you are running this as a normal user. ## ## ## ############################################################################# die() { local message=$* local bell=`tput bel 2>/dev/null` local bold=`tput bold 2>/dev/null` local red=`tput setf 4 2>/dev/null` local off=`tput sgr0 2>/dev/null` echo "$bell${bold}Fatal error: $red$message$off" exit 1 } get_configuration() { if [ $UID -eq 0 ]; then # Started by root/init ...and before anyone can ask, there is # no time when it would make sense for the role user to be # used to start the server directly, because it's a _role_ # account--no more a 'user' than 'root' is. local conf_locs='/etc/init /etc' local confname='minecraft.conf' else # Started safely by a normal user account local conf_locs='~' local confname='.minecraft.conf' fi local found=0 local tmp for tmp in $conf_locs; do if [ -e $tmp/$confname ]; then source $tmp/$confname found=1 break fi done if [ ! found ]; then echo "No configuration file found, using defaults." >&2 fi } # There are a few sanity checks in here simply because there is no better # place for them. A few of the generated defaults _require_ that certain # information already have been sanity-checked. set_defaults() { # If the system is just starting, this might not be populated yet. USER=${USER:-`getusername $UID`} # Note: Unix usernames should not exceed eight characters in length # for reasons which are mostly historical, so 'minecraft' is a bad # choice and definitely unsuitable as a default. if [ $UID -eq 0 ]; then MC_USER=${MC_USER:-miner} else MC_USER=${MC_USER:-$USER} if [ $MC_USER != $USER ]; then # Technical/security considerations make this impractical at best. die "Non-root users may not specify a different MC_USER." fi fi [[ $MC_USER == "root" ]] && die "The server should never run as root!" if ! userexists $MC_USER; then die "The '$MC_USER' role account does not exist."; fi MC_DIR=${MC_DIR:-`gethomedir $MC_USER`} MEM_USE=${MEM_USE:-1024} [[ $MEM_USE -lt 2 ]] && die "MEM_USE may not be set lower than 2Mb!" # If Hey0's mod is installed, it's the default. if [ -r $MC_DIR/Minecraft_Mod.jar ]; then HEY0_MOD=${HEY0_MOD:-yes} else HEY0_MOD=${HEY0_MOD:-no} fi # This gives users sixty seconds to logout before everything goes away. GRACE_TIME=${GRACE_TIME:-60} # The following hack is brought to you by distros that firmly believe # everything should be in it's own separate subdirectory. *glare* local javaloc=`which java 2>/dev/null` if [ -z $javaloc ]; then if [ -x /usr/lib64/java/bin/java ]; then javaloc=/usr/lib64/java/bin/java else if [ -x /usr/lib/java/bin/java ]; then javaloc=/usr/lib/java/bin/java fi fi if [ -z $javaloc ]; then die "Java does not appear to be installed on this machine." else JAVABIN=${javaloc:-java} fi else JAVABIN=$javaloc fi which screen 2>/dev/null 1>/dev/null if [ $? != 0 ]; then die "GNU screen not found on system and is required!" fi } dump_settings () { local varnames="MC_USER MC_DIR MEM_USE HEY0_MOD GRACE_TIME" local tmp echo "# Minecraft server configuration" echo "# Date: `date`" echo "" for tmp in $varnames; do echo "$tmp=${!tmp}" done } append_to_path() { local IFS=: local dirname=$1 local tmp local newpath local match=0 for tmp in $PATH; do if [ $tmp == $1 ]; then (( match++ )) break fi done if [ $match -eq 0 ]; then PATH=${PATH:+$PATH:}$dirname fi } # This is here so that boolean variables can be defined more flexibly boolean() { if [ ${1:0:1} == 0 -o ${1:0:1} == 'n' -o ${1:0:1} == 'N' ]; then return 1 fi } userexists() { [[ -n "`getuid $1`" ]] } gethomedir() { awk -F: "\$1 == \"$1\" { print \$6 }" /etc/passwd 2>/dev/null } getuid() { awk -F: "\$1 == \"$1\" { print \$3 }" /etc/passwd 2>/dev/null } getusername() { awk -F: "\$1 == \"$3\" { print \$1 } | head -n 1" /etc/passwd 2>/dev/null } getserverpids () { if [ -n "`which lsof 2>/dev/null`" ]; then # lsof almost makes this reliable lsof -t $MC_DIR/server.log.lck 2>/dev/null else local uid=`getuid $MC_USER` # Fallback to using ps. We're using the uid because people # can't be trusted to not use 'minecraft' as a username, and # that tends to make ps unable to find the name by the uid ps -C java -o uid=,pid=,cmd= | awk "(/minecraft_server.jar/ || /Minecraft_Mod.jar/) && \$1 == $uid { print \$2 }" 2>/dev/null fi } send_server_message () { local message=$* if [ $MC_USER == $USER ]; then screen -S Minecraft -p Minecraft -X stuff "`echo -e \"\r$message\r\"`" else su - $MC_USER -c "screen -q -S Minecraft -p Minecraft -X stuff \"`echo -e \"\r$message\r\"`\"" fi } send_stop_cmd () { send_server_message "stop" } construct_cmd () { local jarfile if boolean $HEY0_MOD; then jarfile=Minecraft_Mod.jar else jarfile=minecraft_server.jar fi echo "cd $MC_DIR ; screen -d -m -t Minecraft -S Minecraft $JAVABIN -Xms${MEM_USE}M -Xmx${MEM_USE}M -jar $jarfile nogui" } server_is_up() { if [ ! -e $MC_DIR/server.log.lck ]; then # No lockfile means the server is almost certainly down. return 1 fi [[ -n `getserverpids` ]] } server_start () { local status local cmd=`construct_cmd` if [ $MC_USER == $USER ]; then # Starting things as your own uid echo "Running: $cmd" eval $cmd status=$? else # Starting things as root with an su to another uid su - $MC_USER -c "`construct_cmd`" status=$? fi # Because the stupid thing doesn't place the file lock as the very first # thing it does, we need to wait a momnent. If your machine can't get it # done within a clock second, it probably shouldn't be running the server. sleep 1 # We check after the fact because there's simply no way to tell what the # hell happened on the other side of screen without pumping a whole shell # script through it as the "command". if [ $status -eq 0 ]; then if server_is_up; then echo "Minecraft server started successfully." exit else echo "Minecraft server failed to start properly." exit 1 fi echo "Minecraft server started successfully." exit else echo "Error: Command exited with non-zero status!" >&2 exit 1 fi } server_stop () { local second local cleanshutdown if [ $GRACE_TIME -ne 0 ]; then # There's not much point in giving a countdown, so this is pretty much it. # Maybe in a future version we'll emit markers every 15 seconds. echo "Giving Minecraft players $GRACE_TIME seconds warning..." send_server_message "say ATTENTION: The server is shutting down in $GRACE_TIME seconds!" sleep $GRACE_TIME fi send_server_message "say The server is shutting down NOW." for ((second=1 ; second < 30 ; second++)); do send_stop_cmd sleep 1 if ! server_is_up; then cleanshutdown=1 break fi done if [ $cleanshutdown -eq 1 ]; then echo "Minecraft server stopped successfully." else echo "Minecraft server failed to shutdown within 30 seconds!" >&2 exit 1 fi } get_configuration set_defaults show_licence() { cat < Copyright (C) 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; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type \`show w'. This is free software, and you are welcome to redistribute it under certain conditions; type \`show c' for details. The hypothetical commands \`show w' and \`show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than \`show w' and \`show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program \`Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. EOF } # ' This is here to get around some syntax-highlighting failures. case "$1" in 'start') if server_is_up; then echo "The minecraft server is already running." exit fi server_start ;; 'stop') if ! server_is_up; then echo "The minecraft server is not running." exit fi server_stop ;; 'restart') if ! server_is_up; then echo "The minecraft server is not running." exit fi server_stop server_start ;; 'status') if server_is_up; then echo "The minecraft server is currently running." else echo "The minecraft server is currently NOT running." fi ;; 'dumpconfig') dump_settings ;; 'licence') show_licence ;; *) echo "Usage: $0 start|stop|restart|status|dumpconfig|licence" ;; esac # vim: set ts=2: