Annotation of mtctl/mtctl_default.sh, Revision 1.9
1.1 bountyht 1: #---------------------------------------------------------------------
2: # Filename: mtctl
1.7 minionto 3: # Purpose: Minetest Server Control
4: # License: Copyright (C) 2021-2022 by Miniontoby <miniontoby@ircnow.org>
1.1 bountyht 5: #---------------------------------------------------------------------
1.9 ! minionto 6: VERSION="1.6"
1.2 bountyht 7: config=[]
8: config[0]="no"; config[1]="/usr/local/share/minetest/"
1.1 bountyht 9:
10: #---------------------------------------------------------------------
11: # Alias
12:
13: mtinfo() {
14: MSG="$1"
15: echo -e "mtctl: $MSG" | sed -e 's/\\n/\\nmtctl: /'
16: }
17: mthelp() {
1.9 ! minionto 18: echo -e "usage: mtctl start|stop|restart|status|create|backup|enable|disable worldname\n mtctl list|help|version|check_updates"
1.1 bountyht 19: }
1.5 minionto 20: if [ "x$1" == "x" ]; then mthelp; exit 0; fi
1.1 bountyht 21:
22:
23: #---------------------------------------------------------------------
1.2 bountyht 24: # Setup
25:
26: if [[ "`id -u`" -eq 0 ]]; then CONFDIR=/etc/mtctl; else CONFDIR=$HOME/.mtctl; fi
27: if [ \! -d $CONFDIR ]; then mkdir -p $CONFDIR || exit 1; fi
28: if [ \! -f $CONFDIR/config ]; then
29: mtinfo "\nNo configfile found!\nCreating it now!\n\n"
30: echo -n 'Use custom build minetest folder (yes/no): '; read MTBUILD
1.7 minionto 31: case $MTBUILD in
1.2 bountyht 32: YES|yes) MTBUILD='yes'
33: EXAMPLEDIR="$HOME/minetest"
34: ;;
35: NO|no) MTBUILD='no'
36: EXAMPLEDIR="$HOME/.minetest"
37: ;;
38: *) mtinfo "Error, not a valid option!"
39: exit 1
40: ;;
41: esac
42: echo -n "Insert the path to the minetest folder(eg. $EXAMPLEDIR): "; read MTLOCATION
43:
44: echo -e "builded=$MTBUILD\nlocation=$MTLOCATION" > $CONFDIR/config
45: unset MTBUILD MTLOCATION EXAMPLEDIR
46: mtinfo "Configfile created!!\n\n"
47: fi
48:
49: while read line; do
50: linea="`echo $line | grep -F = 2> /dev/null`"
51: if [ "x$linea" \!= "x" ]; then
52: varname=$(echo "$line" | cut -d '=' -f 1)
53: case $varname in
54: builded) indexnumber=0
55: ;;
56: location) indexnumber=1
57: ;;
58: esac
59: config[$indexnumber]=$(echo "$line" | cut -d '=' -f 2-)
60: fi
61: done < $CONFDIR/config
1.1 bountyht 62:
1.2 bountyht 63: mtsetup() {
64: EXITDIR=${config[1]}/tmp
65: if [ "${config[0]}" == "yes" ]; then SERVEREXE="${config[1]}/bin/minetestserver"; else SERVEREXE="`which minetestserver`"; fi
66: WORLDBASE=${config[1]}/worlds
67: LOGDIR=${config[1]}/log
68: OK=0; cd ${config[1]} || exit 1
69: 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
70: rm temp.test || exit 1
71: if [ \! -f $SERVEREXE ]; then mtinfo "Error: Couldn't determine SERVEREXE setting\n$SERVEREXE"; exit 1; fi
72:
73: mkdir -p $EXITDIR || exit 1
74: mkdir -p $WORLDBASE || exit 1
75: mkdir -p $LOGDIR || exit 1
76: }
1.1 bountyht 77:
78: #---------------------------------------------------------------------
79: # Normal Functions
80:
81: GetPIDS() {
82: 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/ .*//"`
83: }
84:
85: SetWorld() {
86: NAME=$1; if [ "x$NAME" == "x" ]; then mthelp; exit 1; fi
87: WORLDDIR=$WORLDBASE/$NAME; if [ \! -d $WORLDDIR ]; then mtstatus "Failed"; mtinfo "Error: World not found: $NAME"; exit 1; fi
88: 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
1.7 minionto 89: OWNER=`grep '^name.*=' $WORLDDIR/world.conf | sed -e "s/^.*= *//" -e "s/ .*//"`; if [ "x$OWNER" == "x" ]; then mtstatus "Failed"; mtinfo "Error: Owner for $NAME not defined in cfg file"; exit 1; fi
1.1 bountyht 90: }
91: mtstatus() {
92: CHECK="$1"
93: EXTRA=""
94: if [ "$CHECK" == "Ok" ]; then
95: GetPIDS "$WORLDDIR" "$NAME"
96: if [ "x$FOO$BAR" \!= "x" ]; then
97: CHECK="Online"
98: else
99: CHECK="Offline"
100: fi
101: EXTRA="\n"
1.7 minionto 102: elif [ "$CHECK" == "Failed" ]; then EXTRA="\n";
103: elif [ "$CHECK" == "Backup failed" ]; then EXTRA="\n";
104: elif [ "$CHECK" == "Backup success" ]; then EXTRA="\n"; fi
1.1 bountyht 105: echo -ne "\r$NAME($CHECK)$EXTRA"
106: }
107:
108: #---------------------------------------------------------------------
109: # Functions for executing the actions
110:
111: startMT() {
112: SetWorld "$1"; mtstatus
113: GetPIDS "$WORLDDIR" "$NAME"
114: BAR=`echo $BAR | wc -l`
115: if [ "x$FOO" \!= "x" ]; then
116: mtstatus "Failed"
117: mtinfo "Error: World seems already to be running\nIf it is not running, run $ mctl stop $NAME to be sure"
118: exit 1
119: fi
120:
1.5 minionto 121: EXITFLAGWORLD=$EXITDIR/mtctlstop.$NAME
1.7 minionto 122: MINETEST_SUBGAME_PATH=${config[1]}/games
1.1 bountyht 123: # MAYBE Export if linux doesnt work
124:
125: sleep 1; DIR=`pwd` || exit 1; cd $WORLDDIR || exit 1
126: 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
127: cd $DIR || exit 1
128:
129: (
130: while true; do
131: $SERVEREXE --config $WORLDDIR/world.conf --port $PORT --logfile $LOGDIR/debug-$NAME.log --map-dir $WORLDDIR >> $LOGDIR/$NAME.log 2>&1
1.5 minionto 132: if [ -f $EXITFLAGWORLD ]; then exit 0; fi; sleep 10
1.1 bountyht 133: done
134: ) > $LOGDIR/start-$NAME.txt &
135: mtstatus "Ok"
136: }
137:
138: stopMT() {
139: SetWorld "$1"; mtstatus
140: GetPIDS "$WORLDDIR" "$NAME"
141: if [ "x$FOO$BAR" == "x" ]; then mtstatus "Failed"; mtinfo "$NAME seems to be stopped already"; exit 0; fi
1.5 minionto 142: touch $EXITDIR/mtctlstop.$NAME
143:
144: if [ "x$FOO" \!= "x" ]; then
145: kill -SIGINT $FOO
1.7 minionto 146: elif [ "x$BAR" \!= "x" ]; then
147: kill -9 $BAR
1.5 minionto 148: fi
1.1 bountyht 149:
150: mtstatus "Waiting"
1.5 minionto 151: sleep 5; GetPIDS "$WORLDDIR" "$NAME"
1.1 bountyht 152:
153: if [ "x$FOO$BAR" == "x" ]; then
154: mtstatus "Ok"
155: else
156: mtstatus "Waiting."
1.5 minionto 157: sleep 5; GetPIDS "$WORLDDIR" "$NAME"
1.1 bountyht 158: if [ "x$FOO$BAR" == "x" ]; then
159: mtstatus "Ok"
160: else
161: mtstatus "Failed"; mtinfo "Error: Stop of $NAME failed\nTry once more, then consult a sysadmin"; exit 1
162: fi
163: fi
164: }
165:
166: restartMT() {
167: SetWorld "$1"
168: /usr/bin/mtctl stop "$1"|| exit 1
169: /usr/bin/mtctl start "$1" || exit 1
170: }
171:
172: statusMT() {
1.7 minionto 173: SetWorld "$1"
174: GetPIDS "$WORLDDIR" "$NAME"
175: if [ "x$FOO$BAR" \!= "x" ]; then
176: STATUS="Online"
177: else
178: STATUS="Offline"
179: fi
180: LASTLOG="`tail -n 5 $LOGDIR/$NAME.log 2> /dev/null`"
181: echo -e "mtctl.$1 - The Minetest Server Control\n Active: $STATUS\n Process: $FOO\n Main PID: $BAR\n\n$LASTLOG"
1.1 bountyht 182: }
183:
184: listMT() {
185: for WORLDNAME in `ls $WORLDBASE 2> /dev/null | grep '^[a-zA-Z0-9]*$' | sort`; do
186: SetWorld "$WORLDNAME"
1.7 minionto 187: mtinfo "World: $WORLDNAME, Port: $PORT, Owner: $OWNER"
1.1 bountyht 188: done
189: }
190:
191: createMT() {
192: NAME=$1; if [ "x$NAME" == "x" ]; then mthelp; exit 1; fi
193: 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
194: echo -ne "\nServer Description: "; read SERVER_DESCRIPTION
195: PortCheck () {
1.7 minionto 196: CHECK='yes'; if [ -z "${PORT##*[!0-9]*}" ]; then CHECK='no'; ERROR="Ports are only numeric"; return; fi; for x in `ls $WORLDBASE | 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
1.1 bountyht 197: }
1.7 minionto 198: while true; do
199: echo -ne "\nPort: "; read PORT; PortCheck $PORT; if [ "$CHECK" == "no" ]; then echo -e "Failed\nError: $ERROR"; exit 1; else echo -e "Ok"; break; fi;
200: done
1.1 bountyht 201: echo -ne "\nMessage Of The Day [MOTD]: "; read MOTD; echo -ne "\nSeed: "; read SEED; echo -ne "\nCreative (true/false): "; read CREATIVE_MODE
202: echo -ne "\nEnable Damage (true/false): "; read ENABLE_DAMAGE; echo -ne "\nEnable Player Versus Player [PVP] (true/false): "; read ENABLE_PVP
203: echo -ne "\nUsername: "; read USERNAME
204:
205: cd $WORLDBASE; mkdir $NAME; cd $NAME
1.3 minionto 206: 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
1.8 minionto 207: echo -e "creative_mode = $CREATIVE_MODE\nenable_damage = $ENABLE_DAMAGE\nbackend = sqlite3\nplayer_backend = sqlite3\nmod_storage_backend = sqlite3\nauth_backend = sqlite3\ngameid = minetest\nworld_name = $NAME" > world.mt
1.1 bountyht 208: echo -ne "\nWorld created!\nWant to start the world?(yes/no): "; read startit
209: if [[ "$startit" == "yes" ]]; then /usr/bin/mtctl start $NAME; fi
210: echo -e "\nSuccess: \033[1;32mDone \033[m\nFeel free to join your new server at port $PORT"
211: }
212:
1.3 minionto 213: backupMT() {
214: SetWorld "$1"
215: # Backup script from mtlbak by Minix
216: # Copyright (C) 2021 Minix from FreedomTest (freedomtest@protonmail.com)
217:
218: BACKUP_DIR="$CONFDIR/backups/$NAME"
219: LOG_FILE="$LOGDIR/backup_$NAME.log"
220: mkdir -p $BACKUP_DIR
221: echo -ne "" >> $LOG_FILE
222:
223: if [ -f /tmp/$(basename $WORLDDIR)_local_backup_in_progress ]; then
224: 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
225: 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"
226: exit 1
227: fi
228:
229: touch /tmp/$(basename $WORLDDIR)_local_backup_in_progress
230: rm $BACKUP_DIR/map.sqlite.tmp* 2> /dev/null #Cleaning in case of crashed attempts
231:
232: echo -e "\n$(date) backup started" >> $LOG_FILE
233: mtstatus "Backup started"
234:
235: try=0
236: while [ $try -lt 5 ]; do
237: echo "Starting backup attempt #$(expr $try + 1) on $(date)" >> $LOG_FILE
238: sqlite3 $WORLDDIR/map.sqlite ".backup $BACKUP_DIR/map.sqlite.tmp" 2> /dev/null
239: if [ $? -eq 0 ]; then
240: mv $BACKUP_DIR/{map.sqlite.tmp,map.sqlite}
241: #Backup auth.sqlite and players.sqlite files properly
242: until sqlite3 $WORLDDIR/auth.sqlite ".backup $BACKUP_DIR/auth.sqlite" 2> /dev/null; do
243: continue
244: done
245: until sqlite3 $WORLDDIR/players.sqlite ".backup $BACKUP_DIR/players.sqlite" 2> /dev/null; do
246: continue
247: done
1.7 minionto 248: rsync -ptrW --delete --exclude "*.sqlite" $WORLDDIR/ $BACKUP_DIR/
1.3 minionto 249: echo "Backup finished succesfully on $(date)" >> $LOG_FILE
250: mtstatus "Backup success"
251: rm /tmp/$(basename $WORLDDIR)_local_backup_in_progress 2> /dev/null
252: exit 0
253: else
254: rm $BACKUP_DIR/map.sqlite.tmp 2> /dev/null
255: try=$(expr $try + 1)
256: if [ $try -eq 5 ]; then
257: echo "Backup failed 5 times, aborting on $(date)" >> $LOG_FILE
258: mtstatus "Backup failed"
259: rm /tmp/$(basename $WORLDDIR)_local_backup_in_progress 2> /dev/null
260: exit 1
261: else
262: echo "map.sqlite backup attempt #$try failed, retrying in 60 seconds" >> $LOG_FILE
263: sleep 60
264: fi
265: fi
266: done
267: }
268:
1.9 ! minionto 269: startupMT() {
! 270: if [[ -f "$CONFDIR/startup" ]]; then
! 271: if [[ -f "$CONFDIR/.booted" ]]; then
! 272: exit 1
! 273: fi
! 274: failed=""
! 275: while read -r line
! 276: do
! 277: /usr/bin/mtctl start "$line" || failed="$failed, $line"
! 278: done < "$CONFDIR/startup"
! 279: if [[ "x$failed" == "x" ]]; then
! 280: echo "Success!"
! 281: else
! 282: echo "Servers have failed to start$failed"
! 283: fi
! 284: touch $CONFDIR/.booted
! 285: fi
! 286: }
! 287:
! 288: enableMT() {
! 289: SetWorld "$1"
! 290: if [[ -f "$CONFDIR/startup" ]]; then
! 291: INCLUDES=$(grep -x "$NAME" $CONFDIR/startup)
! 292: if [[ "X$INCLUDES" == "X$NAME" ]]; then
! 293: echo "$NAME is already enabled!"
! 294: return
! 295: fi
! 296: fi
! 297: if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q '/usr/bin/mtctl startup'; echo $?) == 1 ]]; then
! 298: set -f
! 299: crontab -l > temp
! 300: echo '@reboot rm $HOME/.mtctl/.booted 2>/dev/null && /usr/bin/mtctl startup' >> temp
! 301: cat temp | crontab -
! 302: rm temp
! 303: set +f
! 304: fi
! 305: echo "$NAME" >> $CONFDIR/startup
! 306: echo "$NAME is enabled!"
! 307: }
! 308:
! 309: disableMT() {
! 310: SetWorld "$1"
! 311: if [[ -f "$CONFDIR/startup" ]]; then
! 312: INCLUDES=$(grep -x "$NAME" $CONFDIR/startup)
! 313: if [[ "X$INCLUDES" == "X$NAME" ]]; then
! 314: grep -xv "$NAME" $CONFDIR/startup > temp && mv temp $CONFDIR/startup
! 315: echo "$NAME is disabled!"
! 316: return
! 317: fi
! 318: fi
! 319: echo "$NAME is already disabled!"
! 320: }
! 321:
1.3 minionto 322:
1.1 bountyht 323: #---------------------------------------------------------------------
324: # Handle the actions
1.2 bountyht 325: ACTION="$1"
1.1 bountyht 326:
327: case $ACTION in
328: start)
1.2 bountyht 329: mtsetup
1.1 bountyht 330: startMT "$2"
331: ;;
332: stop)
1.2 bountyht 333: mtsetup
1.1 bountyht 334: stopMT "$2"
335: ;;
336: restart)
1.2 bountyht 337: mtsetup
1.1 bountyht 338: restartMT "$2"
339: ;;
340: status)
1.2 bountyht 341: mtsetup
1.1 bountyht 342: statusMT "$2"
343: ;;
344: list)
1.2 bountyht 345: mtsetup
1.1 bountyht 346: listMT
347: ;;
348: create)
1.2 bountyht 349: mtsetup
1.1 bountyht 350: createMT "$2"
1.7 minionto 351: ;;
352: backup)
353: mtsetup
354: backupMT "$2"
1.9 ! minionto 355: ;;
! 356: startup)
! 357: startupMT
! 358: ;;
! 359: enable)
! 360: #mtsetup
! 361: enableMT "$2"
! 362: ;;
! 363: disable)
! 364: #mtsetup
! 365: disableMT "$2"
1.1 bountyht 366: ;;
367: version)
368: mtinfo "Version: $VERSION"
369: ;;
370: check_updates)
371: NEWESTVERSION=$(curl https://cvsweb.planetofnix.com/cgi-bin/cvsweb/~checkout~/mtctl/version.txt?content-type=text/plain 2> /dev/null)
372: if [ "$NEWESTVERSION" \!= "$VERSION" ]; then
373: mtinfo "Update avaible!\n\nInstalling update NOW!"
1.4 minionto 374: curl -sSL https://ircforever.org/mtctl.php | $SHELL
1.1 bountyht 375: fi
1.2 bountyht 376: ;;
1.1 bountyht 377: help)
378: mthelp
379: ;;
380: *)
381: mthelp
382: ;;
383: esac
384:
385:
386: #---------------------------------------------------------------------
387: # Final
CVSweb