mcwrapper 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+