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.
- 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
|
+
|