[BACK]Return to mtctl_default.sh CVS log [TXT][DIR] Up to [local] / mtctl

File: [local] / mtctl / mtctl_default.sh (download)

Revision 1.4, Tue Oct 19 10:05:56 2021 UTC (2 years, 5 months ago) by miniontoby
Branch: MAIN
Changes since 1.3: +14 -5 lines

Update 1.3: check changelog.txt for more info!

#---------------------------------------------------------------------
# Filename: mtctl
# Purpose: Minetest server Control
# License: Copyright (C) 2021 by Miniontoby <miniontoby@ircnow.org>
#---------------------------------------------------------------------
VERSION="1.3"
config=[]
config[0]="no"; config[1]="/usr/local/share/minetest/"

#---------------------------------------------------------------------
# Alias

mtinfo() {
	MSG="$1"
	echo -e "mtctl: $MSG" | sed -e 's/\\n/\\nmtctl: /'
}
mthelp() {
	echo -e "usage:  mtctl start|stop|restart|status|create|backup worldname\n        mtctl list|help|version|check_updates"; exit 1
}
if [ "x$1" == "x" ]; then mthelp; exit 1; fi


#---------------------------------------------------------------------
# Setup

if [[ "`id -u`" -eq 0 ]]; then CONFDIR=/etc/mtctl; else CONFDIR=$HOME/.mtctl; fi
if [ \! -d $CONFDIR ]; then mkdir -p $CONFDIR || exit 1; fi
if [ \! -f $CONFDIR/config ]; then
	mtinfo "\nNo configfile found!\nCreating it now!\n\n"
	echo -n 'Use custom build minetest folder (yes/no): '; read MTBUILD
	case $MTBUILD in 
		YES|yes) MTBUILD='yes'
			EXAMPLEDIR="$HOME/minetest"
			;;
		NO|no) MTBUILD='no'
			EXAMPLEDIR="$HOME/.minetest"
			;;
		*) mtinfo "Error, not a valid option!"
			exit 1
			;;
	esac
	echo -n "Insert the path to the minetest folder(eg. $EXAMPLEDIR): "; read MTLOCATION

	echo -e "builded=$MTBUILD\nlocation=$MTLOCATION" > $CONFDIR/config
	unset MTBUILD MTLOCATION EXAMPLEDIR
	mtinfo "Configfile created!!\n\n"
fi

while read line; do
	linea="`echo $line | grep -F = 2> /dev/null`"
	if [ "x$linea" \!= "x" ]; then
		varname=$(echo "$line" | cut -d '=' -f 1)
		case $varname in
			builded) indexnumber=0
				;;
			location) indexnumber=1
				;;
		esac
		config[$indexnumber]=$(echo "$line" | cut -d '=' -f 2-)
	fi
done < $CONFDIR/config

mtsetup() {
	EXITDIR=${config[1]}/tmp
	if [ "${config[0]}" == "yes" ]; then SERVEREXE="${config[1]}/bin/minetestserver"; else SERVEREXE="`which minetestserver`"; fi
	WORLDBASE=${config[1]}/worlds
	LOGDIR=${config[1]}/log
	EXITFLAGALL=$EXITDIR/minestop.all
	OK=0; cd ${config[1]} || exit 1
	touch temp.test && OK=1; if [ "@$OK" == "@0" ]; then mtinfo "Error: Directory tree should be owned by the MT user:\n${config[1]}"; exit 1; fi
	rm temp.test || exit 1
	if [ \! -f $SERVEREXE ]; then mtinfo "Error: Couldn't determine SERVEREXE setting\n$SERVEREXE"; exit 1; fi

	mkdir -p $EXITDIR || exit 1
	mkdir -p $WORLDBASE || exit 1
	mkdir -p $LOGDIR || exit 1
}

#---------------------------------------------------------------------
# Normal Functions

GetPIDS() {
	FOO=`ps ax | grep $SERVEREXE | grep " $1" | grep -e "--port" | sed -e "s/^ *//" -e "s/ .*//"`; BAR=`ps ax | grep "mtctl start *$2"\$ | grep -v grep | grep -v "^ *$$ " | sed -e "s/^ *//" -e "s/ .*//"`
}

