mcwrapper 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ mcwrapper.conf
2
+ mcwrapper.pid
3
+ command_pipe
4
+ backups
5
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mcwrapper.gemspec
4
+ gemspec
@@ -0,0 +1,14 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mcwrapper (1.6.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ mcwrapper!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Spike Grobstein <spikegrobstein@mac.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,183 @@
1
+ # mcwrapper
2
+
3
+ A Minecraft Server wrapper for OSX and Linux (and any othe POSIX-compatible OS).
4
+ `mcwrapper` enables a Minecraft server admin to easily start and stop their server, send
5
+ commands, and also do safe, automatic world data backups.
6
+
7
+ *I'm MC Wrapper and I'm here to say that I wanna wrap up minecraft so everything'll be okay.*
8
+
9
+ `mcwrapper` has been designed for ease of use and simplicity, but also kept developers in mind.
10
+ It provides facilities for reading configuration options from Minecraft Server and `mcwrapper`
11
+ itself and also has a robust collection of status codes that it returns when it's run.
12
+
13
+ ## Install
14
+
15
+ `mcwrapper` can now be installed via RubyGems.org. To install, simply run the following command:
16
+
17
+ gem install mcwrapper
18
+
19
+ This will install a new executable in your RubyGems installation's `bin` folder. To verify
20
+ that it installed properly, you can run:
21
+
22
+ mcwrapper --version
23
+
24
+ This should show your currently installed version.
25
+
26
+ ## Quickstart
27
+
28
+ If you don't have `minecraft_server.jar` installed on your machine:
29
+
30
+ mkdir minecraft_server
31
+ cd minecraft_server
32
+ mcwrapper install
33
+
34
+ Follow the instructions (press enter when prompted). This will download the current version
35
+ of `minecraft_server.jar` from Mojang and place it in the correct location.
36
+
37
+ To start Minecraft Server, `cd` into the directory with `minecraft_server.jar` and execute:
38
+
39
+ mcwrapper start
40
+
41
+ The above will start up a Minecraft server instance using default settings. All support files
42
+ related to mcwrapper will be stored in the `minecraft_server.jar` directory.
43
+
44
+ ## Usage
45
+
46
+ Basic usage is:
47
+
48
+ mcwrapper <action> [ <action_params> ]
49
+
50
+ Use the help action to see a full breakdown of usage:
51
+
52
+ mcwrapper help
53
+
54
+ See the Configuration section below for instructions on modifying the default configuration and
55
+ creating an `mcwrapper.config` file.
56
+
57
+ ## Actions
58
+
59
+ See the wiki page for actions for detailed information:
60
+
61
+ https://github.com/spikegrobstein/mcwrapper/wiki/Actions
62
+
63
+ ## Configuration
64
+
65
+ `mcwrapper` is configured using environment variables, but you can also specify these settings
66
+ in a `mcwrapper.conf` file. `mcwrapper` searches for this file, in the following order, in
67
+ the following places:
68
+
69
+ 1. `$MCWRAPPER_CONFIG_PATH` environment variable
70
+ 2. `./mcwrapper.conf`
71
+ 3. `~/.mcwrapper.conf`
72
+ 4. `/etc/mcwrapper.conf`
73
+
74
+ All parameters that can be set in this file can also be set in your shell's environment either
75
+ via using `export` directly or by putting in your `.bashrc` or `.bash_profile`.
76
+
77
+ The `mcwrapper.conf` file and other configuration is not required as it has sensible defaults
78
+ and will try to find the location of `minecraft_server.jar` on its own (starting with the
79
+ current directory). An example `mcwrapper.conf-example` file is located in the distribution which
80
+ contains documentation and examples of all configuration options.
81
+
82
+ See the Configuration wiki page for detailed information:
83
+
84
+ https://github.com/spikegrobstein/mcwrapper/wiki/Configuration
85
+
86
+ ## Details
87
+
88
+ When running, `mcwrapper` uses 2 files:
89
+
90
+ * `mcwrapper.pid` -- the pid of the currently running process. This is used by `mcwrapper` for
91
+ sanity checks but can also be used by 3rd party scripts to see if `minecraft_server` is running.
92
+ * `command_input` -- the FIFO used for communicating with the server.
93
+
94
+ The names and locations of the above files are both configurable in `mcwrapper.conf`.
95
+
96
+ You can run arbitrary commands either through the mcwrapper script as seen in the Quickstart
97
+ or you can output commands directly to the `command_input` FIFO. This is handy if you write
98
+ re-usable Minecraft scripts.
99
+
100
+ Examples of working directly with the FIFO:
101
+
102
+ echo "tell spizzike you are awesome" > command_input
103
+
104
+ If you have a file called `gimmie_diamond.mcs` containing the following text:
105
+
106
+ give spizzike 264
107
+ give spizzike 264
108
+ give spizzike 264
109
+ give spizzike 264
110
+ give spizzike 264
111
+ give spizzike 264
112
+
113
+ You can run that all through the Minecraft server with the following command:
114
+
115
+ command_input < gimmie_diamond.mcs
116
+
117
+ ## Backing Up Minecraft Data
118
+
119
+ Since it's not safe to back up the world data while the server is running, you need to force
120
+ a save, then disable writing world data to disk during a backup.
121
+
122
+ `mcwrapper` contains a backup action for just this purpose. To back up your current world data
123
+ directory, run the following command:
124
+
125
+ mcwrapper backup
126
+
127
+ `mcwrapper` will read your `server.properties` file to learn the location of your world data
128
+ and, after flushing anything in memory, creates a timestamped directory in the minecraft server
129
+ directory and creates a symlink to the latest backup called `latest`.
130
+
131
+ By default, the backup action will simply copy your world data and server configuration (white
132
+ lists, server.properties, ban lists, etc) into the backups directory, but it can be configured
133
+ to zip or tgz the backup data. See `mcwrapper.conf-example` for information on this.
134
+
135
+ Assuming your `mcwrapper` lives in `/usr/local/minecraft/mcwrapper`, `backup` will do the
136
+ following:
137
+
138
+ 1. create `/usr/local/minecraft/backups/YYYYMMDDHHMMSS` where YYYYMMDDHHMMSS is the current
139
+ timestamp
140
+ 2. copy `/usr/local/minecraft/world` and any other configuration data in `/usr/local/minecraft`
141
+ into the above directory
142
+ 3. create a symlink to the latest backup at `/usr/local/minecraft/backups/latest`
143
+ 4. delete old backups. Defaults to keeping the latest 5.
144
+
145
+ The name of the `latest` backup can be configured by editing that setting in `mcwrapper`. You
146
+ can also configure how many previous backups are kept. Again, see `mcwrapper.conf-example` for
147
+ information on doing this.
148
+
149
+ For an example of doing automated backups via `cron` see the wiki:
150
+
151
+ https://github.com/spikegrobstein/mcwrapper/wiki/Automated-Backups
152
+
153
+ ## Restoring from a Minecraft backup
154
+
155
+ If you ever find a need to restore from a previous world data backup, `mcwrapper` now using the
156
+ `restore` action and passing a path (full or relative) to the backup you wish to restore:
157
+
158
+ mcwrapper restore backups/20111118123456
159
+
160
+ The above example will perform the following actions:
161
+
162
+ 1. gracefully stop the Minecraft server if it's running.
163
+ 2. do a non-clobbering backup of the current world data. This means that regardless of what
164
+ your backup retention settings are, it will not delete any while creating a backup of the
165
+ current world data.
166
+ 3. copy the specified backup directory into the servers's world directory.
167
+ 4. start Minecraft server up if it was previously running.
168
+
169
+ In addition to the above, a file is also created inside the world directory called
170
+ `RESTORED_FROM` which contains the argument specified to the `restore` action.
171
+
172
+ ## The Future (Todo List)
173
+
174
+ In the future I aim to create sysV init scripts for Linux (Ubuntu flavoured) and OSX launchd
175
+ configs. I also plan on including Minecraft backup support to SnapBackup, my backup
176
+ script (http://github.com/spikegrobstein/snapbackup).
177
+
178
+ ## About
179
+
180
+ `mcwrapper` is written by Spike Grobstein <me@spike.cx>
181
+ http://sadistech.com
182
+ http://spike.grobste.in
183
+ http://github.com/spikegrobstein
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $: << File.dirname(__FILE__) + '/../lib'
4
+ require 'mcwrapper'
5
+
6
+ # simple wrapper for executing mcwrapper.
7
+ exec MCWrapper::MCWRAPPER, *ARGV
8
+
@@ -0,0 +1,6 @@
1
+ module MCWrapper
2
+ MCWRAPPER = File.dirname(__FILE__) + '/../libexec/mcwrapper'
3
+ # Your code goes here...
4
+ end
5
+
6
+ require "mcwrapper/version"
@@ -0,0 +1,4 @@
1
+ module MCWrapper
2
+ # VERSION = `#{ MCWRAPPER } --version`.split(/\s/).last
3
+ VERSION = '1.6.0'
4
+ end
@@ -0,0 +1,1189 @@
1
+ #! /bin/bash -
2
+
3
+ ## MCWrapper
4
+ # A utility for manging a Minecraft Server installation
5
+ # Start, stop and safely back up your world data without service interruption.
6
+ # https://github.com/spikegrobstein/mcwrapper
7
+ ##
8
+
9
+ MCWRAPPER_VERSION="1.6.0"
10
+
11
+ #### Exit Codes
12
+
13
+ # no error
14
+ EXIT_SUCCESS=0
15
+
16
+ # generic bad exit code
17
+ EXIT_GENERIC_FAILURE=1
18
+
19
+ # bad commandline params
20
+ EXIT_BAD_PARAMS=2
21
+ EXIT_UNKNOWN_CONFIG_SETTING=3
22
+ EXIT_INVALID_ACTION=4
23
+
24
+ # server-running related failures
25
+ EXIT_SERVER_NOT_RUNNING=5
26
+ EXIT_SERVER_ALREADY_RUNNING=6
27
+ EXIT_SERVER_DISAPPEARED=7
28
+ EXIT_SERVER_CANNOT_START=8
29
+
30
+ # support file related codes:
31
+ EXIT_MINECRAFT_SERVER_NOT_FOUND=10
32
+ EXIT_NO_SERVER_PROPERTIES=11
33
+ EXIT_SERVER_LOG_NOT_FOUND=12
34
+
35
+ EXIT_MAKE_FIFO_FAILED=20
36
+ EXIT_SEND_COMMAND_FAILED=21
37
+
38
+ EXIT_NO_JAVA=30
39
+
40
+ EXIT_GENCONFIG_EXISTS=40
41
+ EXIT_GENCONFIG_ERROR=41
42
+
43
+ # backup related codes:
44
+ EXIT_CANNOT_CREATE_BACKUP_DIR=50
45
+ EXIT_CANNOT_BACKUP_WORLD_DATA=51
46
+ EXIT_CANNOT_BACKUP_CONFIGS=52
47
+ EXIT_FAILED_TO_DELETE_SYMLINK=53
48
+ EXIT_ERORR_CREATING_SYMLINK=54
49
+ EXIT_BACKUPS_DISABLED=55
50
+ EXIT_LATEST_BACKUP_NOT_FOUND=56
51
+ EXIT_CANNOT_RESTORE_WORLD=57
52
+
53
+ EXIT_BAD_COMPRESSION_TYPE=60
54
+
55
+ # installer related codes:
56
+ EXIT_CANNOT_BACKUP_OLD_MINECRAFT_SERVER=70
57
+ EXIT_DOWNLOAD_MINECRAFT_SERVER_FAILED=71
58
+ EXIT_CREATE_MINECRAFT_SERVER_DIR_FAILED=72
59
+ EXIT_CANNOT_MOVE_MINECRAFT_SERVER=73
60
+ EXIT_EXISTING_MINECRAFT_SERVER_NOT_FOUND=74
61
+
62
+ # misc other codes:
63
+ EXIT_NOT_IMPLEMENTED=98
64
+ EXIT_RUNNING_AS_ROOT=99
65
+
66
+ #### End Exit Codes
67
+
68
+ ## basic constants to be used through the app
69
+ #
70
+ # initialize some variables about the location of mcwrapper and its support files.
71
+ pushd "$(dirname "$0")" &> /dev/null
72
+ MCWRAPPER_DIR="$PWD"
73
+ popd &> /dev/null
74
+ MCWRAPPER="$(basename "$0")"
75
+
76
+ MCWRAPPER_CONFIG_NAME="mcwrapper.conf"
77
+
78
+ # default filename of the minecraft server
79
+ MINECRAFT_SERVER_NAME="minecraft_server.jar"
80
+
81
+ # filename of the minecraft server.properties file
82
+ MINECRAFT_SERVER_PROPERTIES_NAME="server.properties"
83
+
84
+ # STDERR echo function for error output
85
+ function errcho {
86
+ echo $@ >&2
87
+ }
88
+
89
+ # absolutely, under no circumstances, let mcwrapper be run as root!!!!
90
+ if [[ `id -u` = 0 ]]; then
91
+ errcho "You have started mcwrapper as root."
92
+ errcho "This is not recommended. Please run as an un-privilaged user."
93
+ errcho ""
94
+ exit $EXIT_RUNNING_AS_ROOT
95
+ fi
96
+
97
+ function print_usage {
98
+ local MCWRAPPER_NAME=$( basename $0 )
99
+
100
+ echo "USAGE:"
101
+ echo " $MCWRAPPER_NAME <action> [ <action_options> ]"
102
+ echo ""
103
+ echo "Action can be one of:"
104
+ echo " help -- this usage screen"
105
+ echo " version -- outputs mcwrapper's version number"
106
+ echo " about -- output information about mcwrapper"
107
+ echo " start -- start the server if it's not already running"
108
+ echo " stop -- stop a running server"
109
+ echo " restart -- restart a running server (issues stop, waits for it to stop, then starts)"
110
+ echo " status -- whether the server is running or not"
111
+ echo " check -- runs basic sanity checks"
112
+ echo " install -- runs an installation wizard to walk you through setup"
113
+ echo " update -- update your Minecraft Server binary"
114
+ echo " log -- follows the server log as it's written to"
115
+ echo " backup -- safe backup of your Minecraft world data"
116
+ echo " restore -- restore a specified backup. Takes the path to the backup as an argument"
117
+ echo " restoring from a backup will cause a hard restart of the server and"
118
+ echo " all users will be disconnected. A non-destructive backup of current world"
119
+ echo " data will be created."
120
+ echo " example: $MCWRAPPER_NAME restore /usr/local/minecraft/backups/20121118235500"
121
+ echo " genconfig -- copy the default config file to \$MINECRAFT_SERVER_PATH"
122
+ echo " config -- used to read configuration information about mcwrapper"
123
+ echo " example: $MCWRAPPER_NAME config serverpath"
124
+ echo " valid configuration parameters are:"
125
+ echo " * serverpath -- absolute path to minecraft_server.jar"
126
+ echo " * serverdir -- absolute path to server directory (containing minecraft_server.jar)"
127
+ echo " * pidfile -- absolute path to mcwrapper pidfile"
128
+ echo " * pid -- the pid of the currently running minecraft server process"
129
+ echo " * pipe -- absolute path to the mcwrapper command pipe"
130
+ echo " * command -- the command that will be used to launch the minecraft server"
131
+ echo " * backupdir -- the path to the backup directory"
132
+ echo " * latestbackup -- the path to the latest backup if there is one"
133
+ echo " * backup-retention -- the number of backups to keep before deleting old ones"
134
+ echo " prop -- used to read server.properties configuration information"
135
+ echo " best when used with external scripts"
136
+ echo " example: $MCWRAPPER_NAME prop level-name"
137
+ echo " if no property name is supplied, mcwrapper will print out all property keys from the file."
138
+ echo " command -- execute a minecraft server command. As an alternative to writing to the FIFO. Also aliased as 'cmd'"
139
+ echo ""
140
+ echo "For README and source code, see: https://github.com/spikegrobstein/mcwrapper"
141
+ echo "For additional documentation, see: https://github.com/spikegrobstein/mcwrapper/wiki"
142
+ echo ""
143
+ }
144
+
145
+ function print_version {
146
+ echo "mcwrapper $MCWRAPPER_VERSION"
147
+ }
148
+
149
+ function print_about {
150
+ print_version
151
+ echo "https://github.com/spikegrobstein/mcwrapper"
152
+ echo "Finally, simplified management of your Minecraft server."
153
+ echo "Start, stop, monitor, backup."
154
+ echo "Run with no arguments to see usage."
155
+ echo ""
156
+ }
157
+
158
+ # figure out where the config file lives
159
+ # first check to see if it's set in the MCWRAPPER_CONFIG_PATH
160
+ # then check: ./mcwrapper.conf, ~/.mcwrapper.conf, /etc/mcwrapper.conf
161
+ function get_config_path {
162
+
163
+ # if it's defined in an ENV var, then let's use that
164
+ if [[ ! -z "$MCWRAPPER_CONFIG_PATH" ]]; then
165
+ echo $MCWRAPPER_CONFIG_PATH
166
+ return
167
+ fi
168
+
169
+ # check ./mcwrapper.conf
170
+ local CURRENT_PATH="./${MCWRAPPER_CONFIG_NAME}"
171
+ if [[ -e "$CURRENT_PATH" ]]; then
172
+ echo $CURRENT_PATH
173
+ return
174
+ fi
175
+
176
+ # check ~/.mcwrapper.conf
177
+ CURRENT_PATH=~/".${MCWRAPPER_CONFIG_NAME}"
178
+ if [[ -e "$CURRENT_PATH" ]]; then
179
+ echo $CURRENT_PATH
180
+ return
181
+ fi
182
+
183
+ # check /etc/mcwrapper.conf
184
+ CURRENT_PATH="/etc/${MCWRAPPER_CONFIG_NAME}"
185
+ if [[ -e "$CURRENT_PATH" ]]; then
186
+ echo $CURRENT_PATH
187
+ return
188
+ fi
189
+
190
+ # if we can't find the config, it's no big deal. we'll just use defaults and not read it.
191
+ }
192
+
193
+ # configure self from config file
194
+ function read_config {
195
+ # set the global config path:
196
+ CONFIG_PATH=`get_config_path`
197
+
198
+ # if it's not found, don't do shit. stick with default values.
199
+ if [[ -z "$CONFIG_PATH" || ! -e "$CONFIG_PATH" ]]; then
200
+ return
201
+ fi
202
+
203
+ # it was found, so we read it by sourcing it.
204
+ . "$CONFIG_PATH"
205
+ }
206
+
207
+ function default_config {
208
+ # path to the minecraft_server.jar
209
+ # if this is not defined in the existing environment, try to guess where it is
210
+ if [[ -z "$MINECRAFT_SERVER_PATH" ]]; then
211
+
212
+ # check in the current directory first, then check one level up for minecraft.
213
+ # if it's not actually where it thinks it is, it'll break when it tries to do something.
214
+ # the resulting value of MINECRAFT_SERVER_PATH will be the last place that it looked.
215
+
216
+ MINECRAFT_SERVER_PATH="./${MINECRAFT_SERVER_NAME}"
217
+
218
+ if [[ ! -e "$MINECRAFT_SERVER_PATH" ]]; then
219
+ unset MINECRAFT_SERVER_PATH
220
+ fi
221
+
222
+ fi
223
+
224
+ # Java binary (uses one in PATH by default)
225
+ JAVA_BIN="java"
226
+
227
+ # Java VM settings (increasing these never hurts)
228
+ MX_SIZE="1024M"
229
+ MS_SIZE="1024M"
230
+
231
+ # these can be relative or absolute paths
232
+ # if relative, they're relative to the mcwrapper executable
233
+ PID_FILE="mcwrapper.pid"
234
+ COMMAND_PIPE="command_input"
235
+
236
+ BACKUP_DIRECTORY_PATH="backups"
237
+
238
+ # what the name of the symlink is.
239
+ LATEST_BACKUP_NAME="latest"
240
+
241
+ # how many backups to keep in the backups directory
242
+ # (we automatically delete old backups)
243
+ # set to -1 to retain ALL backups (never delete)
244
+ # set to 0 to completely disable backups.
245
+ BACKUPS_TO_KEEP=5
246
+
247
+ # set backup name to
248
+ # +%Y%m%d -- just the datestamp; no time.
249
+ # +%Y%m%d%H%M%S -- full timestamp including hour, minute, second
250
+ CURRENT_BACKUP_NAME=`date +%Y%m%d%H%M%S`
251
+ }
252
+
253
+ # run this to process a loaded config
254
+ # some variables require some modification before they can be used
255
+ # for example $PID_FILE which can be relative or absolute.
256
+ # if relative, we want to prepend the MINECRAFT_SERVER_DIR_PATH to it.
257
+ function process_config {
258
+ if [[ -z "$MINECRAFT_SERVER_PATH" ]]; then
259
+ return 1
260
+ fi
261
+
262
+ # the directory of the minecraft_server.jar based off $MINECRAFT_SERVER_PATH
263
+ MINECRAFT_SERVER_DIR_PATH=`dirname $MINECRAFT_SERVER_PATH`
264
+
265
+ pushd "$MINECRAFT_SERVER_DIR_PATH" &> /dev/null
266
+ MINECRAFT_SERVER_DIR=$(pwd)
267
+ popd &> /dev/null
268
+
269
+ # PID_FILE can be relative or absolute
270
+ if [[ ! "$PID_FILE" =~ ^/ ]]; then
271
+ PID_FILE="${MINECRAFT_SERVER_DIR_PATH}/$PID_FILE"
272
+ fi
273
+
274
+ # COMMAND_PIPE can be relative or absolute
275
+ if [[ ! "$COMMAND_PIPE" =~ ^/ ]]; then
276
+ COMMAND_PIPE="${MINECRAFT_SERVER_DIR_PATH}/$COMMAND_PIPE"
277
+ fi
278
+
279
+ # set MINECRAFT_SERVER_CMD
280
+ # this may be overridden in the config, so if it's set already, don't set it.
281
+ if [[ -z "$MINECRAFT_SERVER_CMD" ]]; then
282
+ # command for starting minecraft_server.jar
283
+ MINECRAFT_SERVER_CMD="$JAVA_BIN -Xmx${MX_SIZE} -Xms${MS_SIZE} -jar "$MINECRAFT_SERVER_PATH" nogui"
284
+ fi
285
+
286
+ # the path to the server.properties file
287
+ if [[ -z "$SERVER_PROPERTIES_PATH" ]]; then
288
+ SERVER_PROPERTIES_PATH=`dirname "$MINECRAFT_SERVER_PATH"`"/${MINECRAFT_SERVER_PROPERTIES_NAME}"
289
+ fi
290
+
291
+ # BACKUP_DIRECTORY_PATH can be relative or absolute
292
+ if [[ ! "$BACKUP_DIRECTORY_PATH" =~ ^/ ]]; then
293
+ BACKUP_DIRECTORY_PATH="${MINECRAFT_SERVER_DIR_PATH}/${BACKUP_DIRECTORY_PATH}"
294
+ fi
295
+ }
296
+
297
+ # copy the mcwrapper.conf-example file to the current directory
298
+ function copy_example_configuration {
299
+ local GENCONFIG_PATH="./${MCWRAPPER_CONFIG_NAME}"
300
+
301
+ if [[ -e "$GENCONFIG_PATH" ]]; then
302
+ errcho "$GENCONFIG_PATH already exists. Doing nothing."
303
+ exit $EXIT_GENCONFIG_EXISTS
304
+ fi
305
+
306
+ cp "${MCWRAPPER_DIR}/../mcwrapper.conf-example" "$GENCONFIG_PATH" \
307
+ || { errcho "Error copying $GENCONFIG_PATH"; exit $EXIT_GENCONFIG_ERROR; }
308
+
309
+ echo "Copied example configuration to $GENCONFIG_PATH"
310
+ }
311
+
312
+ function read_server_property {
313
+ # takes 1 arg... the property name
314
+ local PROP_NAME=$1;shift
315
+
316
+ if [[ ! -e "$SERVER_PROPERTIES_PATH" ]]; then
317
+ echo "Cannot locate server.properties path. ($SERVER_PROPERTIES_PATH)" >&2
318
+ exit $EXIT_NO_SERVER_PROPERTIES
319
+ fi
320
+
321
+ # if no property is supplied, just dump the entire properties file's keys
322
+ if [[ -z "$PROP_NAME" ]]; then
323
+ cat "$SERVER_PROPERTIES_PATH" | grep -v '^#' | awk -F '=' '{ print $1 }'
324
+ return
325
+ fi
326
+
327
+ cat "$SERVER_PROPERTIES_PATH" | grep "$PROP_NAME\=" | awk -F '=' '{ print $2 }'
328
+ }
329
+
330
+ function read_command {
331
+ sleep 1
332
+
333
+ # read from the command pipe via FD7 (needed for read timeout)
334
+ # no special reason to use 7, it's just sufficiently high that it probably won't collide with anything.
335
+ exec 7<> "$COMMAND_PIPE"
336
+
337
+ # initialize INPUT to be empty string
338
+ local INPUT=""
339
+
340
+ # number of seconds between reads
341
+ # this is needed to make sure the server is still running
342
+ local READ_TIMEOUT=2
343
+
344
+ while [[ "$INPUT" != 'stop' ]]; do
345
+ read -t "$READ_TIMEOUT" -u 7 INPUT
346
+
347
+ # if it timed out or got no input, then exit if server isnt' running.
348
+ if [[ "$?" != 0 || -z "$INPUT" ]]; then
349
+ check_is_running || exit $EXIT_SERVER_DISAPPEARED
350
+
351
+ continue
352
+ fi
353
+
354
+ echo $INPUT
355
+
356
+ # if the user said "stop" then exit after the command completes.
357
+ if [[ "$INPUT" = "stop" ]]; then
358
+ clean_up
359
+ exit $EXIT_SUCCESS
360
+ fi
361
+ done
362
+ }
363
+
364
+ function send_command {
365
+ check_is_running \
366
+ || { echo "Server is NOT running. Not sending command" >&2 ; exit $EXIT_SERVER_NOT_RUNNING; }
367
+
368
+ # echo the command into the command pipe to be picked up by the reader process:
369
+ local COMMAND=$1
370
+ (echo "$COMMAND" > "$COMMAND_PIPE") &> /dev/null \
371
+ || { echo "Error sending command: '${COMMAND}' (${?})" >&2 ; exit $EXIT_SEND_COMMAND_FAILED; }
372
+ }
373
+
374
+ function create_pid {
375
+ local PID_VALUE=$1
376
+ echo $PID_VALUE > $PID_FILE
377
+ }
378
+
379
+ function remove_pid {
380
+ # clean up PID file when done.
381
+ rm $PID_FILE
382
+ }
383
+
384
+ # reads the pidfile and echos it
385
+ # returns 1 if the pidfile does not exist or if there was an error reading it.
386
+ function read_pid {
387
+ if [[ ! -e "$PID_FILE" ]]; then
388
+ #echo "Server not running!" >&2
389
+ return $EXIT_SERVER_NOT_RUNNING
390
+ fi
391
+
392
+ local PID=`cat "$PID_FILE" 2>&1`
393
+
394
+ if [[ $? != $EXIT_SUCCESS ]]; then
395
+ return $EXIT_SERVER_NOT_RUNNING
396
+ fi
397
+
398
+ echo $PID
399
+ }
400
+
401
+ function check_is_running {
402
+ local PID=`read_pid`
403
+
404
+ # if read_pid returned a non-zero status, then we're not running
405
+ if [[ $? != $EXIT_SUCCESS ]]; then
406
+ return $EXIT_SERVER_NOT_RUNNING
407
+ fi
408
+
409
+ # check to see if we have a wrapper currently running
410
+ # send a 0 signal to process to see if it's running.
411
+ if ! kill -0 "$PID" &> /dev/null; then
412
+ return $EXIT_SERVER_NOT_RUNNING
413
+ fi
414
+
415
+ return $EXIT_SUCCESS
416
+ }
417
+
418
+ # ensure that the FIFO exists
419
+ function set_up_pipe {
420
+ if [[ ! -p "$COMMAND_PIPE" ]]; then
421
+ # if the file exists, but it's not a pipe, then we can't start.
422
+ if [[ -e "$COMMAND_PIPE" ]]; then
423
+ echo "Cannot create the pipe ($COMMAND_PIPE)" >&2
424
+ echo "A file or directory already exists." >&2
425
+ echo ""
426
+ exit "$EXIT_MAKE_FIFO_FAILED"
427
+ fi
428
+
429
+ mkfifo "$COMMAND_PIPE"
430
+
431
+ local PIPE_STATUS=$?
432
+
433
+ if [[ $PIPE_STATUS != 0 ]]; then
434
+ # if mkfifo failed, print error message, exit non-zero.
435
+ echo "Error creating the pipe: $COMMAND_PIPE ($PIPE_STATUS)." >&2
436
+ exit $EXIT_MAKE_FIFO_FAILED
437
+ fi
438
+ fi
439
+ }
440
+
441
+ # remove the FIFO
442
+ function remove_pipe {
443
+ if [[ -p "$COMMAND_PIPE" ]]; then
444
+ rm "$COMMAND_PIPE"
445
+ fi
446
+ }
447
+
448
+ # write the PID file and start'er up!
449
+ # don't start if we're already running.
450
+ function start_minecraft {
451
+ if check_is_running; then
452
+ echo "Server is already running. Exiting..." >&2
453
+ exit $EXIT_SERVER_ALREADY_RUNNING
454
+ fi
455
+
456
+ set_up_pipe
457
+
458
+ # now we go to the minecraft_server directory and start the server in a background process
459
+ # need to go to the directory to make sure that the Minecraft server puts the files in the right place (it puts them in the CWD)
460
+ pushd $MINECRAFT_SERVER_DIR_PATH &> /dev/null
461
+ read_command | $MINECRAFT_SERVER_CMD &> /dev/null &
462
+
463
+ create_pid $!
464
+
465
+ # sleep for one second to make sure that the process actually started properly.
466
+ sleep 1
467
+
468
+ # verify that minecraft server actually started.
469
+ if ! check_is_running; then
470
+ echo "Could not start Minecraft Server." >&2
471
+ exit $EXIT_SERVER_CANNOT_START
472
+ fi
473
+ }
474
+
475
+ # stops the minecraft server by sending it the 'stop' command via the FIFO
476
+ function stop_minecraft {
477
+ # if $BACKUP_ON_EXIT is non-zero length, then backup the world before exiting.
478
+ if [[ ! -z "$BACKUP_ON_EXIT" ]]; then
479
+ echo ""
480
+ echo -n "Backing up world data before exiting..." >&2
481
+ ( backup_world )
482
+ # TODO: check status of backup_world. Don't say "Done" if we didn't back anything up.
483
+ echo "Done." >&2
484
+ fi
485
+
486
+ send_command "stop"
487
+ }
488
+
489
+ function restart_minecraft {
490
+ stop_minecraft
491
+ wait_for_minecraft_to_stop
492
+ start_minecraft
493
+ }
494
+
495
+ # waits for minecraft to stop
496
+ # TODO: Make this timeout and make time configurable.
497
+ function wait_for_minecraft_to_stop {
498
+ if check_is_running; then
499
+ # if it's still running... sleep for 1 second and try again
500
+ echo -n "."
501
+ sleep 1
502
+ wait_for_minecraft_to_stop
503
+ fi
504
+ }
505
+
506
+ function server_log_path {
507
+ echo "${MINECRAFT_SERVER_DIR_PATH}/server.log"
508
+ }
509
+
510
+ function check_server_log_exists {
511
+ local SERVER_LOG_PATH=`server_log_path`
512
+
513
+ # make sure that the log file exists before trying to tail it.
514
+ if [[ ! -e "$SERVER_LOG_PATH" ]]; then
515
+ echo "Server log not found! ($SERVER_LOG_PATH)" >&2
516
+ echo ""
517
+ exit $EXIT_SERVER_LOG_NOT_FOUND
518
+ fi
519
+ }
520
+
521
+ # tail and follow the server.log
522
+ # ^C to stop
523
+ function tail_server_log {
524
+ local SERVER_LOG_PATH=`server_log_path`
525
+ check_server_log_exists
526
+
527
+ tail -F "$SERVER_LOG_PATH"
528
+ }
529
+
530
+ function sanity_check {
531
+ # TODO: add checks to make sure that PID_FILE and COMMAND_PIPE are writable
532
+
533
+ # make sure that there is a java binary installed in the PATH
534
+ which "$JAVA_BIN" &> /dev/null
535
+ if [[ $? != 0 ]]; then
536
+ echo "The java binary is not found." >&2
537
+ echo "Please install the necessary package(s) or specify the JAVA_BIN configuration option." >&2
538
+ echo "" >&2
539
+ exit $EXIT_NO_JAVA
540
+ fi
541
+
542
+ # check to make sure that things that need to exist exist.
543
+ if [[ ! -e "$MINECRAFT_SERVER_PATH" ]]; then
544
+ # the minecraft server path does not exist.
545
+ echo "Minecraft server not found!" >&2
546
+
547
+ if [[ -z "$MINECRAFT_SERVER_PATH" ]]; then
548
+ echo "Default location: ./${MINECRAFT_SERVER_NAME}" >&2
549
+ echo "Or set MINECRAFT_SERVER_NAME" >&2
550
+ else
551
+ echo "(MINECRAFT_SERVER_PATH=$MINECRAFT_SERVER_PATH)" >&2
552
+ fi
553
+ echo "" >&2
554
+ exit $EXIT_MINECRAFT_SERVER_NOT_FOUND
555
+ fi
556
+ }
557
+
558
+ # performs cleanup after stopping mcwrapper
559
+ # removes pid and pipe
560
+ function clean_up {
561
+ remove_pid
562
+ remove_pipe
563
+ }
564
+
565
+ ##########################################################################################
566
+ ## Installer portion: ============>>>>>>>>>>>>
567
+
568
+ # runs through interactive installer
569
+ # confirm configuration
570
+ # download minecraft_server.jar
571
+ # sanity check
572
+ function run_installer () {
573
+ echo "Welcome to the mcwrapper installer."
574
+ echo "Before the Minecraft Server is installed, we must first confirm a few settings..."
575
+ echo ""
576
+
577
+ # check for configuration
578
+ local CURRENT_CONFIG_PATH=`get_config_path`
579
+
580
+ if [[ -z "$CURRENT_CONFIG_PATH" ]]; then
581
+ echo "Using default configuration."
582
+ echo "An example configuration is included in the mcwrapper package."
583
+ echo "See mcwrapper.conf-example for details."
584
+ else
585
+ echo "mcwrapper config path: $CURRENT_CONFIG_PATH"
586
+ fi
587
+ echo ""
588
+
589
+ if [[ -z "$MINECRAFT_SERVER_PATH" ]]; then
590
+ MINECRAFT_SERVER_PATH="./${MINECRAFT_SERVER_NAME}"
591
+ MINECRAFT_SERVER_DIR_PATH="./"
592
+ fi
593
+
594
+ # show where minecraft_server.jar will be installed
595
+ echo "Minecraft Server Path: $MINECRAFT_SERVER_PATH"
596
+
597
+ if [[ -e "$MINECRAFT_SERVER_PATH" ]]; then
598
+ echo -n "Minecraft server already exists! Do you wish to overwrite? [y/N]: "
599
+ read OVERWRITE_SERVER
600
+ if [[ "$OVERWRITE_SERVER" != 'y' ]]; then
601
+ echo ""
602
+ echo "Not overwriting server. Thanks, bye!"
603
+ echo ""
604
+ exit $EXIT_SUCCESS
605
+ fi
606
+
607
+ backup_old_server
608
+ fi
609
+
610
+ echo -n "Is this where you wish to install the Minecraft Server? [Y/n]: "
611
+ read INSTALL_PATH_CORRECT
612
+ if [[ "$INSTALL_PATH_CORRECT" != 'y' && ! -z "$INSTALL_PATH_CORRECT" ]]; then
613
+ echo ""
614
+ echo "Please update your mcwrapper.conf and re-run this installer."
615
+ echo ""
616
+ exit $EXIT_SUCCESS
617
+ fi
618
+
619
+ echo "Downloading and installing Minecraft Server..."
620
+ download_minecraft_server
621
+
622
+ # ok, so now the server is downloaded and copied to the right location.
623
+
624
+ echo "Minecraft is downloaded and in place. You can now start it by running the following command:"
625
+ echo "$MCWRAPPER start"
626
+
627
+ exit 0
628
+ }
629
+
630
+ # download the minecraft_server.jar file
631
+ # parse the minecraft.net download page and look for the download link for the server
632
+ # then download that to the necessary place
633
+ # if anything hard-fails, it prints an error message and exits.
634
+ function download_minecraft_server () {
635
+
636
+ which curl >/dev/null \
637
+ || { echo "curl does not appear to be installed. This is required to download the Minecraft server" >&2; exit $EXIT_NO_CURL; }
638
+
639
+ # parse the download page and read the minecraft_server.jar download URI
640
+ local MINECRAFT_SERVER_DOWNLOAD_URI="https://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar"
641
+
642
+ # check if there was an error grabbing the download page (either curl returns a bad value or we didn't find the URI)
643
+ if [[ "$?" != "0" || -z "$MINECRAFT_SERVER_DOWNLOAD_URI" ]]; then
644
+ echo "There was an error locating the download link. www.minecraft.net down?"
645
+ echo ""
646
+ exit $EXIT_DOWNLOAD_MINECRAFT_SERVER_FAILED
647
+ fi
648
+
649
+ # build the minecraft_server.jar download URL
650
+ local MINECRAFT_SERVER_DOWNLOAD_URL="${MINECRAFT_SERVER_DOWNLOAD_URI}"
651
+
652
+ local MINECRAFT_SERVER_TEMP_FILE="/tmp/minecraft_server.jar"
653
+
654
+ # if the tempfile exists, delete it
655
+ if [[ -e "$MINECRAFT_SERVER_TEMP_FILE" ]]; then
656
+ rm "$MINECRAFT_SERVER_TEMP_FILE"
657
+ fi
658
+
659
+ echo "Downloading Minecraft server from: $MINECRAFT_SERVER_DOWNLOAD_URL"
660
+
661
+ # download the server to the temp directory
662
+ curl --progress-bar -L -o "$MINECRAFT_SERVER_TEMP_FILE" "$MINECRAFT_SERVER_DOWNLOAD_URL"
663
+
664
+ # assuming that was successful, make sure the directories exist and move the binary to the right location
665
+ local CURL_RETURN=$?
666
+ if [[ "$CURL_RETURN" != "0" ]]; then
667
+ echo "An error occurred ($CURL_RETURN) while downloading minecraft_server.jar from: $MINECRAFT_SERVER_DOWNLOAD_URL"
668
+ echo ""
669
+ exit $EXIT_DOWNLOAD_MINECRAFT_SERVER_FAILED
670
+ elif [[ ! -s "$MINECRAFT_SERVER_TEMP_FILE" ]]; then
671
+ echo "Failed downloading the minecraft server."
672
+ echo "This is usually caused by a server error on minecraft.net."
673
+ echo ""
674
+ exit $EXIT_DOWNLOAD_MINECRAFT_SERVER_FAILED
675
+ fi
676
+
677
+ # make sure directories exit
678
+ mkdir -p "$MINECRAFT_SERVER_DIR_PATH"
679
+ if [[ $? != 0 ]]; then
680
+ echo "Failed creating the minecraft server directory ($MINECRAFT_SERVER_DIR_PATH)"
681
+ echo ""
682
+ exit $EXIT_CREATE_MINECRAFT_SERVER_DIR_FAILED
683
+ fi
684
+
685
+ # move the minecraft server to the right place:
686
+ mv "$MINECRAFT_SERVER_TEMP_FILE" "$MINECRAFT_SERVER_PATH"
687
+
688
+ # check for errors when moving the minecraft_server.jar file
689
+ if [[ "$?" != 0 ]]; then
690
+ echo "An error occurred when moving minecraft_server.jar to the install directory."
691
+ echo ""
692
+ exit $EXIT_CANNOT_MOVE_MINECRAFT_SERVER
693
+ fi
694
+ }
695
+
696
+ # backs up an old minecraft_server.jar file before downloading a new one
697
+ # if something fails, it prints an error message and exits
698
+ function backup_old_server () {
699
+ # back up the old minecraft server (just in case)
700
+ mv "$MINECRAFT_SERVER_PATH" "${MINECRAFT_SERVER_PATH}.old"
701
+
702
+ if [[ "$?" != "0" ]]; then
703
+ echo "Failed backing up the old minecraft server!"
704
+ echo ""
705
+ exit $EXIT_CANNOT_BACKUP_OLD_MINECRAFT_SERVER
706
+ fi
707
+ }
708
+
709
+ # basically the same as install without all of the confirmation levels
710
+ # if an existing minecraft server is not found, then bail.
711
+ function update_minecraft_server () {
712
+ if [[ ! -e "$MINECRAFT_SERVER_PATH" ]]; then
713
+ echo "Existing Minecraft Server not found! ($MINECRAFT_SERVER_PATH)"
714
+ echo "Either run \`$MCWRAPPER install\` or make sure you install minecraft_server.jar in the above location."
715
+ echo ""
716
+ exit $EXIT_EXISTING_MINECRAFT_SERVER_NOT_FOUND
717
+ fi
718
+
719
+ echo "Updating server..."
720
+
721
+ backup_old_server
722
+ download_minecraft_server
723
+
724
+ if ! check_is_running; then
725
+ # server is not running, so just return
726
+ return
727
+ fi
728
+
729
+ read -p "Would you like to restart Minecraft Server? [Y/n]: " INPUT
730
+ if [[ -z "$INPUT" || "$INPUT" == 'y' ]]; then
731
+ echo -n "Restarting Minecraft Server..."
732
+ restart_minecraft
733
+ echo "Done."
734
+ fi
735
+
736
+ }
737
+
738
+ ## End Installer portion.
739
+ ##########################################################################################
740
+ ## MCBackup portion: ============>>>>>>>>>>>>
741
+
742
+
743
+ # create the backup directory
744
+ # if it exists, this effectively does nothing.
745
+ function create_backup_directory () {
746
+ mkdir -p "$CURRENT_BACKUP_PATH"
747
+
748
+ if [[ $? != 0 ]]; then
749
+ #an error occurred
750
+ echo "An error occurred when creating the backup directory." >&2
751
+ exit $EXIT_CANNOT_CREATE_BACKUP_DIR
752
+ fi
753
+ }
754
+
755
+ # stop writing to the world file(s) after flushing the buffer
756
+ function stop_writing_world () {
757
+ send_command "save-all"
758
+ send_command "save-off"
759
+ }
760
+
761
+ # begin writing the world data again
762
+ function start_writing_world () {
763
+ send_command "save-on"
764
+ }
765
+
766
+ # get the path to the current world directory
767
+ function world_dir_path () {
768
+ local LEVEL_NAME=`read_server_property level-name`
769
+ local WORLD_DATA_DIR="${MINECRAFT_SERVER_DIR_PATH}/${LEVEL_NAME}"
770
+
771
+ echo $WORLD_DATA_DIR
772
+ }
773
+
774
+ # copy the world data and configuration
775
+ function do_backup () {
776
+ local WORLD_DATA_DIR=$(world_dir_path)
777
+
778
+ cp -R "$WORLD_DATA_DIR" "$CURRENT_BACKUP_PATH/"
779
+
780
+ if [[ $? != 0 ]]; then
781
+ #an error occurred
782
+ echo "An error occurred when copying the world data." >&2
783
+ exit $EXIT_CANNOT_BACKUP_WORLD_DATA
784
+ fi
785
+
786
+ cp -R "${MINECRAFT_SERVER_DIR_PATH}/"*.{txt,properties} "$CURRENT_BACKUP_PATH/"
787
+
788
+ if [[ $? != 0 ]]; then
789
+ #an error occurred
790
+ echo "An error occurred when copying the configuration information" >&2
791
+ exit $EXIT_CANNOT_BACKUP_CONFIGS
792
+ fi
793
+
794
+ if [[ ! -z "$COMPRESS_BACKUP" ]]; then
795
+ # TODO: add support for bz2
796
+ # TODO: make this code a little more readable without the secret, back alley variable updating.
797
+ case "$COMPRESS_BACKUP" in
798
+ zip )
799
+ zip_backup
800
+ ;;
801
+ tgz )
802
+ tgz_backup
803
+ ;;
804
+ * )
805
+ echo "UKNOWN COMPRESSION TYPE: $COMPRESS_BACKUP"
806
+ exit $EXIT_BAD_COMPRESSION_TYPE
807
+ ;;
808
+ esac
809
+
810
+ # after the backup is compressed, remove the uncompressed version
811
+ rm -rf "$CURRENT_BACKUP_PATH"
812
+
813
+ # ARCHIVE_FILENAME gets set in the compressor ({tgz,zip}_backup) functions
814
+ # we set CURRENT_BACKUP_PATH so the symlink gets pointed to the archive rather than the directory we just deleted
815
+ CURRENT_BACKUP_PATH="${BACKUP_DIRECTORY_PATH}/${ARCHIVE_FILENAME}"
816
+ fi
817
+ }
818
+
819
+
820
+ #TODO: there's some duplicate code here... should probably fix it.
821
+ # concept:
822
+ # create a compress_backup( $type ) function
823
+ # check for `type ${type}_backup` function, if it exists
824
+ # call it; it should have a signature like: somekind_backup( $current_backup_path )
825
+ # and return the path to the compressed backup
826
+ function tgz_backup {
827
+ # cd to the backup directory
828
+ # create new tgz backup
829
+ pushd "$BACKUP_DIRECTORY_PATH"
830
+
831
+ local FILENAME=`basename "$CURRENT_BACKUP_PATH"`
832
+ ARCHIVE_FILENAME="${FILENAME}.tgz"
833
+
834
+ tar cfz "$ARCHIVE_FILENAME" "$FILENAME"
835
+
836
+ popd
837
+ }
838
+
839
+ function zip_backup {
840
+ pushd "$BACKUP_DIRECTORY_PATH"
841
+
842
+ local FILENAME=`basename "$CURRENT_BACKUP_PATH"`
843
+ ARCHIVE_FILENAME="${FILENAME}.zip"
844
+
845
+ zip -q -r "$ARCHIVE_FILENAME" "$FILENAME"
846
+
847
+ popd
848
+ }
849
+
850
+ function create_symlink () {
851
+ # then we symlink the current backup to "latest" in backups directory
852
+ if [[ -L "$LATEST_BACKUP_PATH" ]]; then
853
+ # if the symlink already exists, delete it before creating it.
854
+ rm "$LATEST_BACKUP_PATH"
855
+
856
+ if [[ $? != 0 ]]; then
857
+ #an error occurred
858
+ echo "An error occurred when deleting the old symlink." >&2
859
+ exit $EXIT_FAILED_TO_DELETE_SYMLINK
860
+ fi
861
+ fi
862
+
863
+ # just the directory/filename of the current backup
864
+ # this way, the symlink isn't an absolute path, so you can move the
865
+ # backup directory without issue.
866
+ local NEW_BACKUP=`basename "$CURRENT_BACKUP_PATH"`
867
+
868
+ ln -s "$NEW_BACKUP" "$LATEST_BACKUP_PATH"
869
+
870
+ if [[ $? != 0 ]]; then
871
+ #an error occurred
872
+ echo "An error occurred when creating the symlink." >&2
873
+ exit $EXIT_ERORR_CREATING_SYMLINK
874
+ fi
875
+ }
876
+
877
+ # delete old backups
878
+ function cleanup_old_backups () {
879
+ if [[ "$BACKUPS_TO_KEEP" = "-1" ]]; then
880
+ # if we want infinite retention, then set BACKUPS_TO_KEEP to -1
881
+ return
882
+ fi
883
+
884
+ echo "Cleaning up old backups..." >&2
885
+
886
+ OLD_BACKUPS=`ls -r "$BACKUP_DIRECTORY_PATH" | grep -v "$LATEST_BACKUP_NAME" | tail -n +"${BACKUPS_TO_KEEP}"`
887
+
888
+ for old_backup in $OLD_BACKUPS; do
889
+ echo "Removing $old_backup" >&2
890
+ rm -rf "${BACKUP_DIRECTORY_PATH}/$old_backup"
891
+ if [[ $? != 0 ]]; then
892
+ #an error occurred but don't exit.
893
+ echo "An error occurred when deleting a previous backup: ${old_backup}." >&2
894
+ fi
895
+ done
896
+ }
897
+
898
+ # call this to go through the whole backup procedure
899
+ # makes sure backup directory exists, makes sure we don't back up a worldfile that's actively being written to, backs it up, symlinks it. everything.
900
+ function backup_world {
901
+ if [[ "$BACKUPS_TO_KEEP" = "0" ]]; then
902
+ # set BACKUPS_TO_KEEP to "0" to disable backups entirely.
903
+ echo ""
904
+ echo "Backups are disabled. Not backing anything up."
905
+ exit $EXIT_BACKUPS_DISABLED
906
+ fi
907
+
908
+ # the path to the to-be-backed-up directory
909
+ CURRENT_BACKUP_PATH="${BACKUP_DIRECTORY_PATH}/$CURRENT_BACKUP_NAME"
910
+
911
+ # the path to the symlink to the above.
912
+ LATEST_BACKUP_PATH="${BACKUP_DIRECTORY_PATH}/${LATEST_BACKUP_NAME}"
913
+
914
+ create_backup_directory
915
+
916
+ # stop writing world if we're running
917
+ if [[ $(check_is_running) ]]; then
918
+ stop_writing_world
919
+ fi
920
+
921
+ do_backup
922
+
923
+ # start writing world only if we're running
924
+ if [[ $(check_is_running) ]]; then
925
+ start_writing_world
926
+ fi
927
+
928
+ create_symlink
929
+
930
+ cleanup_old_backups
931
+ }
932
+
933
+ function path_to_latest_backup {
934
+ local LATEST_BACKUP_PATH="${BACKUP_DIRECTORY_PATH}/${LATEST_BACKUP_NAME}"
935
+
936
+ # if the link doesn't exist, then warn the user and exit with proper exit code
937
+ if [[ ! -L "$LATEST_BACKUP_PATH" ]]; then
938
+ echo "Latest backup not found. Either never created or not a link or something. ($LATEST_BACKUP_PATH)" >&2
939
+ exit $EXIT_LATEST_BACKUP_NOT_FOUND
940
+ fi
941
+
942
+ # read the link to the latest backup
943
+ local LATEST_BACKUP_LINK=`readlink "$LATEST_BACKUP_PATH"`
944
+
945
+ # if the link to the latest backup is absolute, output that, otherwise, build the path and output that.
946
+ if [[ "$LATEST_BACKUP_LINK" =~ ^/ ]]; then
947
+ echo $LATEST_BACKUP_LINK
948
+ exit $EXIT_SUCCESS
949
+ fi
950
+
951
+ echo "${BACKUP_DIRECTORY_PATH}/${LATEST_BACKUP_LINK}"
952
+ }
953
+
954
+ # given a path to a world backup, restore the current world with the contents
955
+ # when doing this, back up the current world, if it exists
956
+ function restore_world {
957
+ local RESTORE_FROM=$1
958
+
959
+ # check to make sure a RESTORE_FROM parameter is supplied
960
+ [[ -z "$RESTORE_FROM" ]] \
961
+ && { echo "USAGE: $0 restore <backup_name>" >&2; exit $EXIT_CANNOT_RESTORE_WORLD; }
962
+
963
+ # check to make sure world dir exists and is a dir
964
+ [[ -e "$RESTORE_FROM" && -d "$RESTORE_FROM" ]] \
965
+ || { echo "Path does not appear to be a Minecraft world directory or does not exist." >&2; exit $EXIT_CANNOT_RESTORE_WORLD; }
966
+
967
+ # back-up current world data and temporarily enable infinite retention
968
+ # we don't want to inadvertently clobber any existing backups
969
+ BACKUPS_TO_KEEP=-1
970
+ backup_world
971
+
972
+ local SERVER_IS_RUNNING
973
+ local WORLD_DIR_PATH=$(world_dir_path)
974
+
975
+ if server_is_running; then
976
+ SERVER_IS_RUNNING="1"
977
+ stop_server
978
+ else
979
+ SERVER_IS_RUNNING="0"
980
+ fi
981
+
982
+ # delete old world
983
+ rm -rf "$WORLD_DIR_PATH"
984
+
985
+ # copy world
986
+ cp -R "$RESTORE_FROM" "$WORLD_DIR_PATH"
987
+ echo "$RESTORE_FROM" > "$WORLD_DIR_PATH/RESTORED_FROM"
988
+
989
+ # start server if it was running when we started
990
+ if [[ "$SERVER_IS_RUNNING" = '1' ]]; then
991
+ start_minecraft
992
+ fi
993
+ }
994
+
995
+ ## End MCBackup portion.
996
+ ##########################################################################################
997
+
998
+ ## begin meat of program:
999
+
1000
+ if [[ $# -eq 0 ]]; then
1001
+ print_usage
1002
+ exit $EXIT_SUCCESS
1003
+ fi
1004
+
1005
+ ACTION=$1;shift
1006
+
1007
+ # selfconfigure
1008
+ default_config
1009
+ read_config
1010
+ process_config
1011
+
1012
+ # before most actions are run, sanity_check is called
1013
+ # this ensures that things are configured properly before
1014
+ # performing any actions that require specific configuration
1015
+
1016
+ case $ACTION in
1017
+ help|--help|-?|-h )
1018
+ print_usage
1019
+ exit $EXIT_SUCCESS
1020
+ ;;
1021
+ version|--version )
1022
+ print_version
1023
+ exit $EXIT_SUCCESS
1024
+ ;;
1025
+ about )
1026
+ print_about
1027
+ exit $EXIT_SUCCESS
1028
+ ;;
1029
+ start )
1030
+ sanity_check
1031
+ echo -n "Starting minecraft... "
1032
+ start_minecraft
1033
+ echo "Done."
1034
+ exit $EXIT_SUCCESS
1035
+ ;;
1036
+ stop )
1037
+ sanity_check
1038
+ echo -n "Stopping minecraft... "
1039
+ stop_minecraft
1040
+ echo "Done."
1041
+ exit $EXIT_SUCCESS
1042
+ ;;
1043
+ restart )
1044
+ sanity_check
1045
+ echo -n "Restarting minecraft..."
1046
+ restart_minecraft
1047
+ echo " Done."
1048
+ exit $EXIT_SUCCESS
1049
+ ;;
1050
+ status )
1051
+ sanity_check
1052
+ if check_is_running; then
1053
+ echo "Server is running." >&2
1054
+ exit $EXIT_SUCCESS
1055
+ fi
1056
+
1057
+ echo "Server is NOT running." >&2
1058
+ exit $EXIT_SERVER_NOT_RUNNING
1059
+
1060
+ ;;
1061
+ check )
1062
+ sanity_check
1063
+
1064
+ # sanity_check will exit with an exit code if it fails
1065
+ # so, assuming it didn't exit, everything is ok.
1066
+
1067
+ echo "Everything looks OK!"
1068
+ exit $EXIT_SUCCESS
1069
+ ;;
1070
+
1071
+ install )
1072
+ run_installer
1073
+ exit $EXIT_SUCCESS
1074
+ ;;
1075
+ update )
1076
+ sanity_check
1077
+ update_minecraft_server
1078
+ exit $EXIT_SUCCESS
1079
+ ;;
1080
+ backup )
1081
+ sanity_check
1082
+ echo "Backing up minecraft world data..."
1083
+ backup_world
1084
+ echo "Done."
1085
+ exit $EXIT_SUCCESS
1086
+ ;;
1087
+ restore )
1088
+ sanity_check
1089
+ RESTORE_FROM=$1;shift
1090
+ restore_world $RESTORE_FROM
1091
+ echo "Done."
1092
+ exit $EXIT_SUCCESS
1093
+ ;;
1094
+ log )
1095
+ sanity_check
1096
+ check_server_log_exists
1097
+ echo "Tailing from: ${MINECRAFT_SERVER_DIR_PATH}/server.log" >&2
1098
+ echo "Press ^C to cancel." >&2
1099
+ echo "-------------------------------------------------------------------------------------------" >&2
1100
+
1101
+ tail_server_log
1102
+
1103
+ exit $EXIT_SUCCESS
1104
+ ;;
1105
+ genconfig )
1106
+ copy_example_configuration
1107
+
1108
+ exit $EXIT_SUCCESS
1109
+ ;;
1110
+ config )
1111
+ # dump info about the config
1112
+ CONFIG_SETTING=$1
1113
+ case $CONFIG_SETTING in
1114
+ serverpath )
1115
+ echo $MINECRAFT_SERVER_PATH
1116
+ exit $EXIT_SUCCESS
1117
+ ;;
1118
+ serverdir )
1119
+ echo $MINECRAFT_SERVER_DIR_PATH
1120
+ exit $EXIT_SUCCESS
1121
+ ;;
1122
+ pidfile )
1123
+ echo $PID_FILE
1124
+ exit $EXIT_SUCCESS
1125
+ ;;
1126
+ pid )
1127
+ check_is_running
1128
+ if [[ $? != 0 ]]; then
1129
+ echo "Server is NOT running." >&2
1130
+ exit $EXIT_SERVER_NOT_RUNNING
1131
+ fi
1132
+
1133
+ echo `read_pid`
1134
+ exit $EXIT_SUCCESS
1135
+ ;;
1136
+ pipe )
1137
+ echo $COMMAND_PIPE
1138
+ exit $EXIT_SUCCESS
1139
+ ;;
1140
+ configfile )
1141
+ echo $CONFIG_PATH
1142
+ exit $EXIT_SUCCESS
1143
+ ;;
1144
+ command )
1145
+ echo $MINECRAFT_SERVER_CMD
1146
+ exit $EXIT_SUCCESS
1147
+ ;;
1148
+ backupdir )
1149
+ echo $BACKUP_DIRECTORY_PATH
1150
+ exit $EXIT_SUCCESS
1151
+ ;;
1152
+ latestbackup )
1153
+ echo $(path_to_latest_backup)
1154
+ exit $EXIT_SUCCESS
1155
+ ;;
1156
+ backup-retention )
1157
+ echo $BACKUPS_TO_KEEP
1158
+ exit $EXIT_STATUS
1159
+ ;;
1160
+ *)
1161
+ echo "Unknown config setting: $CONFIG_SETTING"
1162
+ exit $EXIT_UNKNOWN_CONFIG_SETTING
1163
+ ;;
1164
+ esac
1165
+ ;;
1166
+ prop )
1167
+ sanity_check
1168
+ PROP=$1
1169
+ read_server_property $PROP
1170
+ exit $EXIT_SUCCESS
1171
+ ;;
1172
+ command|cmd )
1173
+ sanity_check
1174
+ COMMAND="$@"
1175
+ echo -n "sending: $COMMAND ... "
1176
+ send_command "$COMMAND"
1177
+ echo "Done."
1178
+ exit $EXIT_SUCCESS
1179
+ ;;
1180
+ * )
1181
+ echo "Invalid action: $ACTION" >&2
1182
+ echo "" >&2
1183
+ print_usage
1184
+ exit $EXIT_INVALID_ACTION
1185
+ esac
1186
+
1187
+ exit $EXIT_SUCCESS
1188
+
1189
+