mcwrapper 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +19 -0
- data/README.markdown +183 -0
- data/Rakefile +1 -0
- data/bin/mcwrapper +8 -0
- data/lib/mcwrapper.rb +6 -0
- data/lib/mcwrapper/version.rb +4 -0
- data/libexec/mcwrapper +1189 -0
- data/mcwrapper.conf-example +61 -0
- data/mcwrapper.gemspec +19 -0
- metadata +59 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
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.
|
data/README.markdown
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/mcwrapper
ADDED
data/lib/mcwrapper.rb
ADDED
data/libexec/mcwrapper
ADDED
@@ -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
|
+
|