diff --git a/bash_completion/msm b/bash_completion/msm index 863f187..616def2 100644 --- a/bash_completion/msm +++ b/bash_completion/msm @@ -16,6 +16,7 @@ __init_server() { SERVER_USER="$DEFAULT_SERVER_USER" SCREEN_NAME="${DEFAULT_SCREEN_NAME//\{SERVER_NAME\}/${1}}" WORLD_STORAGE_PATH="$SERVER_PATH/$DEFAULT_WORLD_STORAGE_PATH" + WORLD_STORAGE_INACTIVE_PATH="$SERVER_PATH/$DEFAULT_WORLD_STORAGE_INACTIVE_PATH" WHITELIST="$SERVER_PATH/$DEFAULT_WHITELIST" BANNED_PLAYERS="$SERVER_PATH/$DEFAULT_BANNED_PLAYERS" @@ -42,7 +43,8 @@ __init_server() { case "$name" in SERVER_USER) SERVER_USER="$value";; SCREEN_NAME) SCREEN_NAME="$value";; - WORLD_STORAGE_PATH) WORLD_STORAGE_DIR="$SERVER_PATH/$value";; + WORLD_STORAGE_PATH) WORLD_STORAGE_PATH="$SERVER_PATH/$value";; + WORLD_STORAGE_INACTIVE_PATH) WORLD_STORAGE_INACTIVE_PATH="$SERVER_PATH/$value";; WHITELIST) WHITELIST="$SERVER_PATH/$value";; BANNED_PLAYERS) BANNED_PLAYERS="$SERVER_PATH/$value";; @@ -126,7 +128,7 @@ _msm() { ;; worlds) if [[ $COMP_CWORD == 3 ]]; then - options="list load ram todisk backup" + options="list load ram todisk backup on off" else case "${COMP_WORDS[3]}" in ram) @@ -136,6 +138,20 @@ _msm() { fi fi ;; + on) + if [[ $COMP_CWORD == 4 ]]; then + if [ -d "$WORLD_STORAGE_INACTIVE_PATH" ]; then + options="$(ls -1 "$WORLD_STORAGE_INACTIVE_PATH")" + fi + fi + ;; + off) + if [[ $COMP_CWORD == 4 ]]; then + if [ -d "$WORLD_STORAGE_PATH" ]; then + options="$(ls -1 "$WORLD_STORAGE_PATH")" + fi + fi + ;; esac fi ;; diff --git a/init/msm b/init/msm index 14f5b17..8478308 100755 --- a/init/msm +++ b/init/msm @@ -76,6 +76,16 @@ echoerr() { echo "$@" 1>&2 } +# A function used to print debug messages to stdout. Prevents messages from +# appearing unless in debug mode, and allows debug statements to be easily +# distinguished from necessary echo statements. +# $1: The message to output +debug() { + if [[ $DEBUG == "true" ]]; then + echoerr "$1" + fi +} + # Determines whether "$1" is a valid name for a server or jar group directory # It must only contain upper or lower case letters, digits, dashes or # underscores. @@ -184,11 +194,53 @@ world_backup() { file_name="$(date "+%F-%H-%M-%S").zip" local server_id=${world_server_id[$1]} - as_user ${server_user_name[$server_id]} "mkdir -p \"${world_backup_path[$1]}\" && cd \"${server_world_storage[$server_id]}\" && zip -rq \"${world_backup_path[$1]}/${file_name}\" \"${world_name[$1]}\"" + local containing_dir="$(dirname "${world_path[$1]}")" + local dir_name="$(basename "${world_path[$1]}")" + as_user ${server_user_name[$server_id]} "mkdir -p \"${world_backup_path[$1]}\" && cd \"$containing_dir\" && zip -rq \"${world_backup_path[$1]}/${file_name}\" \"${dir_name}\"" echo "Done." } +# Activates a world +# $1: The ID of the world +world_activate() { + if [ -d "${world_inactive_path[$1]}" ]; then + echo -n "Moving world \"${world_name[$1]}\" to the active worldstorage directory... " + local new_path="${world_active_path[$1]}" + as_user "${server_user_name[${world_server_id[$1]}]}" "mkdir -p \"$new_path\" && mv \"${world_inactive_path[$1]}\" \"$new_path\"" + echo "Done." + else + if [ -d "${world_active_path[$1]}" ]; then + echo "World \"${world_name[$1]}\" is already activate." + else + echoerr "Error: Directory \"${world_inactive_path[$1]}\" could not be found." + return 1 + fi + fi +} + +# Deactivates a world +# $1: The ID of the world +world_deactivate() { + if server_is_running "${world_server_id[$1]}"; then + echoerr "Error: Worlds cannot be deactivated whilst the server is running." + return 1 + else + if [ -d "${world_active_path[$1]}" ]; then + echo -n "Moving world \"${world_name[$1]}\" to the inactive worldstorage directory... " + local new_path="${world_inactive_path[$1]}" + as_user "${server_user_name[${world_server_id[$1]}]}" "mkdir -p \"$new_path\" && mv \"${world_path[$1]}\" \"$new_path\"" + echo "Done." + else + if [ -d "${world_inactive_path[$1]}" ]; then + echo "World \"${world_name[$1]}\" is already deactivate." + else + echoerr "Error: Directory \"${world_active_path[$1]}\" could not be found." + return 1 + fi + fi + fi +} ### Server Utility Functions @@ -214,18 +266,20 @@ server_get_id() { # $1: The ID of the server # $2: The name of the world server_world_get_id() { - local i=${server_world_offset[$1]} - local max=$(( $i + ${server_num_worlds[$1]} )) - - # For each of the servers worlds: - while [[ $i -lt $max ]]; do - if [[ "${world_name[$i]}" == "$2" ]]; then - echo $i - return 0 - fi + if [ -d "${server_world_storage[$1]}/$2" ] || [ -d "${server_world_storage_inactive[$1]}/$2" ]; then + # If the directory exists - i=$(( $i + 1 )) - done + local start=${server_world_offset[$1]} + local max=$(( $i + ${server_num_worlds[$1]} )) + + # For each of the servers worlds: + for ((i=$start; i<$max; i++)); do + if [[ "${world_name[$i]}" == "$2" ]]; then + echo $i + return 0 + fi + done + fi return 1 } @@ -246,11 +300,17 @@ server_is_running() { # $1: The id of the server for which links should be ensured server_ensure_links() { echo -n "Maintaining world symbolic links... " - local i=${server_world_offset[$1]} - local max=$(( $i + ${server_num_worlds[$1]} )) + local start=${server_world_offset[$1]} + local max=$(( $start + ${server_num_worlds[$1]} )) local output="false" - while [[ $i -lt $max ]]; do + for ((i=$start; i<$max; i++)); do + if [[ ${world_status[$i]} != "active" ]]; then + # Remove the symbolic link if it exists + as_user "${server_user_name[$1]}" "rm -f \"${world_link[$i]}\"" + continue + fi + # -L checks for the path being a link rather than a file # ! -a, since it is within double square brackets means: the negation of # the existence of the file. In other words: true if does not exist @@ -291,8 +351,6 @@ server_ensure_links() { echoerr -en "\n Error: Could not create link for world \"${world_name[$i]}\". The file \"${world_link[$i]}\" already exists, and should not be overwritten automatically. Either remove this file, or rename \"${world_name[$i]}\"." output="true" fi - - i=$(( $i + 1 )) done if [[ $output == "true" ]]; then @@ -1127,185 +1185,323 @@ manager_stop_all_servers_now() { ### Main Functions +# Initialises a server's world +# $1: The server id +# $2: The world id to use +# $3: The name of the world +server_world_init() { + world_server_id[$2]="$1" + world_name[$2]="$3" + world_active_path[$2]="${server_world_storage[$1]}/${world_name[$2]}" + world_inactive_path[$2]="${server_world_storage_inactive[$1]}/${world_name[$2]}" + + # Set the status of this world (active/inactive) + if [ -d "${world_active_path[$2]}" ]; then + world_status[$2]="active" + world_path[$2]="${world_active_path[$2]}" + else + if [ -d "${world_inactive_path[$2]}" ]; then + world_status[$2]="inactive" + world_path[$2]="${world_inactive_path[$2]}" + else + world_status[$2]="unknown" + + echoerr "Error: World cannot be found in either \"${world_active_path[$2]}\" or \"${world_inactive_path[$2]}\"." + return 1 + fi + fi + + world_link[$2]="${server_path[$1]}/${world_name[$2]}" + world_flag_inram[$2]="${world_path[$2]}/$WORLD_FLAG_INRAM" + world_backup_path[$2]="$WORLD_ARCHIVE_PATH/${server_name[$1]}/${world_name[$2]}" + + # If the ramdisk path is set, get the path for this world + if [ ! -z "$RAMDISK_STORAGE_PATH" ]; then + world_ramdisk_path[$2]="${RAMDISK_STORAGE_PATH}/${server_name[$1]}/${world_name[$2]}" + fi + + # Detect whether this world should be in ram + if [[ -e "${world_path[$2]}/$WORLD_FLAG_INRAM" ]]; then + world_inram[$2]="true" + else + world_inram[$2]="false" + fi +} + +# Load a config file for a server +# $1: The id of the server to laod +server_load_config() { + local name value + + if [[ -f "${server_conf[$1]}" ]]; then + while read line; do + # ignore comment lines + echo "$line" | grep "^#" >/dev/null 2>&1 && continue + + # if not empty, set the property using declare + if [ ! -z "$line" ]; then + name="$(echo $line | awk -F '=' '{print $1}')" + value="$(echo $line | awk -F '\"' '{print $2}')" + fi + + case "$name" in + SERVER_USER) server_user_name[$1]="$value";; + SCREEN_NAME) server_screen_name[$1]="$value";; + WORLD_STORAGE_PATH) server_world_storage[$1]="${server_path[$1]}/$value";; + WORLD_STORAGE_INACTIVE_PATH) server_world_storage_inactive[$1]="${server_path[$1]}/$value";; + + LOG) server_log[$1]="${server_path[$1]}/$value";; + PROPERTIES) server_properties[$1]="$value";; + WHITELIST) server_whitelist[$1]="$value";; + BANNED_PLAYERS) server_banned_players[$1]="$value";; + BANNED_IPS) server_banned_ips[$1]="$value";; + + OPS) server_ops[$1]="$value";; + JAR) server_jar[$1]="${server_path[$1]}/$value";; + RAM) server_ram[$1]="$value";; + INVOCATION) server_invocation[$1]="$value";; + + STOP_DELAY) server_stop_delay[$1]="$value";; + RESTART_DELAY) server_restart_delay[$1]="$value";; + STOP_MESSAGE) server_stop_message[$1]="$value";; + STOP_ABORT) server_stop_abort[$1]="$value";; + RESTART_MESSAGE) server_restart_message[$1]="$value";; + RESTART_ABORT) server_restart_abort[$1]="$value";; + WORLD_BACKUP_STARTED) server_world_backup_started[$1]="$value";; + WORLD_BACKUP_FINISHED) server_world_backup_finished[$1]="$value";; + + COMPLETE_BACKUP_STARTED) server_complete_backup_started[$1]="$value";; + COMPLETE_BACKUP_FINISHED) server_complete_backup_finished[$1]="$value";; + CONFIRM_SAVE_ON) server_confirm_save_on[$1]="$value";; + CONFIRM_SAVE_OFF) server_confirm_save_off[$1]="$value";; + CONFIRM_SAVE_ALL) server_confrim_save_all[$1]="$value";; + CONFIRM_START) server_confrim_start[$1]="$value";; + CONFIRM_WHITELIST_LIST) server_confirm_whitelist_list[$1]="$value";; + CONFIRM_KICK) server_confirm_kick[$1]="$value";; + CONFIRM_KICK_FAIL) server_confirm_kick_fail[$1]="$value";; + CONFIRM_TIME_SET) server_confirm_time_set[$1]="$value";; + CONFIRM_TIME_SET_FAIL) server_confirm_time_set_fail[$1]="$value";; + CONFIRM_TIME_ADD) server_confirm_time_add[$1]="$value";; + CONFIRM_TIME_ADD_FAIL) server_confirm_time_add_fail[$1]="$value";; + CONFIRM_TOGGLEDOWNFALL) server_confirm_toggledownfall[$1]="$value";; + CONFIRM_TOGGLEDOWNFALL_FAIL) server_confirm_toggledownfall_fail[$1]="$value";; + CONFIRM_GAMEMODE) server_confirm_gamemode[$1]="$value";; + CONFIRM_GAMEMODE_FAIL_NO_USER) server_confirm_gamemode_fail_no_user[$1]="$value";; + CONFIRM_GAMEMODE_FAIL_NO_CHANGE) server_confirm_gamemode_fail_no_change[$1]="$value";; + COMPLETE_BACKUP_FOLLOW_SYMLINKS) server_complete_backup_follow_symlinks[$1]="$value";; + esac + done < "${server_conf[$1]}" + fi +} + +# Initialise a server's variables +# $1: The id to use for this server +# $2: The name of the server +server_init() { + server_name[$1]="$2" + server_path[$1]="$SERVER_STORAGE_PATH/$2" + server_conf[$1]="${server_path[$1]}/$DEFAULT_SERVER_CONF" + server_flag_active[$1]="${server_path[$1]}/$SERVER_FLAG_ACTIVE" + server_backup_path[$1]="$BACKUP_ARCHIVE_PATH/${server_name[$1]}" + server_log_archive_path[$1]="$LOG_ARCHIVE_PATH/${server_name[$1]}" + + if [[ -e "${server_flag_active[$1]}" ]]; then + server_active[$1]="true" + else + server_active[$1]="false" + fi + + # Setup defaults + # Note: screen_name will at this stage have the {SERVER_NAME} tag in it + # which needs to be replaced. + # Invocation may also the {RAM} and {JAR} tags. + + server_user_name[$1]="$DEFAULT_SERVER_USER" + server_screen_name[$1]="${DEFAULT_SCREEN_NAME//\{SERVER_NAME\}/${server_name[$1]}}" # Replace tags now, they cannot change + server_world_storage[$1]="${server_path[$1]}/$DEFAULT_WORLD_STORAGE_PATH" + server_world_storage_inactive[$1]="${server_path[$1]}/$DEFAULT_WORLD_STORAGE_INACTIVE_PATH" + server_log[$1]="${server_path[$1]}/$DEFAULT_LOG" + server_properties[$1]="${server_path[$1]}/$DEFAULT_PROPERTIES" + server_whitelist[$1]="${server_path[$1]}/$DEFAULT_WHITELIST" + server_banned_players[$1]="${server_path[$1]}/$DEFAULT_BANNED_PLAYERS" + server_banned_ips[$1]="${server_path[$1]}/$DEFAULT_BANNED_IPS" + server_ops[$1]="${server_path[$1]}/$DEFAULT_OPS" + server_jar[$1]="${server_path[$1]}/$DEFAULT_JAR" + server_ram[$1]="$DEFAULT_RAM" + server_invocation[$1]="$DEFAULT_INVOCATION" # Don't replace tags yet, they may change + server_stop_delay[$1]="$DEFAULT_STOP_DELAY" + server_restart_delay[$1]="$DEFAULT_RESTART_DELAY" + server_stop_message[$1]="$DEFAULT_STOP_MESSAGE" + server_stop_abort[$1]="$DEFAULT_STOP_ABORT" + server_restart_message[$1]="$DEFAULT_RESTART_MESSAGE" + server_restart_abort[$1]="$DEFAULT_RESTART_ABORT" + server_world_backup_started[$1]="$DEFAULT_WORLD_BACKUP_STARTED" + server_world_backup_finished[$1]="$DEFAULT_WORLD_BACKUP_FINISHED" + server_complete_backup_started[$1]="$DEFAULT_COMPLETE_BACKUP_STARTED" + server_complete_backup_finished[$1]="$DEFAULT_COMPLETE_BACKUP_FINISHED" + server_confirm_save_on[$1]="$DEFAULT_CONFIRM_SAVE_ON" + server_confirm_save_off[$1]="$DEFAULT_CONFIRM_SAVE_OFF" + server_confirm_save_all[$1]="$DEFAULT_CONFIRM_SAVE_ALL" + server_confirm_start[$1]="$DEFAULT_CONFIRM_START" + server_confirm_kick[$1]="$DEFAULT_CONFIRM_KICK" + server_confirm_kick_fail[$1]="$DEFAULT_CONFIRM_KICK_FAIL" + server_confirm_time_set[$1]="$DEFAULT_CONFIRM_TIME_SET" + server_confirm_time_set_fail[$1]="$DEFAULT_CONFIRM_TIME_SET_FAIL" + server_confirm_time_add[$1]="$DEFAULT_CONFIRM_TIME_ADD" + server_confirm_time_add_fail[$1]="$DEFAULT_CONFIRM_TIME_ADD_FAIL" + server_confirm_toggledownfall[$1]="$DEFAULT_CONFIRM_TOGGLEDOWNFALL" + server_confirm_toggledownfall_fail[$1]="$DEFAULT_CONFIRM_TOGGLEDOWNFALL_FAIL" + server_confirm_gamemode[$1]="$DEFAULT_CONFIRM_GAMEMODE" + server_confirm_gamemode_fail_no_user[$1]="$DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_USER" + server_confirm_gamemode_fail_no_change[$1]="$DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_CHANGE" + server_complete_backup_follow_symlinks[$1]="$DEFAULT_COMPLETE_BACKUP_FOLLOW_SYMLINKS" + + + # Load config overrides from server config file if present + server_load_config $1 + + + # Replace tags in delay messages + server_stop_message[$1]="${server_stop_message[$1]//\{DELAY\}/${server_stop_delay[$1]}}" + server_restart_message[$1]="${server_restart_message[$1]//\{DELAY\}/${server_restart_delay[$1]}}" + + # Replace tags in server invocation + server_invocation[$1]="${server_invocation[$1]//\{RAM\}/${server_ram[$1]}}" + server_invocation[$1]="${server_invocation[$1]//\{JAR\}/${server_jar[$1]}}" + + + # Load worlds if there is a world storage directory present + server_world_offset[$1]=0 + server_num_worlds[$1]=0 + + # Start world id's for this server's worlds at the end of the array + local world_id=$num_worlds + + # Record the index at which worlds for this server start + server_world_offset[$1]=$world_id + + if [[ -d "${server_world_storage[$1]}" ]]; then + # Load active worlds + while IFS= read -r -d $'\0' world_path; do + local name=$(basename $world_path) + server_world_init $1 $world_id $name + + # Build the server_worlds comma separated list + if [[ $world_id == $server_world_offset[$1] ]]; then + server_worlds[$1]="$name" + else + server_worlds[$1]="${server_worlds[$1]}, $name" + fi + + world_id=$(($world_id+1)) + num_worlds=$world_id + done < <(find "${server_world_storage[$1]}" -mindepth 1 -maxdepth 1 -type d -print0) + fi + + if [[ -d "${server_world_storage_inactive[$1]}" ]]; then + # Load inactive worlds + while IFS= read -r -d $'\0' world_path; do + local name=$(basename $world_path) + server_world_init $1 $world_id $name + + # Build the server_worlds_inactive comma separated list + if [[ $world_id == $server_world_offset[$1] ]]; then + server_worlds[$1]="$name" + else + server_worlds[$1]="${server_worlds[$1]}, $name" + fi + + world_id=$(($world_id+1)) + num_worlds=$world_id + done < <(find "${server_world_storage_inactive[$1]}" -mindepth 1 -maxdepth 1 -type d -print0) + fi + + # Record the number of worlds this server has + server_num_worlds[$1]=$(( $world_id - ${server_world_offset[$1]} )) +} + +# Asserts that a variable has been set in the config file +# $1: The name of the variable to test +# $2: The message to print to stderr if the variable is unset +assert_is_set_in_config() { + [[ ! ${!1} && ${!1-_} ]] && { + echoerr "Error: $1 must be set in $CONFIG" + exit 1 + } +} + +# Ensures all non-optional settings have been set +init_ensure_settings() { + assert_is_set_in_config USERNAME + assert_is_set_in_config SERVER_STORAGE_PATH + assert_is_set_in_config JAR_STORAGE_PATH + assert_is_set_in_config RAMDISK_STORAGE_PATH + + assert_is_set_in_config WORLD_ARCHIVE_PATH + assert_is_set_in_config LOG_ARCHIVE_PATH + assert_is_set_in_config BACKUP_ARCHIVE_PATH + + assert_is_set_in_config DEFAULT_SERVER_CONF + assert_is_set_in_config DEFAULT_SERVER_USER + assert_is_set_in_config DEFAULT_SCREEN_NAME + assert_is_set_in_config DEFAULT_WORLD_STORAGE_PATH + assert_is_set_in_config DEFAULT_WORLD_STORAGE_INACTIVE_PATH + assert_is_set_in_config DEFAULT_COMPLETE_BACKUP_FOLLOW_SYMLINKS + + assert_is_set_in_config DEFAULT_LOG + assert_is_set_in_config DEFAULT_PROPERTIES + assert_is_set_in_config DEFAULT_WHITELIST + assert_is_set_in_config DEFAULT_BANNED_PLAYERS + assert_is_set_in_config DEFAULT_BANNED_IPS + assert_is_set_in_config DEFAULT_OPS + + assert_is_set_in_config DEFAULT_JAR + assert_is_set_in_config DEFAULT_RAM + assert_is_set_in_config DEFAULT_INVOCATION + + assert_is_set_in_config DEFAULT_STOP_DELAY + assert_is_set_in_config DEFAULT_RESTART_DELAY + assert_is_set_in_config DEFAULT_STOP_MESSAGE + assert_is_set_in_config DEFAULT_STOP_ABORT + assert_is_set_in_config DEFAULT_RESTART_MESSAGE + assert_is_set_in_config DEFAULT_RESTART_ABORT + assert_is_set_in_config DEFAULT_WORLD_BACKUP_STARTED + assert_is_set_in_config DEFAULT_WORLD_BACKUP_FINISHED + assert_is_set_in_config DEFAULT_COMPLETE_BACKUP_STARTED + assert_is_set_in_config DEFAULT_COMPLETE_BACKUP_FINISHED + assert_is_set_in_config DEFAULT_CONFIRM_SAVE_ON + assert_is_set_in_config DEFAULT_CONFIRM_SAVE_OFF + assert_is_set_in_config DEFAULT_CONFIRM_SAVE_ALL + assert_is_set_in_config DEFAULT_CONFIRM_START + assert_is_set_in_config DEFAULT_CONFIRM_KICK + assert_is_set_in_config DEFAULT_CONFIRM_KICK_FAIL + assert_is_set_in_config DEFAULT_CONFIRM_TIME_SET + assert_is_set_in_config DEFAULT_CONFIRM_TIME_SET_FAIL + assert_is_set_in_config DEFAULT_CONFIRM_TIME_ADD + assert_is_set_in_config DEFAULT_CONFIRM_TIME_ADD_FAIL + assert_is_set_in_config DEFAULT_CONFIRM_TOGGLEDOWNFALL + assert_is_set_in_config DEFAULT_CONFIRM_TOGGLEDOWNFALL_FAIL + assert_is_set_in_config DEFAULT_CONFIRM_GAMEMODE + assert_is_set_in_config DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_USER + assert_is_set_in_config DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_CHANGE +} + init() { # Sourcing $CONFIG will override the previous defaults, with new values source "$CONFIG" + + init_ensure_settings + + num_worlds=0 + num_servers=0 - local i=0 - local j=0 - - for server in $(ls -1 "$SERVER_STORAGE_PATH"); do - server_name[$i]="$server" - server_path[$i]="$SERVER_STORAGE_PATH/$server" - server_conf[$i]="${server_path[$i]}/$DEFAULT_SERVER_CONF" - server_flag_active[$i]="${server_path[$i]}/$SERVER_FLAG_ACTIVE" - server_backup_path[$i]="$BACKUP_ARCHIVE_PATH/${server_name[$i]}" - server_log_archive_path[$i]="$LOG_ARCHIVE_PATH/${server_name[$i]}" - - if [[ -e "${server_flag_active[$i]}" ]]; then - server_active[$i]="true" - else - server_active[$i]="false" - fi - - # Setup defaults - # Note: screen_name will at this stage have the {SERVER_NAME} tag in it - # which needs to be replaced. - # Invocation may also the {RAM} and {JAR} tags. - - server_user_name[$i]="$DEFAULT_SERVER_USER" - server_screen_name[$i]="${DEFAULT_SCREEN_NAME//\{SERVER_NAME\}/${server_name[$i]}}" # Replace tags now, they cannot change - server_world_storage[$i]="${server_path[$i]}/$DEFAULT_WORLD_STORAGE_PATH" - server_log[$i]="${server_path[$i]}/$DEFAULT_LOG" - server_properties[$i]="${server_path[$i]}/$DEFAULT_PROPERTIES" - server_whitelist[$i]="${server_path[$i]}/$DEFAULT_WHITELIST" - server_banned_players[$i]="${server_path[$i]}/$DEFAULT_BANNED_PLAYERS" - server_banned_ips[$i]="${server_path[$i]}/$DEFAULT_BANNED_IPS" - server_ops[$i]="${server_path[$i]}/$DEFAULT_OPS" - server_jar[$i]="${server_path[$i]}/$DEFAULT_JAR" - server_ram[$i]="$DEFAULT_RAM" - server_invocation[$i]="$DEFAULT_INVOCATION" # Don't replace tags yet, they may change - server_stop_delay[$i]="$DEFAULT_STOP_DELAY" - server_restart_delay[$i]="$DEFAULT_RESTART_DELAY" - server_stop_message[$i]="$DEFAULT_STOP_MESSAGE" - server_stop_abort[$i]="$DEFAULT_STOP_ABORT" - server_restart_message[$i]="$DEFAULT_RESTART_MESSAGE" - server_restart_abort[$i]="$DEFAULT_RESTART_ABORT" - server_world_backup_started[$i]="$DEFAULT_WORLD_BACKUP_STARTED" - server_world_backup_finished[$i]="$DEFAULT_WORLD_BACKUP_FINISHED" - server_complete_backup_started[$i]="$DEFAULT_COMPLETE_BACKUP_STARTED" - server_complete_backup_finished[$i]="$DEFAULT_COMPLETE_BACKUP_FINISHED" - server_confirm_save_on[$i]="$DEFAULT_CONFIRM_SAVE_ON" - server_confirm_save_off[$i]="$DEFAULT_CONFIRM_SAVE_OFF" - server_confirm_save_all[$i]="$DEFAULT_CONFIRM_SAVE_ALL" - server_confirm_start[$i]="$DEFAULT_CONFIRM_START" - server_confirm_kick[$i]="$DEFAULT_CONFIRM_KICK" - server_confirm_kick_fail[$i]="$DEFAULT_CONFIRM_KICK_FAIL" - server_confirm_time_set[$i]="$DEFAULT_CONFIRM_TIME_SET" - server_confirm_time_set_fail[$i]="$DEFAULT_CONFIRM_TIME_SET_FAIL" - server_confirm_time_add[$i]="$DEFAULT_CONFIRM_TIME_ADD" - server_confirm_time_add_fail[$i]="$DEFAULT_CONFIRM_TIME_ADD_FAIL" - server_confirm_toggledownfall[$i]="$DEFAULT_CONFIRM_TOGGLEDOWNFALL" - server_confirm_toggledownfall_fail[$i]="$DEFAULT_CONFIRM_TOGGLEDOWNFALL_FAIL" - server_confirm_gamemode[$i]="$DEFAULT_CONFIRM_GAMEMODE" - server_confirm_gamemode_fail_no_user[$i]="$DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_USER" - server_confirm_gamemode_fail_no_change[$i]="$DEFAULT_CONFIRM_GAMEMODE_FAIL_NO_CHANGE" - server_complete_backup_follow_symlinks[$i]="$DEFAULT_COMPLETE_BACKUP_FOLLOW_SYMLINKS" - - - # Load config overrides from server config file if present - - if [[ -e "${server_conf[$i]}" ]]; then - local name - local value - - while read line; do - # ignore comment lines - echo "$line" | grep "^#" >/dev/null 2>&1 && continue - - # if not empty, set the property using declare - if [ ! -z "$line" ]; then - name="$(echo $line | awk -F '=' '{print $1}')" - value="$(echo $line | awk -F '\"' '{print $2}')" - fi - - case "$name" in - SERVER_USER) server_user_name[$i]="$value";; - SCREEN_NAME) server_screen_name[$i]="$value";; - WORLD_STORAGE_PATH) server_world_storage[$i]="${server_path[$i]}/$value";; - - LOG) server_log[$i]="${server_path[$i]}/$value";; - PROPERTIES) server_properties[$i]="$value";; - WHITELIST) server_whitelist[$i]="$value";; - BANNED_PLAYERS) server_banned_players[$i]="$value";; - BANNED_IPS) server_banned_ips[$i]="$value";; - - OPS) server_ops[$i]="$value";; - JAR) server_jar[$i]="${server_path[$i]}/$value";; - RAM) server_ram[$i]="$value";; - INVOCATION) server_invocation[$i]="$value";; - - STOP_DELAY) server_stop_delay[$i]="$value";; - RESTART_DELAY) server_restart_delay[$i]="$value";; - STOP_MESSAGE) server_stop_message[$i]="$value";; - STOP_ABORT) server_stop_abort[$i]="$value";; - RESTART_MESSAGE) server_restart_message[$i]="$value";; - RESTART_ABORT) server_restart_abort[$i]="$value";; - WORLD_BACKUP_STARTED) server_world_backup_started[$i]="$value";; - WORLD_BACKUP_FINISHED) server_world_backup_finished[$i]="$value";; - - COMPLETE_BACKUP_STARTED) server_complete_backup_started[$i]="$value";; - COMPLETE_BACKUP_FINISHED) server_complete_backup_finished[$i]="$value";; - CONFIRM_SAVE_ON) server_confirm_save_on[$i]="$value";; - CONFIRM_SAVE_OFF) server_confirm_save_off[$i]="$value";; - CONFIRM_SAVE_ALL) server_confrim_save_all[$i]="$value";; - CONFIRM_START) server_confrim_start[$i]="$value";; - CONFIRM_WHITELIST_LIST) server_confirm_whitelist_list[$i]="$value";; - CONFIRM_KICK) server_confirm_kick[$i]="$value";; - CONFIRM_KICK_FAIL) server_confirm_kick_fail[$i]="$value";; - CONFIRM_TIME_SET) server_confirm_time_set[$i]="$value";; - CONFIRM_TIME_SET_FAIL) server_confirm_time_set_fail[$i]="$value";; - CONFIRM_TIME_ADD) server_confirm_time_add[$i]="$value";; - CONFIRM_TIME_ADD_FAIL) server_confirm_time_add_fail[$i]="$value";; - CONFIRM_TOGGLEDOWNFALL) server_confirm_toggledownfall[$i]="$value";; - CONFIRM_TOGGLEDOWNFALL_FAIL) server_confirm_toggledownfall_fail[$i]="$value";; - CONFIRM_GAMEMODE) server_confirm_gamemode[$i]="$value";; - CONFIRM_GAMEMODE_FAIL_NO_USER) server_confirm_gamemode_fail_no_user[$i]="$value";; - CONFIRM_GAMEMODE_FAIL_NO_CHANGE) server_confirm_gamemode_fail_no_change[$i]="$value";; - COMPLETE_BACKUP_FOLLOW_SYMLINKS) server_complete_backup_follow_symlinks[$i]="$value";; - esac - done < "${server_conf[$i]}" - fi - - # Replace tags in delay messages - server_stop_message[$i]="${server_stop_message[$i]//\{DELAY\}/${server_stop_delay[$i]}}" - server_restart_message[$i]="${server_restart_message[$i]//\{DELAY\}/${server_restart_delay[$i]}}" - - # Replace tags in server invocation - server_invocation[$i]="${server_invocation[$i]//\{RAM\}/${server_ram[$i]}}" - server_invocation[$i]="${server_invocation[$i]//\{JAR\}/${server_jar[$i]}}" - - - # Load worlds if there is a world storage directory present - server_world_offset[$i]=0 - server_num_worlds[$i]=0 - - if [[ -e "${server_world_storage[$i]}" ]]; then - server_worlds[$i]=$(ls -1 "${server_world_storage[$i]}") - - # Record the index at which worlds for this server start - server_world_offset[$i]=$j - - for world in ${server_worlds[$i]}; do - world_server_id[$j]="$i" - world_name[$j]="$world" - world_path[$j]="${server_world_storage[$i]}/${world_name[$j]}" - world_link[$j]="${server_path[$i]}/${world_name[$j]}" - world_flag_inram[$j]="${world_path[$j]}/$WORLD_FLAG_INRAM" - world_backup_path[$j]="$WORLD_ARCHIVE_PATH/${server_name[$i]}/${world_name[$j]}" - - if [ ! -z $RAMDISK_STORAGE_PATH ]; then - world_ramdisk_path[$j]="${RAMDISK_STORAGE_PATH}/${server_name[$i]}/${world_name[$j]}" - fi - - if [[ -e "${world_path[$j]}/$WORLD_FLAG_INRAM" ]]; then - world_inram[$j]="true" - else - world_inram[$j]="false" - fi - - j=$(($j+1)) - done - - # Record the number of worlds this server has - server_num_worlds[$i]=$(( $j - ${server_world_offset[$i]} )) - fi - - i=$(($i+1)) - done - - num_servers=$i - num_worlds=$j + local server_id=0 + while IFS= read -r -d $'\0' server_path; do + local name=$(basename $server_path) + server_init $server_id $name + server_id=$(($server_id+1)) + num_servers=$server_id + done < <(find "$SERVER_STORAGE_PATH" -mindepth 1 -maxdepth 1 -type d -print0) } # Called if the script is interrupted before exiting naturally @@ -1489,6 +1685,7 @@ main() { echo -e " worlds ram Toggles a world's \"in RAM\" status" echo -e " worlds todisk Synchronises any \"in RAM\" worlds to disk a server has" echo -e " worlds backup Makes a backup of all worlds a server has" + echo -e " worlds on|off Activate or deactivate a world, inactive worlds are not backed up" echo -e " logroll Move a server log to a gziped archive, to reduce lag" echo -e " backup Makes a backup of an entire server directory" echo -e " jar [] Sets a server's jar file" @@ -1608,6 +1805,20 @@ main() { echo "Backup took $SECONDS seconds". ;; + on) + if [ -z "$4" ]; then + echo "Invalid command." + else + world_activate "$(server_world_get_id "$id" "$4")" + fi + ;; + off) + if [ -z "$4" ]; then + echo "Invalid command." + else + world_deactivate "$(server_world_get_id "$id" "$4")" + fi + ;; *) echo "Invalid command." ;; diff --git a/msm.conf b/msm.conf index 6e7d10b..de727cf 100644 --- a/msm.conf +++ b/msm.conf @@ -78,6 +78,11 @@ DEFAULT_SCREEN_NAME="msm-{SERVER_NAME}" # A directory name relative to the server directory where worlds are stored DEFAULT_WORLD_STORAGE_PATH="worldstorage" +# A directory name relative to the server directory where old worlds are stored +# These worlds will cannot be used by the server and will not be saved when +# backing up all worlds. But will be inclued in a complete server backup. +DEFAULT_WORLD_STORAGE_INACTIVE_PATH="worldstorage_inactive" + # "true" and symlinks are followed when performing a complete backup, # "false" and symlinks are replaced in the zip with a file containing the # path to the original symlink larget, this saves space.