SetWorld() {
	NAME=$1; if [ "x$NAME" == "x" ]; then mthelp; exit 1; fi
	WORLDDIR=$WORLDBASE/$NAME; if [ \! -d $WORLDDIR ]; then mtstatus "Failed"; mtinfo "Error: World not found: $NAME"; exit 1; fi
	PORT=`grep '^port.*=' $WORLDDIR/world.conf | sed -e "s/^.*= *//" -e "s/ .*//"`; if [ "x$PORT" == "x" ]; then mtstatus "Failed"; mtinfo "Error: Port for $NAME not defined in cfg file"; exit 1; fi
}
mtstatus() {
	CHECK="$1"
	EXTRA=""
	if [ "$CHECK" == "Ok" ]; then
		GetPIDS "$WORLDDIR" "$NAME"
		if [ "x$FOO$BAR" \!= "x" ]; then
			CHECK="Online"
		else
			CHECK="Offline"
		fi
		EXTRA="\n"
        elif [ "$CHECK" == "Failed" ]; then EXTRA="  \n";
        elif [ "$CHECK" == "Backup failed" ]; then EXTRA="  \n";
        elif [ "$CHECK" == "Backup success" ]; then EXTRA="  \n"; fi
	echo -ne "\r$NAME($CHECK)$EXTRA"
}

#---------------------------------------------------------------------
# Functions for executing the actions

startMT() {
	SetWorld "$1"; mtstatus
	GetPIDS "$WORLDDIR" "$NAME"
	BAR=`echo $BAR | wc -l`
	if [ "x$FOO" \!= "x" ]; then
		mtstatus "Failed"
		mtinfo "Error: World seems already to be running\nIf it is not running, run $ mctl stop $NAME to be sure"
		exit 1
	fi

	EXITFLAGWORLD=$EXITDIR/minestop.$NAME
	MINETEST_SUBGAME_PATH=${config[1]}/games 
	# MAYBE Export if linux doesnt work

	rm -f $EXITFLAGALL $EXITFLAGWORLD
	sleep 1; DIR=`pwd` || exit 1; cd $WORLDDIR || exit 1
	F1=env_meta.txt; F2=env_meta.old; if [ -s $F1 ]; then N=`grep EnvArgsEnd $F1 | wc -l` || exit 1; if [ "x$N" == "x0" ]; then rm -f $F1 || exit 1; fi; fi; if [ -s $F1 ]; then rm -f $F2; cp -p $F1 $F2 || exit 1; else if [ -s $F2 ]; then rm -f $F1; cp -p $F2 $F1 || exit 1; else rm -f $F1 || exit 1; fi; fi
	cd $DIR || exit 1

	(
	while true; do
		$SERVEREXE --config $WORLDDIR/world.conf --port $PORT --logfile $LOGDIR/debug-$NAME.log --map-dir $WORLDDIR >> $LOGDIR/$NAME.log 2>&1
		if [ -f $EXITFLAGALL ]; then exit 0; fi; if [ -f $EXITFLAGWORLD ]; then exit 0; fi; sleep 10
	done
	) > $LOGDIR/start-$NAME.txt &
	mtstatus "Ok"
}

stopMT() {
	SetWorld "$1"; mtstatus
	GetPIDS "$WORLDDIR" "$NAME"
	if [ "x$FOO$BAR" == "x" ]; then mtstatus "Failed"; mtinfo "$NAME seems to be stopped already"; exit 0; fi
	if [ "x$FOO" \!= "x" ]; then kill -SIGINT $FOO 2> /dev/null ; sleep 1; kill -SIGINT $FOO 2> /dev/null ; sleep 1; kill -SIGINT $FOO 2> /dev/null ; sleep 1; kill -SIGINT $FOO 2> /dev/null ; fi
	if [ "x$BAR" \!= "x" ]; then kill -9 $BAR; fi

	mtstatus "Waiting"
	sleep 15; GetPIDS "$WORLDDIR" "$NAME"

	if [ "x$FOO$BAR" == "x" ]; then
		mtstatus "Ok"
	else
		kill -9 $FOO; kill -9 $FOO; kill -9 $FOO; kill -9 $FOO;
		if [ "x$BAR" \!= "x" ]; then kill -9 $BAR; fi

		mtstatus "Waiting."
		sleep 15; GetPIDS "$WORLDDIR" "$NAME"
		if [ "x$FOO$BAR" == "x" ]; then
			mtstatus "Ok"
		else
			mtstatus "Failed"; mtinfo "Error: Stop of $NAME failed\nTry once more, then consult a sysadmin"; exit 1
		fi
	fi
}

