-
Notifications
You must be signed in to change notification settings - Fork 0
/
mcbackup.sh
442 lines (412 loc) · 13.8 KB
/
mcbackup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
#!/bin/bash
#############################################################################
# __ __ ___ ___ _ #
# | \/ |/ __| _ ) __ _ __| |___ _ _ __ #
# | |\/| | (__| _ \/ _` / _| / / || | '_ \ #
# |_| |_|\___|___/\__,_\__|_\_\\_,_| .__/ #
# MINECRAFT BACKUP |_| #
#############################################################################
# MCBackup - A tool to aid Minecraft server backups via bash command line. #
# Copyright (C) 2012 GrimWorld #
# #
# 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 3 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, see <http://www.gnu.org/licenses/>. #
# #
# Designed by CJ for GrimWorld.co #
# 07/01/12 (v0.5) beta #
#############################################################################
## Default values for settings
ARCHIVE=true
COMPRESSION=false
RESTORE=false
HELP=false
LIST=false
QUIET=false
REMOVE=false
# User Variables!
BACKUP_PATH="/backups"
MINECRAFT_PATH="/minecraft"
WORLD_PREFIX="world"
SERVER_COMMAND=$(cat /minecraft/command.txt)
SCREEN_COMMAND="screen -x"
REMOVE_DAYS=7
BKP_FULL=true
BKP_WORLD=false
BKP_WORLDS=false
BKP_CFG=false
BKP_PLUGINS=false
BKP_DB=false
SHOW_MESSAGES=true
## Preamble
echo "==============================================="
echo " __ __ ___ ___ _ "
echo " | \/ |/ __| _ ) __ _ __| |___ _ _ __ "
echo " | |\/| | (__| _ \/ _' / _| / / || | '_ \ "
echo " |_| |_|\___|___/\__,_\__|_\_\\_,_| .__/ "
echo " MINECRAFT BACKUP |_| "
echo "-----------------------------------------------"
## Option decoding
for arg in $@
do
case $arg in
-a) ARCHIVE=true;;
-f) BKP_FULL=true;;
-c) BKP_CFG=true; BKP_FULL=false;;
-d) ARCHIVE=false;;
-l) LIST=true;;
-m) SHOW_MESSAGES=false;;
-p) BKP_PLUGINS=true; BKP_FULL=false;;
-q) QUIET=true;;
-r:*) RESTORE=$(echo $arg | awk -F":" '{print $2}');;
-s) BKP_DB=true; BKP_FULL=false;;
-w:*) BKP_WORLD=$(echo $arg | awk -F":" '{print $2}'); BKP_FULL=false;;
-W) BKP_WORLDS=true; BKP_WORLD=false; BKP_FULL=false;;
-x) REMOVE=true;;
-z) COMPRESSION=true;;
-h | ? | -r | -w | -*) HELP=true;;
esac
done
#### MAIN PROGRAM ####
### Functions
## Utility functions
function end() {
# Parameters: exit code
# end works identical to exit, but displays a bottom divider in the process
echo "==============================================="
exit $1
}
function serverStart() {
# Blank current line in case something is already typed
$SCREEN_COMMAND -X stuff "$(printf '\r')"
if $SHOW_MESSAGES; then
$SCREEN_COMMAND -X stuff "say Initiating server backup - $(date -u +'%T GMT')$(printf '\r')"
fi
$SCREEN_COMMAND -X stuff "save-off$(printf '\r')"
$SCREEN_COMMAND -X stuff "save-all$(printf '\r')"
}
function serverFinish() {
# Parameters: exit code of backup commands
# Blank current line in case something is already typed
$SCREEN_COMMAND -X stuff "$(printf '\r')"
if [ $1 == 0 ]; then cStatus="completed"; else cStatus="failed"; fi
$SCREEN_COMMAND -X stuff "save-on$(printf '\r')"
if $SHOW_MESSAGES; then
$SCREEN_COMMAND -X stuff "say Server backup $cStatus - $(date -u +'%T GMT')$(printf '\r')"
fi
}
function validateComponents() {
# This is not necessary right now - will make later
if [ $RESTORE == false ]; then
echo ""
else
echo ""
fi
}
function createName() {
# Append date to backup name and trailing dash
bkpName=$(date -u +%y%m%d)-
# Append enabled options to end of filename
if $ARCHIVE; then bkpName=$bkpName"a"; else bkpName=$bkpName"d"; fi
if $COMPRESSION; then bkpName=$bkpName"z"; fi
if $BKP_DB; then bkpName=$bkpName"s"; fi
if $BKP_CFG; then bkpName=$bkpName"c"; fi
if $BKP_PLUGINS; then bkpName=$bkpName"p"; fi
if $BKP_WORLDS; then bkpName=$bkpName"W"; fi
if $BKP_FULL; then bkpName=$bkpName"f"; fi
if [ $BKP_WORLD != false ]; then bkpName=$bkpName"w:"$BKP_WORLD; fi
# If file exists, append incrementing number to end
bkpNameTmp=$bkpName
i=1
# While file exists, increment suffic number
while [ -f $BACKUP_PATH/$bkpNameTmp.tar -o -f $BACKUP_PATH/$bkpNameTmp.tar.gz -o -d $BACKUP_PATH/$bkpNameTmp ];
do
bkpNameTmp=$bkpName-$i
i=$[i+1]
done
# Append file extension and store result
if $ARCHIVE; then bkpName=$bkpNameTmp.tar; fi
if $COMPRESSION; then bkpName=$bkpName.gz; fi
if ! $ARCHIVE; then bkpName=$bkpNameTmp/; fi
}
function configureOptions() {
# Parameters: type: BACKUP or RESTORE
confType=$1
# Set the working directory
# This is a crucial step for any 'find' commands to search for specific folders
if [ $confType == 'BACKUP' ]; then
cd $MINECRAFT_PATH
else
cd $MINECRAFT_PATH
#cd $BACKUP_PATH/$rName
fi
if $ARCHIVE; then echo " +ARCHIVED"; else echo " +FOLDER"; fi
if $COMPRESSION; then echo " +COMPRESSED"; fi
if $BKP_CFG; then
# Tell user what's being backed up
echo " +CONFIG $confType"
# Main directory, and everything in plugin directory only
# Jars are not allowed to be backed up
# Find matches within the directory cd'd to earlier, strip leading ./
paths="$paths $(find . -maxdepth 1 -type f ! -iname '*.jar' | sed -e 's/\.\///')"
paths="$paths $(find ./plugins -type f ! -iname '*.jar' | sed -e 's/\.\///')"
fi
if $BKP_DB; then
echo " +MYSQL $confType"
paths="$paths mysql"
fi
if $BKP_PLUGINS; then
echo " +PLUGIN $confType"
paths="$paths plugins"
fi
if [ $BKP_WORLD != false ]; then
echo " +SINGLE WORLD: $BKP_WORLD"
paths="$paths $BKP_WORLD"
fi
if $BKP_WORLDS; then
echo " +ALL WORLDS"
# Get all folders starting with world prefix in the pre-defined path
# Remove unnecessary ./s with sed
paths="$paths $(find . -maxdepth 1 -type d -name '$WORLD_PREFIX*' | sed -e 's/\.\///')"
fi
if $BKP_FULL; then
echo " +FULL $confType"
paths=" *"
fi
}
## Non-executing functions such as help and list
function showHelp() {
echo "Usage:"
echo "mcbackup (-options)"
echo "Default: Full backup to tar archive"
echo "File names (IDs) are structured as: YYMMDD-OPTIONS(-NUM)"
echo "All times are UTC/GMT"
echo " Option | Description "
echo "-------------|---------------------------------"
echo "-a | Write to archive/tar (default option)"
echo "-c | Backup/restore config files"
echo "-d | Backup as a folder rather than tar. Cannot use -z"
echo "-f | Make full backup (default option)"
echo "-h | Show this help page"
echo "-l | Show a list of backups and IDs"
echo "-m | Hide server 'say' messages"
echo "-p | Backup/restore plugins"
echo "-q | Do not prompt for confirmation"
echo "-r:backupID | Restore from specified backup (will prompt for confirmation)"
echo "-s | Backup SQL databases"
echo "-w:worldName | Backup/restore single world"
echo "-W | Backup/restore all worlds"
echo "-x | Remove backups older than $REMOVE_DAYS days old"
echo "-z | G-Zip Compression"
}
function showList() {
echo "---------------Available Backups---------------"
echo " BackupID | Date/Time "
echo "--------------------|--------------------------"
# Get contents of backup folder
# List all names (before '.') of entries starting with a number
cd $BACKUP_PATH
for file in $(dir -x -d *); do
# Verify if it's a backup ID
if [[ $file =~ ^[0-9]+- ]]; then
# Take out part before .
part=$(echo $file | awk -F"." '{print $1}')
# Write output
echo "$(printf '%-19s' $part) | $(date -u -r $file +'%b %d %Y %T GMT')"
fi
done
}
## Executing functions (the real stuff)
function createBkp() {
# Generate an ID tag
createName
# Show the backup information
echo "CREATING BACKUP $BACKUP_PATH/$bkpName"
echo "FROM $MINECRAFT_PATH WITH OPTIONS"
# Show option messages
# Configure paths to backup
paths=""
configureOptions "BACKUP"
# Prompt for continuation
if ! $QUIET; then
read -p "ARE YOU SURE YOU WANT TO BACKUP? (Y/N)>" yn
if [[ ! $yn =~ ^[Yy]$ ]]; then
echo "---------------BACKUP CANCELLED----------------"
end 1
fi
fi
# Validate the query
validateComponents
# Set commands
if $ARCHIVE; then
command="tar -cpv"
if $COMPRESSION; then
command=$command"z"
fi
# Paths starts with a space </protip>
command=$command"C $MINECRAFT_PATH -f $BACKUP_PATH/$bkpName$paths"
prep=""
else
prep="mkdir $BACKUP_PATH/$bkpName"
# Make each path an absolute path. Currently, they are all relative
for path in $paths; do
path=$MINECRAFT_PATH/$path
done
command="cp -av --parents$paths $BACKUP_PATH/$bkpName"
fi
# Send server start commands
serverStart
# Do the work!
#echo "DEBUG: $command"
$prep # Extra command
# Make output appear on single line
#$command | cut -b1-$(tput cols) | sed -u 'i\\o033[2K' | tr '\n' '\r'; echo
$command
status=$?
# Send server finish commands
serverFinish $status
# Complete
if [ $status == 0 ]; then cStatus="COMPLETE"; else cStatus="FAILED"; fi
echo "----------------BACKUP $cStatus----------------"
# Delete old backups
if $REMOVE; then
echo "--------------DELETING OLD BACKUPS-------------"
if ! $QUIET; then
echo "ARE YOU SURE YOU WANT TO REMOVE BACKUPS"
read -p "OLDER THAN $REMOVE_DAYS DAYS? (Y/N)>" yn
if [[ ! $yn =~ ^[Yy]$ ]]; then
echo "---------------DELETING CANCELLED--------------"
end $status
fi
fi
# Remove all files older than $REMOVE_DAYS
# Get date
date=$(date -u +%y%m%d)
date=$(($date-$REMOVE_DAYS))
cd $BACKUP_PATH
# Get all backup files
for file in $(dir -d *); do
# Verify if it's a backup ID
if [[ $file =~ ^[0-9]+- ]]; then
# Take out part before -
part=$(echo $file | awk -F"-" '{print $1}')
# Verify age
if [ $date -gt $part ]; then
# Remove
rm -r $file
fi
fi
done
echo "----------------------DONE---------------------"
fi
end $status
}
function restoreBkp() {
# Set actual filename of backup
rName=false
if [ -f $BACKUP_PATH/$RESTORE.tar ]; then
rName=$RESTORE.tar
ARCHIVE=true
fi
if [ -f $BACKUP_PATH/$RESTORE.tar.gz ]; then
rName=$RESTORE.tar.gz
COMPRESSION=true
fi
if [ -d $BACKUP_PATH/$RESTORE ]; then
rName=$RESTORE/
ARCHIVE=false
fi
# If the filename isn't set, it doesn't exist
if [ $rName == false ]; then
echo "FILE DOES NOT EXIST"
showList
end 1
fi
# Display restore information
bkpDate=$(date -u -r $BACKUP_PATH/$rName +"%b %d %Y %T GMT")
echo "RESTORING BACKUP $BACKUP_PATH/$rName"
echo "MODIFIED $bkpDate"
echo "TO $MINECRAFT_PATH WITH OPTIONS"
# Show option messages
# Configure paths to backup
paths=""
configureOptions "RESTORE"
# Prompt for continuation
if ! $QUIET; then
read -p "ARE YOU SURE YOU WANT TO RESTORE? (Y/N)>" yn
if [[ ! $yn =~ ^[Yy]$ ]]; then
echo "---------------RESTORE CANCELLED----------------"
end 1
fi
fi
# Set commands
if $ARCHIVE; then
command="tar -xpv"
if $COMPRESSION; then
command=$command"z"
fi
# Paths starts with a space </protip>
command=$command"C $MINECRAFT_PATH -f $BACKUP_PATH/$rName$paths"
prep=""
else
# Make each path an absolute path. Currently, they are all relative
for path in $paths; do
path=$BACKUP_PATH/$rName/$path
done
command="cp -afv --parents$paths $MINECRAFT_PATH"
fi
# Shut down server for maintenance
if $SHOW_MESSAGES; then
$SCREEN_COMMAND -X stuff "say Rolling back to: $(date -u -r $rName +'%b %d %Y %T GMT')$(printf '\r')"
$SCREEN_COMMAND -X stuff "say 30 seconds remaining - please log out$(printf '\r')"
echo "RESTORE IN 30 SECONDS (Ctrl+C to cancel)"
sleep 10
$SCREEN_COMMAND -X stuff "say 20 seconds remaining - please log out$(printf '\r')"
echo "RESTORE IN 20 SECONDS"
sleep 10
$SCREEN_COMMAND -X stuff "say 10 seconds remaining - please log out$(printf '\r')"
echo "RESTORE IN 10 SECONDS"
sleep 10
fi
# Service stop
service minecraft stop
# Normal stop
$SCREEN_COMMAND -X stuff "stop$(printf '\r')"
# Do the work!
#echo "DEBUG: $command"
$command
status=$?
# Restart server
# Service start
service minecraft start
# Normal start
#$SERVER_COMMAND
# Complete
if [ $status == 0 ]; then cStatus="COMPLETE"; else cStatus="FAILED"; fi
echo "----------------RESTORE $cStatus----------------"
end $status
}
## Main program loop
if $HELP; then
showHelp
end 1
fi
if $LIST; then
showList
end 0
fi
if [ $RESTORE == false ]; then
createBkp
else
restoreBkp
fi
end 1