restartMT() {
	SetWorld "$1"
	/usr/bin/mtctl stop "$1"|| exit 1
	/usr/bin/mtctl start "$1" || exit 1
}

statusMT() {
        SetWorld "$1"
        GetPIDS "$WORLDDIR" "$NAME"
        if [ "x$FOO$BAR" \!= "x" ]; then
                STATUS="Online"
        else
                STATUS="Offline"
        fi
        LASTLOG="`tail -n 5 $LOGDIR/$NAME.log`"
        echo -e "mtctl.$1 - The Minetest Server Control\n   Active: $STATUS\n  Process: $FOO\n Main PID: $BAR\n\n$LASTLOG"
}

listMT() {
	for WORLDNAME in `ls $WORLDBASE 2> /dev/null | grep '^[a-zA-Z0-9]*$' | sort`; do
		SetWorld "$WORLDNAME"
		mtinfo "World: $WORLDNAME Port: $PORT" 
	done
}

createMT() {
	NAME=$1; if [ "x$NAME" == "x" ]; then mthelp; exit 1; fi
	if [ "x$NAME" == "x" ]; then echo -e "Failed\nError: Worlds need a name\n"; exit 1; else if [ -d $WORLDBASE/$NAME ]; then echo -e "Failed\nError: World already exist\n"; exit 1; else echo -e "Server name: Ok"; fi; fi
	echo -ne "\nServer Description: "; read SERVER_DESCRIPTION
	PortCheck () {
		CHECK='yes'; if [ -z "${PORT##*[!0-9]*}" ]; then CHECK='no'; ERROR="Ports are only numeric"; return; fi; for x in `ls /home/$MTUSER/minetest/worlds | sort`; do export WCFILE=$WORLDBASE/$x/world.conf; if [ -f $WCFILE ]; then export PORTF=`grep '^port.*=' $WCFILE | sed -e "s/^.*= *//" -e "s/ .*//"`; if [ "x$PORTF" == "x$1" ]; then CHECK='no'; ERROR="Port already in use"; return; fi; fi; done
	}
	while true; do echo -ne "\nPort: "; read PORT; PortCheck $PORT; if [ "$CHECK" == "no" ]; then echo -e "Failed\nError: $ERROR"; sleep 1; else echo -e "Ok"; break; fi; done
	echo -ne "\nMessage Of The Day [MOTD]: "; read MOTD; echo -ne "\nSeed: "; read SEED; echo -ne "\nCreative (true/false): "; read CREATIVE_MODE
	echo -ne "\nEnable Damage (true/false): "; read ENABLE_DAMAGE; echo -ne "\nEnable Player Versus Player [PVP] (true/false): "; read ENABLE_PVP
	echo -ne "\nUsername: "; read USERNAME

	cd $WORLDBASE; mkdir $NAME; cd $NAME
	echo -e "server_name = $NAME\nserver_description = $SERVER_DESCRIPTION\nport = $PORT\nmotd = $MOTD\nfixed_map_seed = $SEED\ncreative_mode = $CREATIVE_MODE\nenable_damage = $ENABLE_DAMAGE\nenable_pvp = $ENABLE_PVP\nname = $USERNAME\nserver_announce = true\nserverlist_url = servers.minetest.net\nsqlite_synchronous = 0\nserver_unload_unused_data_timeout = 900\nserver_map_save_interval = 900.0" > world.conf
	echo -e "creative_mode = $CREATIVE_MODE\nenable_damage = $ENABLE_DAMAGE\nauth_backend = sqlite3\nbackend = sqlite3\nplayer_backend = sqlite3\ngameid = minetest\nworld_name = $NAME" > world.mt
	echo -ne "\nWorld created!\nWant to start the world?(yes/no): "; read startit
	if [[ "$startit" == "yes" ]]; then /usr/bin/mtctl start $NAME; fi
	echo -e "\nSuccess: \033[1;32mDone \033[m\nFeel free to join your new server at port $PORT"
}

backupMT() {
	SetWorld "$1"
	# Backup script from mtlbak by Minix
	# Copyright (C) 2021 Minix from FreedomTest (freedomtest@protonmail.com)

	BACKUP_DIR="$CONFDIR/backups/$NAME"
	LOG_FILE="$LOGDIR/backup_$NAME.log"
	mkdir -p $BACKUP_DIR
	echo -ne "" >> $LOG_FILE

	if [ -f /tmp/$(basename $WORLDDIR)_local_backup_in_progress ]; then
		echo "\nBackup for $(basename $WORLDDIR) on $(date) aborted because another backup is already in progress, this may be caused by a backup that is taking longer than expected" >> $LOG_FILE
		mtinfo "Backup for $(basename $WORLDDIR) on $(date) aborted because another backup is already in progress, this may be caused by a backup that is taking longer than expected"
		exit 1
	fi

	touch /tmp/$(basename $WORLDDIR)_local_backup_in_progress
	rm $BACKUP_DIR/map.sqlite.tmp* 2> /dev/null #Cleaning in case of crashed attempts

	echo -e "\n$(date) backup started" >> $LOG_FILE
	mtstatus "Backup started"

	try=0
	while [ $try -lt 5 ]; do
		echo "Starting backup attempt #$(expr $try + 1) on $(date)" >> $LOG_FILE
		sqlite3 $WORLDDIR/map.sqlite ".backup $BACKUP_DIR/map.sqlite.tmp" 2> /dev/null
		if [ $? -eq 0 ]; then
			mv $BACKUP_DIR/{map.sqlite.tmp,map.sqlite}
			#Backup auth.sqlite and players.sqlite files properly
			until sqlite3 $WORLDDIR/auth.sqlite ".backup $BACKUP_DIR/auth.sqlite" 2> /dev/null; do
				continue
			done
			until sqlite3 $WORLDDIR/players.sqlite ".backup $BACKUP_DIR/players.sqlite" 2> /dev/null; do
				continue
			done
			rsync -ptrW --delete --exclude "*.sqlite" $WORLDDIR/ $BACKUP_DIR/ 
			echo "Backup finished succesfully on $(date)" >> $LOG_FILE
			mtstatus "Backup success"
			rm /tmp/$(basename $WORLDDIR)_local_backup_in_progress 2> /dev/null
			exit 0
		else
			rm $BACKUP_DIR/map.sqlite.tmp 2> /dev/null
			try=$(expr $try + 1)
			if [ $try -eq 5 ]; then
				echo "Backup failed 5 times, aborting on $(date)" >> $LOG_FILE
				mtstatus "Backup failed"
				rm /tmp/$(basename $WORLDDIR)_local_backup_in_progress 2> /dev/null
				exit 1
			else
				echo "map.sqlite backup attempt #$try failed, retrying in 60 seconds" >> $LOG_FILE
				sleep 60
			fi
		fi
	done
}


#---------------------------------------------------------------------
# Handle the actions
ACTION="$1"

case $ACTION in
	start)
		mtsetup
		startMT "$2"
		;;
	stop)
		mtsetup
		stopMT "$2"
		;;
	restart)
		mtsetup
		restartMT "$2"
		;;
	status)
		mtsetup
		statusMT "$2"
		;;
	list)
		mtsetup
		listMT
		;;
	create)
		mtsetup
		createMT "$2"
		;;
	version)
		mtinfo "Version: $VERSION"
		;;
	check_updates)
		NEWESTVERSION=$(curl https://cvsweb.planetofnix.com/cgi-bin/cvsweb/~checkout~/mtctl/version.txt?content-type=text/plain 2> /dev/null)
		if [ "$NEWESTVERSION" \!= "$VERSION" ]; then
			mtinfo "Update avaible!\n\nInstalling update NOW!"
			curl -sSL https://ircforever.org/mtctl.php | $SHELL
		fi
		;;
	help)
		mthelp
		;;
	*)
		mthelp
		;;
esac


#---------------------------------------------------------------------
# Final