summaryrefslogtreecommitdiffstats
path: root/scripts/wsrep_sst_common.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/wsrep_sst_common.sh')
-rw-r--r--scripts/wsrep_sst_common.sh1586
1 files changed, 1586 insertions, 0 deletions
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
new file mode 100644
index 00000000..bf96f79e
--- /dev/null
+++ b/scripts/wsrep_sst_common.sh
@@ -0,0 +1,1586 @@
+# Copyright (C) 2017-2022 MariaDB
+# Copyright (C) 2012-2015 Codership Oy
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
+# MA 02110-1335 USA.
+
+# This is a common command line parser to be sourced by other SST scripts
+
+trap 'exit 32' HUP PIPE
+trap 'exit 3' INT QUIT TERM
+
+# Setting the path for some utilities on CentOS
+export PATH="$PATH:/usr/sbin:/usr/bin:/sbin:/bin"
+
+trim_string()
+{
+ if [ -n "$BASH_VERSION" ]; then
+ local pattern="[![:space:]${2:-}]"
+ local x="${1#*$pattern}"
+ local z=${#1}
+ x=${#x}
+ if [ $x -ne $z ]; then
+ local y="${1%$pattern*}"
+ y=${#y}
+ x=$(( z-x-1 ))
+ y=$(( y-x+1 ))
+ printf '%s' "${1:$x:$y}"
+ else
+ printf ''
+ fi
+ else
+ local pattern="[[:space:]${2:-}]"
+ echo "$1" | sed -E "s/^$pattern+|$pattern+\$//g"
+ fi
+}
+
+trim_dir()
+{
+ if [ -n "$BASH_VERSION" ]; then
+ local pattern="![:space:]${2:-}"
+ local x="${1#*[$pattern]}"
+ local z=${#1}
+ x=${#x}
+ if [ $x -ne $z ]; then
+ local y="${1%[$pattern/]*}"
+ y=${#y}
+ x=$(( z-x-1 ))
+ y=$(( y-x+1 ))
+ x="${1:$x:$y}"
+ [ -z "$x" ] && x='.'
+ printf '%s' "$x"
+ else
+ printf ''
+ fi
+ else
+ local pattern="[:space:]${2:-}"
+ local x=$(echo "$1" | sed -E "s/^[$pattern]+|[$pattern/]+\$//g")
+ if [ -n "$x" ]; then
+ echo "$x"
+ elif "${1#*/}" != "$1"; then
+ echo '.'
+ else
+ echo ''
+ fi
+ fi
+}
+
+trim_right()
+{
+ if [ -n "$BASH_VERSION" ]; then
+ local pattern="[![:space:]${2:-}]"
+ local z=${#1}
+ local y="${1%$pattern*}"
+ y=${#y}
+ if [ $y -ne $z ]; then
+ y=$(( y+1 ))
+ printf '%s' "${1:0:$y}"
+ else
+ printf ''
+ fi
+ else
+ local pattern="[[:space:]${2:-}]"
+ echo "$1" | sed -E "s/$pattern+\$//g"
+ fi
+}
+
+to_minuses()
+{
+ local x="$1"
+ local t="${1#*_}"
+ local r=""
+ while [ "$t" != "$x" ]; do
+ r="$r${x%%_*}-"
+ x="$t"
+ t="${t#*_}"
+ done
+ if [ -n "$BASH_VERSION" ]; then
+ printf '%s' "$r$x"
+ else
+ echo "$r$x"
+ fi
+}
+
+WSREP_SST_OPT_BYPASS=0
+WSREP_SST_OPT_PROGRESS=0
+WSREP_SST_OPT_BINLOG=""
+WSREP_SST_OPT_BINLOG_INDEX=""
+WSREP_SST_OPT_LOG_BASENAME=""
+WSREP_SST_OPT_DATA=""
+WSREP_SST_OPT_AUTH="${WSREP_SST_OPT_AUTH:-}"
+WSREP_SST_OPT_USER="${WSREP_SST_OPT_USER:-}"
+WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_PSWD:-}"
+WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}"
+WSREP_SST_OPT_DEFAULT=""
+WSREP_SST_OPT_DEFAULTS=""
+WSREP_SST_OPT_EXTRA_DEFAULT=""
+WSREP_SST_OPT_EXTRA_DEFAULTS=""
+WSREP_SST_OPT_SUFFIX_DEFAULT=""
+WSREP_SST_OPT_SUFFIX_VALUE=""
+WSREP_SST_OPT_MYSQLD=""
+WSREP_SST_OPT_PORT=""
+WSREP_SST_OPT_ADDR=""
+WSREP_SST_OPT_ADDR_PORT=""
+WSREP_SST_OPT_HOST=""
+WSREP_SST_OPT_HOST_UNESCAPED=""
+ARIA_LOG_DIR=""
+INNODB_DATA_HOME_DIR=$(trim_dir "${INNODB_DATA_HOME_DIR:-}")
+INNODB_LOG_GROUP_HOME=$(trim_dir "${INNODB_LOG_GROUP_HOME:-}")
+INNODB_UNDO_DIR=$(trim_dir "${INNODB_UNDO_DIR:-}")
+INNODB_BUFFER_POOL=""
+INNODB_FORCE_RECOVERY=""
+INNOEXTRA=""
+
+while [ $# -gt 0 ]; do
+case "$1" in
+ '--address')
+ WSREP_SST_OPT_ADDR=$(trim_string "$2")
+ #
+ # Break address string into host:port/path parts
+ #
+ case "$WSREP_SST_OPT_ADDR" in
+ \[*)
+ # IPv6
+ # Remove the starting and ending square brackets, if present:
+ addr="${WSREP_SST_OPT_ADDR#\[}"
+ addr=$(trim_right "${addr%%\]*}")
+ # Some utilities and subsequent code require an address
+ # without square brackets:
+ readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr"
+ # Square brackets are needed in most cases:
+ readonly WSREP_SST_OPT_HOST="[$addr]"
+ # Mark this address as IPv6:
+ readonly WSREP_SST_OPT_HOST_IPv6=1
+ # Let's remove the leading part that contains the host address:
+ remain="${WSREP_SST_OPT_ADDR#*\]}"
+ ;;
+ *)
+ addr=$(trim_right "${WSREP_SST_OPT_ADDR%%[:/]*}")
+ readonly WSREP_SST_OPT_HOST="$addr"
+ readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr"
+ readonly WSREP_SST_OPT_HOST_IPv6=0
+ # Let's remove the leading part that contains the host address:
+ remain="${WSREP_SST_OPT_ADDR#*[:/]}"
+ ;;
+ esac
+ # If there is nothing but the address, then the remainder is empty:
+ [ "$remain" = "$WSREP_SST_OPT_ADDR" ] && remain=""
+ # Let's remove the ":" character that separates the port number
+ # from the hostname:
+ remain="${remain#:}"
+ # Extract the port number from the address - all characters
+ # up to "/" (if present):
+ WSREP_SST_OPT_ADDR_PORT="${remain%%/*}"
+ # If the "/" character is present, then the path is not empty:
+ if [ "$WSREP_SST_OPT_ADDR_PORT" != "$remain" ]; then
+ # This operation removes everything up to the "/" character,
+ # effectively removing the port number from the string:
+ readonly WSREP_SST_OPT_PATH="${remain#*/}"
+ else
+ readonly WSREP_SST_OPT_PATH=""
+ fi
+ WSREP_SST_OPT_ADDR_PORT=$(trim_right "$WSREP_SST_OPT_ADDR_PORT")
+ # Remove the module name part from the string, which ends with "/":
+ remain="${WSREP_SST_OPT_PATH#*/}"
+ # This operation removes the tail after the very first occurrence
+ # of the "/" character, inclusively:
+ readonly WSREP_SST_OPT_MODULE=$(trim_right "${WSREP_SST_OPT_PATH%%/*}")
+ # If there is one more "/" in the string, then everything before
+ # it will be the LSN, otherwise the LSN is empty:
+ if [ "$remain" != "$WSREP_SST_OPT_PATH" ]; then
+ # Extract the part that matches the LSN by removing all
+ # characters starting from the very first "/":
+ readonly WSREP_SST_OPT_LSN=$(trim_right "${remain%%/*}")
+ # Exctract everything after the first occurrence of
+ # the "/" character in the string:
+ source="$remain"
+ remain="${remain#*/}"
+ # If the remainder does not match the original string,
+ # then there is something else (the version number in
+ # our case):
+ if [ "$remain" != "$source" ]; then
+ # Let's extract the version number by removing the tail
+ # after the very first occurence of the "/" character
+ # (inclusively):
+ readonly WSREP_SST_OPT_SST_VER=$(trim_right "${remain%%/*}")
+ else
+ readonly WSREP_SST_OPT_SST_VER=""
+ fi
+ else
+ readonly WSREP_SST_OPT_LSN=""
+ readonly WSREP_SST_OPT_SST_VER=""
+ fi
+ shift
+ ;;
+ '--bypass')
+ readonly WSREP_SST_OPT_BYPASS=1
+ ;;
+ '--progress')
+ readonly WSREP_SST_OPT_PROGRESS=$(( $2 ))
+ shift
+ ;;
+ '--datadir')
+ # Let's remove the trailing slash:
+ readonly WSREP_SST_OPT_DATA=$(trim_dir "$2")
+ shift
+ ;;
+ '--aria-log-dir-path')
+ # Let's remove the trailing slash:
+ readonly ARIA_LOG_DIR=$(trim_dir "$2")
+ shift
+ ;;
+ '--innodb-data-home-dir')
+ # Let's remove the trailing slash:
+ readonly INNODB_DATA_HOME_DIR=$(trim_dir "$2")
+ shift
+ ;;
+ '--innodb-log-group-home-dir')
+ # Let's remove the trailing slash:
+ readonly INNODB_LOG_GROUP_HOME=$(trim_dir "$2")
+ shift
+ ;;
+ '--innodb-undo-directory')
+ # Let's remove the trailing slash:
+ readonly INNODB_UNDO_DIR=$(trim_dir "$2")
+ shift
+ ;;
+ '--innodb-buffer-pool-filename')
+ readonly INNODB_BUFFER_POOL=$(trim_string "$2")
+ shift
+ ;;
+ '--defaults-file')
+ file=$(trim_string "$2")
+ readonly WSREP_SST_OPT_DEFAULT="$1=$file"
+ readonly WSREP_SST_OPT_DEFAULTS="$1='$file'"
+ shift
+ ;;
+ '--defaults-extra-file')
+ file=$(trim_string "$2")
+ readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$file"
+ readonly WSREP_SST_OPT_EXTRA_DEFAULTS="$1='$file'"
+ shift
+ ;;
+ '--defaults-group-suffix')
+ suffix=$(trim_string "$2")
+ readonly WSREP_SST_OPT_SUFFIX_DEFAULT="$1=$suffix"
+ readonly WSREP_SST_OPT_SUFFIX_VALUE="$suffix"
+ shift
+ ;;
+ '--host')
+ addr=$(trim_string "$2")
+ case "$addr" in
+ \[*)
+ # IPv6
+ # Remove the starting and ending square brackets, if present:
+ addr="${addr#\[}"
+ addr=$(trim_right "${addr%%\]*}")
+ # Some utilities and subsequent code require an address
+ # without square brackets:
+ readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr"
+ # Square brackets are needed in most cases:
+ readonly WSREP_SST_OPT_HOST="[$addr]"
+ # Mark this address as IPv6:
+ readonly WSREP_SST_OPT_HOST_IPv6=1
+ ;;
+ *)
+ readonly WSREP_SST_OPT_HOST="$addr"
+ readonly WSREP_SST_OPT_HOST_UNESCAPED="$addr"
+ readonly WSREP_SST_OPT_HOST_IPv6=0
+ ;;
+ esac
+ WSREP_SST_OPT_ADDR="$addr"
+ shift
+ ;;
+ '--local-port')
+ readonly WSREP_SST_OPT_LPORT=$(( $2 ))
+ shift
+ ;;
+ '--parent')
+ readonly WSREP_SST_OPT_PARENT=$(( $2 ))
+ shift
+ ;;
+ '--password')
+ WSREP_SST_OPT_PSWD="$2"
+ shift
+ ;;
+ '--port')
+ readonly WSREP_SST_OPT_PORT=$(( $2 ))
+ shift
+ ;;
+ '--role')
+ readonly WSREP_SST_OPT_ROLE=$(trim_string "$2")
+ shift
+ ;;
+ '--socket')
+ readonly WSREP_SST_OPT_SOCKET=$(trim_string "$2")
+ shift
+ ;;
+ '--user')
+ WSREP_SST_OPT_USER="$2"
+ shift
+ ;;
+ '--gtid')
+ readonly WSREP_SST_OPT_GTID=$(trim_string "$2")
+ shift
+ ;;
+ '--binlog'|'--log-bin')
+ readonly WSREP_SST_OPT_BINLOG=$(trim_string "$2")
+ shift
+ ;;
+ '--binlog-index'|'--log-bin-index')
+ WSREP_SST_OPT_BINLOG_INDEX=$(trim_string "$2")
+ shift
+ ;;
+ '--log-basename')
+ readonly WSREP_SST_OPT_LOG_BASENAME=$(trim_string "$2")
+ shift
+ ;;
+ '--gtid-domain-id')
+ readonly WSREP_SST_OPT_GTID_DOMAIN_ID=$(trim_string "$2")
+ shift
+ ;;
+ '--mysqld-args')
+ original_cmd=""
+ shift
+ cmd_tail=0
+ while [ $# -gt 0 ]; do
+ lname="${1#--}"
+ # "--" is interpreted as the end of the list of options:
+ if [ -z "$lname" ]; then
+ shift
+ if [ $# -gt 0 ]; then
+ # copy "--" to the output string:
+ original_cmd="$original_cmd --"
+ # All other arguments must be copied unchanged:
+ while [ $# -gt 0 ]; do
+ original_cmd="$original_cmd '$1'"
+ shift
+ done
+ fi
+ break
+ fi
+ # Make sure the argument does not start with "--", otherwise it
+ # is a long option, which is processed after this "if":
+ if [ "$lname" = "$1" ]; then
+ # Check if the argument is the short option or the short
+ # options list, starting with "-":
+ options="${1#-}"
+ if [ "$options" != "$1" -a -n "$options" ]; then
+ slist=""
+ while [ -n "$options" ]; do
+ # Let's separate the first character as the current
+ # option name:
+ if [ -n "$BASH_VERSION" ]; then
+ option="${options:0:1}"
+ else
+ # If it's not bash, then we need to use slow
+ # external utilities:
+ option=$(echo "$options" | cut -c1)
+ fi
+ # And the subsequent characters consider option value:
+ value=""
+ if [ ${#options} -gt 0 ]; then
+ value="${options#?}"
+ fi
+ # Check for options without argument:
+ if [ "$option" != '?' -a \
+ "$option" != 'a' -a \
+ "$option" != 's' -a \
+ "$option" != 'v' ]
+ then
+ # If the option value is absent, then check
+ # the following argument:
+ if [ -z "$value" -a $# -gt 1 ]; then
+ # if the next argument does not start with
+ # the "-" character, then next argument is
+ # the current option value:
+ if [ "${2#-}" = "$2" ]; then
+ shift
+ value="$1"
+ elif [ "$2" = '--' ]; then
+ shift
+ if [ $# -gt 1 ]; then
+ cmd_tail=1
+ shift
+ value="$1"
+ fi
+ fi
+ fi
+ if [ "$option" = 'h' ]; then
+ if [ -z "$WSREP_SST_OPT_DATA" ]; then
+ MYSQLD_OPT_DATADIR=$(trim_dir "$value")
+ fi
+ elif [ "$option" != 'u' -a \
+ "$option" != 'P' ]
+ then
+ if [ $cmd_tail -ne 0 ]; then
+ option="$option --"
+ fi
+ if [ -z "$value" ]; then
+ slist="$slist$option"
+ elif [ -z "$slist" ]; then
+ slist="$option '$value'"
+ else
+ slist="$slist -$option '$value'"
+ fi
+ break
+ fi
+ if [ $cmd_tail -ne 0 ]; then
+ if [ -n "$slist" ]; then
+ slist="$slist --"
+ else
+ slist='-'
+ fi
+ fi
+ break
+ else
+ slist="$slist$option"
+ fi
+ options="$value"
+ done
+ if [ -n "$slist" ]; then
+ original_cmd="$original_cmd -$slist"
+ fi
+ elif [ -z "$options" ]; then
+ # We found an minus sign without any characters after it:
+ original_cmd="$original_cmd -"
+ else
+ # We found a value that does not start with a minus -
+ # it is a positional argument or the value of previous
+ # option. Copy it to output string (as is):
+ original_cmd="$original_cmd '$1'"
+ fi
+ shift
+ if [ $cmd_tail -ne 0 ]; then
+ # All other arguments must be copied unchanged:
+ while [ $# -gt 0 ]; do
+ original_cmd="$original_cmd '$1'"
+ shift
+ done
+ break
+ fi
+ continue
+ fi
+ # Now we are sure that we are working with an option
+ # that has a "long" name, so remove all characters after
+ # the first equal sign:
+ option="${1%%=*}"
+ # If the option name contains underscores, then replace
+ # them to minuses:
+ if [ "${option#*_}" != "$option" ]; then
+ option=$(to_minuses "$option")
+ fi
+ # The "--loose-" prefix should not affect the recognition
+ # of the option name:
+ if [ "${option#--loose-}" != "$option" ]; then
+ option="--${option#--loose-}"
+ fi
+ # Some options just need to be removed from the list:
+ if [ "$option" != '--defaults-file' -a \
+ "$option" != '--defaults-extra-file' -a \
+ "$option" != '--defaults-group-suffix' -a \
+ "$option" != '--user' -a \
+ "$option" != '--port' -a \
+ "$option" != '--socket' ]; then
+ value="${1#*=}"
+ if [ "$value" = "$1" ]; then
+ value=""
+ fi
+ # Let's fill in the variables containing important paths
+ # that might not have been passed through explicit parameters
+ # (+ removing the trailing slash in these paths). Many of these
+ # options are processed internally within scripts or passed
+ # explicitly to other programs, so we need to remove them
+ # from mysqld's argument list:
+ skip_mysqld_arg=0
+ case "$option" in
+ '--aria-log-dir-path')
+ if [ -z "$ARIA_LOG_DIR" ]; then
+ MYSQLD_OPT_ARIA_LOG_DIR=$(trim_dir "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--innodb-data-home-dir')
+ if [ -z "$INNODB_DATA_HOME_DIR" ]; then
+ MYSQLD_OPT_INNODB_DATA_HOME_DIR=$(trim_dir "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--innodb-log-group-home-dir')
+ if [ -z "$INNODB_LOG_GROUP_HOME" ]; then
+ MYSQLD_OPT_INNODB_LOG_GROUP_HOME=$(trim_dir "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--innodb-undo-directory')
+ if [ -z "$INNODB_UNDO_DIR" ]; then
+ MYSQLD_OPT_INNODB_UNDO_DIR=$(trim_dir "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--innodb-buffer-pool-filename')
+ if [ -z "$INNODB_BUFFER_POOL" ]; then
+ MYSQLD_OPT_INNODB_BUFFER_POOL=$(trim_string "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--innodb-force-recovery')
+ if [ -n "$value" -a "$value" != "0" ]; then
+ INNODB_FORCE_RECOVERY=$(trim_string "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--log-bin')
+ if [ -z "$WSREP_SST_OPT_BINLOG" ]; then
+ MYSQLD_OPT_LOG_BIN=$(trim_string "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--log-bin-index')
+ if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then
+ MYSQLD_OPT_LOG_BIN_INDEX=$(trim_string "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--log-basename')
+ if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ MYSQLD_OPT_LOG_BASENAME=$(trim_string "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ '--datadir')
+ if [ -z "$WSREP_SST_OPT_DATA" ]; then
+ MYSQLD_OPT_DATADIR=$(trim_dir "$value")
+ fi
+ skip_mysqld_arg=1
+ ;;
+ esac
+ if [ $skip_mysqld_arg -eq 0 ]; then
+ original_cmd="$original_cmd '$1'"
+ fi
+ fi
+ shift
+ done
+ WSREP_SST_OPT_MYSQLD="${original_cmd# *}"
+ break
+ ;;
+ *) # Must be command usage
+ # exit 1
+ ;;
+esac
+shift
+done
+
+WSREP_TRANSFER_TYPE='SST'
+[ $WSREP_SST_OPT_BYPASS -ne 0 ] && readonly WSREP_TRANSFER_TYPE='IST'
+# Let's take the name of the current script as a base,
+# removing the directory, extension and "wsrep_sst_" prefix:
+WSREP_METHOD="${0##*/}"
+WSREP_METHOD="${WSREP_METHOD%.*}"
+readonly WSREP_METHOD="${WSREP_METHOD#wsrep_sst_}"
+if [ -n "${WSREP_SST_OPT_ROLE+x}" ]; then
+ if [ "$WSREP_SST_OPT_ROLE" != 'donor' -a \
+ "$WSREP_SST_OPT_ROLE" != 'joiner' ]
+ then
+ wsrep_log_error "Unrecognized role: '$WSREP_SST_OPT_ROLE'"
+ exit 22 # EINVAL
+ fi
+else
+ readonly WSREP_SST_OPT_ROLE='donor'
+fi
+
+readonly WSREP_SST_OPT_PROGRESS
+
+# The same argument can be present on the command line several
+# times, in this case we must take its last value:
+if [ -n "${MYSQLD_OPT_ARIA_LOG_DIR:-}" -a \
+ -z "$ARIA_LOG_DIR" ]; then
+ readonly ARIA_LOG_DIR="$MYSQLD_OPT_ARIA_LOG_DIR"
+fi
+if [ -n "${MYSQLD_OPT_INNODB_DATA_HOME_DIR:-}" -a \
+ -z "$INNODB_DATA_HOME_DIR" ]; then
+ readonly INNODB_DATA_HOME_DIR="$MYSQLD_OPT_INNODB_DATA_HOME_DIR"
+fi
+if [ -n "${MYSQLD_OPT_INNODB_LOG_GROUP_HOME:-}" -a \
+ -z "$INNODB_LOG_GROUP_HOME" ]; then
+ readonly INNODB_LOG_GROUP_HOME="$MYSQLD_OPT_INNODB_LOG_GROUP_HOME"
+fi
+if [ -n "${MYSQLD_OPT_INNODB_UNDO_DIR:-}" -a \
+ -z "$INNODB_UNDO_DIR" ]; then
+ readonly INNODB_UNDO_DIR="$MYSQLD_OPT_INNODB_UNDO_DIR"
+fi
+if [ -n "${MYSQLD_OPT_INNODB_BUFFER_POOL:-}" -a \
+ -z "$INNODB_BUFFER_POOL" ]; then
+ readonly INNODB_BUFFER_POOL="$MYSQLD_OPT_INNODB_BUFFER_POOL"
+fi
+if [ -n "${MYSQLD_OPT_LOG_BIN:-}" -a \
+ -z "$WSREP_SST_OPT_BINLOG" ]; then
+ readonly WSREP_SST_OPT_BINLOG="$MYSQLD_OPT_LOG_BIN"
+fi
+if [ -n "${MYSQLD_OPT_LOG_BIN_INDEX:-}" -a \
+ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then
+ WSREP_SST_OPT_BINLOG_INDEX="$MYSQLD_OPT_LOG_BIN_INDEX"
+fi
+if [ -n "${MYSQLD_OPT_DATADIR:-}" -a \
+ -z "$WSREP_SST_OPT_DATA" ]; then
+ readonly WSREP_SST_OPT_DATA="$MYSQLD_OPT_DATADIR"
+fi
+if [ -n "${MYSQLD_OPT_LOG_BASENAME:-}" -a \
+ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ readonly WSREP_SST_OPT_LOG_BASENAME="$MYSQLD_OPT_LOG_BASENAME"
+fi
+
+# If the --log-bin option is present without a value, then
+# set WSREP_SST_OPT_BINLOG value using other arguments:
+if [ -z "$WSREP_SST_OPT_BINLOG" -a -n "${MYSQLD_OPT_LOG_BIN+x}" ]; then
+ if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ # If the WSREP_SST_OPT_BINLOG variable is not set, but
+ # --log-basename is present among the arguments to mysqld,
+ # then set WSREP_SST_OPT_BINLOG equal to the base name
+ # with the "-bin" suffix:
+ readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin"
+ else
+ # Take the default name:
+ readonly WSREP_SST_OPT_BINLOG='mysql-bin'
+ fi
+fi
+
+# Reconstructing the command line arguments that control the innodb
+# and binlog options:
+if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then
+ WSREP_SST_OPT_MYSQLD="--log-basename='$WSREP_SST_OPT_LOG_BASENAME' $WSREP_SST_OPT_MYSQLD"
+ else
+ WSREP_SST_OPT_MYSQLD="--log-basename='$WSREP_SST_OPT_LOG_BASENAME'"
+ fi
+fi
+if [ -n "$ARIA_LOG_DIR" ]; then
+ INNOEXTRA="$INNOEXTRA --aria-log-dir-path='$ARIA_LOG_DIR'"
+fi
+if [ -n "$INNODB_DATA_HOME_DIR" ]; then
+ INNOEXTRA="$INNOEXTRA --innodb-data-home-dir='$INNODB_DATA_HOME_DIR'"
+fi
+if [ -n "$INNODB_LOG_GROUP_HOME" ]; then
+ INNOEXTRA="$INNOEXTRA --innodb-log-group-home-dir='$INNODB_LOG_GROUP_HOME'"
+fi
+if [ -n "$INNODB_UNDO_DIR" ]; then
+ INNOEXTRA="$INNOEXTRA --innodb-undo-directory='$INNODB_UNDO_DIR'"
+fi
+if [ -n "$INNODB_BUFFER_POOL" ]; then
+ INNOEXTRA="$INNOEXTRA --innodb-buffer-pool-filename='$INNODB_BUFFER_POOL'"
+fi
+if [ -n "$WSREP_SST_OPT_BINLOG" ]; then
+ INNOEXTRA="$INNOEXTRA --log-bin='$WSREP_SST_OPT_BINLOG'"
+ if [ -n "$WSREP_SST_OPT_BINLOG_INDEX" ]; then
+ if [ -n "$WSREP_SST_OPT_MYSQLD" ]; then
+ WSREP_SST_OPT_MYSQLD="--log-bin-index='$WSREP_SST_OPT_BINLOG_INDEX' $WSREP_SST_OPT_MYSQLD"
+ else
+ WSREP_SST_OPT_MYSQLD="--log-bin-index='$WSREP_SST_OPT_BINLOG_INDEX'"
+ fi
+ fi
+fi
+
+readonly INNODB_FORCE_RECOVERY
+readonly WSREP_SST_OPT_MYSQLD
+
+get_binlog()
+{
+ # if no command line argument and WSREP_SST_OPT_BINLOG is not set,
+ # try to get it from my.cnf:
+ if [ -z "$WSREP_SST_OPT_BINLOG" ]; then
+ WSREP_SST_OPT_BINLOG=$(parse_cnf '--mysqld' 'log-bin')
+ fi
+ # if no command line argument and WSREP_SST_OPT_BINLOG_INDEX is not set,
+ # try to get it from my.cnf:
+ if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then
+ WSREP_SST_OPT_BINLOG_INDEX=$(parse_cnf '--mysqld' 'log-bin-index')
+ fi
+ # if no command line argument and WSREP_SST_OPT_LOG_BASENAME is not set,
+ # then try to get it from my.cnf:
+ if [ -z "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ WSREP_SST_OPT_LOG_BASENAME=$(parse_cnf '--mysqld' 'log-basename')
+ fi
+ if [ -z "$WSREP_SST_OPT_BINLOG" ]; then
+ # If the log-bin option is specified without a parameter,
+ # then we need to build the name of the index file according
+ # to the rules described in the server documentation:
+ if [ $(in_config '--mysqld' 'log-bin') -ne 0 ]; then
+ if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ # If the WSREP_SST_OPT_BINLOG variable is not set, but
+ # --log-basename is present among the arguments of mysqld,
+ # then set WSREP_SST_OPT_BINLOG equal to the base name
+ # with the "-bin" suffix:
+ readonly WSREP_SST_OPT_BINLOG="$WSREP_SST_OPT_LOG_BASENAME-bin"
+ else
+ # Take the default name:
+ readonly WSREP_SST_OPT_BINLOG='mysql-bin'
+ fi
+ fi
+ fi
+ if [ -n "$WSREP_SST_OPT_BINLOG" ]; then
+ # If the name of the index file is not specified, then we will build
+ # it according to the specifications for the server:
+ if [ -z "$WSREP_SST_OPT_BINLOG_INDEX" ]; then
+ if [ -n "$WSREP_SST_OPT_LOG_BASENAME" ]; then
+ # If the WSREP_SST_OPT_BINLOG_INDEX variable is not set, but
+ # --log-basename is present among the arguments of mysqld,
+ # then set WSREP_SST_OPT_BINLOG_INDEX equal to the base name
+ # with the "-bin" suffix:
+ readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_LOG_BASENAME-bin.index"
+ else
+ # Use the default name (note that base of this name
+ # is already defined above):
+ readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_BINLOG.index"
+ fi
+ else
+ # Remove all directories from the index file path:
+ local filename="${WSREP_SST_OPT_BINLOG_INDEX##*/}"
+ # Check if the index file name contains the extension:
+ if [ "${filename%.*}" = "$filename" ]; then
+ # Let's add the default extension (".index"):
+ readonly WSREP_SST_OPT_BINLOG_INDEX="$WSREP_SST_OPT_BINLOG_INDEX.index"
+ else
+ readonly WSREP_SST_OPT_BINLOG_INDEX
+ fi
+ fi
+ fi
+}
+
+# Check the presence of the port value and, if necessary, transfer
+# the port number from the address to the WSREP_SST_OPT_PORT variable
+# or vice versa, and also, if necessary, substitute the missing port
+# value into the address value:
+if [ -n "$WSREP_SST_OPT_ADDR_PORT" ]; then
+ if [ -n "$WSREP_SST_OPT_PORT" ]; then
+ if [ "$WSREP_SST_OPT_PORT" != "$WSREP_SST_OPT_ADDR_PORT" ]; then
+ echo "WSREP_SST: [ERROR] port in --port=$WSREP_SST_OPT_PORT" \
+ "differs from port in --address=$WSREP_SST_OPT_ADDR" >&2
+ exit 2
+ fi
+ else
+ # If the address contains a port number, assign it to
+ # the corresponding variable:
+ readonly WSREP_SST_OPT_PORT="$WSREP_SST_OPT_ADDR_PORT"
+ fi
+else
+ # If the port is missing, take the default port:
+ if [ -z "$WSREP_SST_OPT_PORT" ]; then
+ readonly WSREP_SST_OPT_PORT=4444
+ fi
+ WSREP_SST_OPT_ADDR_PORT="$WSREP_SST_OPT_PORT"
+fi
+
+# Let's construct a new value for the address with the port:
+sst_path="${WSREP_SST_OPT_PATH:+/}$WSREP_SST_OPT_PATH"
+WSREP_SST_OPT_ADDR="$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT$sst_path"
+
+readonly WSREP_SST_OPT_ADDR
+readonly WSREP_SST_OPT_ADDR_PORT
+
+commandex()
+{
+ if [ -n "$BASH_VERSION" ]; then
+ command -v "$1" || :
+ elif [ -x "$1" ]; then
+ echo "$1"
+ else
+ which "$1" || :
+ fi
+}
+
+# try to use my_print_defaults, mysql and mysqldump that come
+# with the sources (for MTR suite):
+script_binary=$(dirname "$0")
+SCRIPTS_DIR=$(cd "$script_binary"; pwd)
+EXTRA_DIR="$SCRIPTS_DIR/../extra"
+CLIENT_DIR="$SCRIPTS_DIR/../client"
+
+if [ -x "$CLIENT_DIR/mariadb" ]; then
+ MYSQL_CLIENT="$CLIENT_DIR/mariadb"
+else
+ MYSQL_CLIENT=$(commandex 'mariadb')
+fi
+
+if [ -x "$CLIENT_DIR/mariadb-dump" ]; then
+ MYSQLDUMP="$CLIENT_DIR/mariadb-dump"
+else
+ MYSQLDUMP=$(commandex 'mariadb-dump')
+fi
+
+wsrep_log()
+{
+ # echo everything to stderr so that it gets into common error log
+ # deliberately made to look different from the rest of the log
+ local readonly tst=$(date "+%Y%m%d %H:%M:%S.%N" | cut -b -21)
+ echo "WSREP_SST: $* ($tst)" >&2
+}
+
+wsrep_log_error()
+{
+ wsrep_log "[ERROR] $*"
+}
+
+wsrep_log_warning()
+{
+ wsrep_log "[WARNING] $*"
+}
+
+wsrep_log_info()
+{
+ wsrep_log "[INFO] $*"
+}
+
+if [ -x "$SCRIPTS_DIR/my_print_defaults" ]; then
+ MY_PRINT_DEFAULTS="$SCRIPTS_DIR/my_print_defaults"
+elif [ -x "$EXTRA_DIR/my_print_defaults" ]; then
+ MY_PRINT_DEFAULTS="$EXTRA_DIR/my_print_defaults"
+else
+ MY_PRINT_DEFAULTS=$(commandex 'my_print_defaults')
+ if [ -z "$MY_PRINT_DEFAULTS" ]; then
+ wsrep_log_error "my_print_defaults not found in path"
+ exit 2
+ fi
+fi
+
+readonly MY_PRINT_DEFAULTS
+
+wsrep_defaults="$WSREP_SST_OPT_DEFAULTS"
+wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_EXTRA_DEFAULTS:+ }$WSREP_SST_OPT_EXTRA_DEFAULTS"
+wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_SUFFIX_DEFAULT:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT"
+
+readonly WSREP_SST_OPT_CONF="${wsrep_defaults:+ }$wsrep_defaults"
+
+wsrep_defaults="$WSREP_SST_OPT_DEFAULT"
+wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_EXTRA_DEFAULT:+ }$WSREP_SST_OPT_EXTRA_DEFAULT"
+wsrep_defaults="$wsrep_defaults${WSREP_SST_OPT_SUFFIX_DEFAULT:+ }$WSREP_SST_OPT_SUFFIX_DEFAULT"
+
+readonly WSREP_SST_OPT_CONF_UNQUOTED="${wsrep_defaults:+ }$wsrep_defaults"
+
+#
+# User can specify mariabackup specific settings that will be used during sst
+# process like encryption, etc. Parse such configuration option.
+#
+# 1st parameter: group (config file section like sst) or
+# my_print_defaults argument (like --mysqld)
+# 2nd parameter: var : name of the variable in the section, e.g. server-id
+# 3rd parameter: default value for the parameter
+#
+parse_cnf()
+{
+ local groups="$1"
+ local var="$2"
+ local reval=""
+
+ # normalize the variable names specified in the .cnf file
+ # (user can use '_' or '-', for example, log-bin or log_bin),
+ # then search for the last instance of the desired variable
+ # and finally get the value of that variable (if the variable
+ # was specified several times - we use only its last instance):
+
+ local pattern='BEGIN {OFS=FS="="} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") lastval=substr($0,length($1)+2)} END {print lastval}'
+
+ while [ -n "$groups" ]; do
+ # Remove the largest suffix starting with the '|' character:
+ local group="${groups%%\|*}"
+ # Remove the remainder (the group name) from the rest
+ # of the groups list (as if it were a prefix):
+ if [ "$group" != "$groups" ]; then
+ groups="${groups#*\|}"
+ else
+ groups=""
+ fi
+ # If the group name is the same as the "mysqld" without "--" prefix,
+ # then try to use it together with the group suffix:
+ if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
+ reval=$("$MY_PRINT_DEFAULTS" \
+ ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
+ ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
+ ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
+ "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
+ if [ -n "$reval" ]; then
+ break
+ fi
+ fi
+ # Let's try to use the group name as it is:
+ reval=$("$MY_PRINT_DEFAULTS" \
+ ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
+ ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
+ ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
+ "$group" | awk "$pattern")
+ if [ -n "$reval" ]; then
+ break
+ fi
+ done
+
+ # Use default if we haven't found a value:
+ [ -z "$reval" ] && reval="${3:-}"
+
+ # Truncate spaces:
+ [ -n "$reval" ] && reval=$(trim_string "$reval")
+
+ if [ -n "$BASH_VERSION" ]; then
+ printf '%s' "$reval"
+ else
+ echo "$reval"
+ fi
+}
+
+#
+# This function simply checks for the presence of the parameter
+# in the config file, but does not return its value. It returns "1"
+# (true) even if the parameter is present in the configuration file
+# without a value:
+#
+in_config()
+{
+ local groups="$1"
+ local var="$2"
+ local found=0
+
+ # normalize the variable names specified in the .cnf file
+ # (user can use '_' or '-', for example, log-bin or log_bin),
+ # then search for the last instance(s) of the desired variable:
+
+ local pattern='BEGIN {OFS=FS="="; found=0} {sub(/^--loose/,"-",$0); gsub(/_/,"-",$1); if ($1=="--'"$var"'") found=1} END {print found}'
+
+ while [ -n "$groups" ]; do
+ # Remove the largest suffix starting with the '|' character:
+ local group="${groups%%\|*}"
+ # Remove the remainder (the group name) from the rest
+ # of the groups list (as if it were a prefix):
+ if [ "$group" != "$groups" ]; then
+ groups="${groups#*\|}"
+ else
+ groups=""
+ fi
+ # If the group name is the same as the "mysqld" without "--" prefix,
+ # then try to use it together with the group suffix:
+ if [ "$group" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
+ found=$("$MY_PRINT_DEFAULTS" \
+ ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
+ ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
+ ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
+ "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
+ if [ $found -ne 0 ]; then
+ break
+ fi
+ fi
+ # Let's try to use the group name as it is:
+ found=$($MY_PRINT_DEFAULTS \
+ ${WSREP_SST_OPT_DEFAULT:+"$WSREP_SST_OPT_DEFAULT"} \
+ ${WSREP_SST_OPT_EXTRA_DEFAULT:+"$WSREP_SST_OPT_EXTRA_DEFAULT"} \
+ ${WSREP_SST_OPT_SUFFIX_DEFAULT:+"$WSREP_SST_OPT_SUFFIX_DEFAULT"} \
+ "$group" | awk "$pattern")
+ if [ $found -ne 0 ]; then
+ break
+ fi
+ done
+ if [ -n "$BASH_VERSION" ]; then
+ printf '%s' $found
+ else
+ echo $found
+ fi
+}
+
+wsrep_auth_not_set()
+{
+ [ -z "$WSREP_SST_OPT_AUTH" ]
+}
+
+# Get rid of incorrect values resulting from substitution
+# in programs external to the script:
+if [ "$WSREP_SST_OPT_USER" = '(null)' ]; then
+ WSREP_SST_OPT_USER=""
+fi
+if [ "$WSREP_SST_OPT_PSWD" = '(null)' ]; then
+ WSREP_SST_OPT_PSWD=""
+fi
+if [ "$WSREP_SST_OPT_AUTH" = '(null)' ]; then
+ WSREP_SST_OPT_AUTH=""
+fi
+
+# Let's read the value of the authentication string from the
+# configuration file so that it does not go to the command line
+# and does not appear in the ps output:
+if wsrep_auth_not_set; then
+ WSREP_SST_OPT_AUTH=$(parse_cnf 'sst' 'wsrep-sst-auth')
+fi
+
+# Splitting WSREP_SST_OPT_AUTH as "user:password" pair:
+if ! wsrep_auth_not_set; then
+ # Extract username as shortest prefix up to first ':' character:
+ WSREP_SST_OPT_AUTH_USER="${WSREP_SST_OPT_AUTH%%:*}"
+ if [ -z "$WSREP_SST_OPT_USER" ]; then
+ # if the username is not in the command line arguments,
+ # set the username and password using WSREP_SST_OPT_AUTH
+ # from the environment:
+ WSREP_SST_OPT_USER="$WSREP_SST_OPT_AUTH_USER"
+ WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}"
+ elif [ "$WSREP_SST_OPT_USER" = "$WSREP_SST_OPT_AUTH_USER" ]; then
+ # If the username in the command line arguments and in
+ # the environment variable are the same, set the password
+ # if it was not specified in the command line:
+ if [ -z "$WSREP_SST_OPT_PSWD" ]; then
+ WSREP_SST_OPT_PSWD="${WSREP_SST_OPT_AUTH#*:}"
+ fi
+ else
+ # The username is passed through the command line and does
+ # not match the username in the environment variable - ignore
+ # the environment and rebuild the authentication parameters:
+ WSREP_SST_OPT_AUTH="$WSREP_SST_OPT_USER:$WSREP_SST_OPT_PSWD"
+ fi
+fi
+
+readonly WSREP_SST_OPT_USER
+readonly WSREP_SST_OPT_PSWD
+readonly WSREP_SST_OPT_AUTH
+
+if [ -n "$WSREP_SST_OPT_REMOTE_AUTH" ]; then
+ # Split auth string at the last ':'
+ readonly WSREP_SST_OPT_REMOTE_USER="${WSREP_SST_OPT_REMOTE_AUTH%%:*}"
+ readonly WSREP_SST_OPT_REMOTE_PSWD="${WSREP_SST_OPT_REMOTE_AUTH#*:}"
+else
+ readonly WSREP_SST_OPT_REMOTE_USER=
+ readonly WSREP_SST_OPT_REMOTE_PSWD=
+fi
+
+readonly WSREP_SST_OPT_REMOTE_AUTH
+
+if [ -n "$WSREP_SST_OPT_DATA" ]; then
+ SST_PROGRESS_FILE="$WSREP_SST_OPT_DATA/sst_in_progress"
+else
+ SST_PROGRESS_FILE=""
+fi
+
+wsrep_cleanup_progress_file()
+{
+ if [ -n "$SST_PROGRESS_FILE" -a -f "$SST_PROGRESS_FILE" ]; then
+ rm -f "$SST_PROGRESS_FILE" 2>/dev/null || :
+ fi
+}
+
+wsrep_check_program()
+{
+ local prog="$1"
+ local cmd=$(commandex "$prog")
+ if [ -z "$cmd" ]; then
+ echo "'$prog' not found in PATH"
+ return 2 # no such file or directory
+ fi
+}
+
+wsrep_check_programs()
+{
+ local ret=0
+ while [ $# -gt 0 ]; do
+ wsrep_check_program "$1" || ret=$?
+ shift
+ done
+ return $ret
+}
+
+wsrep_check_datadir()
+{
+ if [ -z "$WSREP_SST_OPT_DATA" ]; then
+ wsrep_log_error \
+ "The '--datadir' parameter must be passed to the SST script"
+ exit 2
+ fi
+}
+
+get_openssl()
+{
+ # If the OPENSSL_BINARY variable is already defined, just return:
+ if [ -n "${OPENSSL_BINARY+x}" ]; then
+ return
+ fi
+ # Let's look for openssl:
+ OPENSSL_BINARY=$(commandex 'openssl')
+ if [ -z "$OPENSSL_BINARY" ]; then
+ OPENSSL_BINARY='/usr/bin/openssl'
+ if [ ! -x "$OPENSSL_BINARY" ]; then
+ OPENSSL_BINARY=""
+ fi
+ fi
+ readonly OPENSSL_BINARY
+}
+
+#
+# Generate a string equivalent to 16 random bytes
+#
+wsrep_gen_secret()
+{
+ get_openssl
+ if [ -n "$OPENSSL_BINARY" ]; then
+ "$OPENSSL_BINARY" rand -hex 16
+ elif [ -n "$BASH_VERSION" ]; then
+ printf '%04x%04x%04x%04x%04x%04x%04x%04x' \
+ $RANDOM $RANDOM $RANDOM $RANDOM \
+ $RANDOM $RANDOM $RANDOM $RANDOM
+ elif [ -n "$(commandex cksum)" -a \
+ -n "$(commandex printf)" ]
+ then
+ printf '%08x%08x%08x%08x' \
+ $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \
+ $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \
+ $(head -8 /dev/urandom | cksum | cut -d ' ' -f1) \
+ $(head -8 /dev/urandom | cksum | cut -d ' ' -f1)
+ else
+ wsrep_log_error "Unable to generate 16-byte secret"
+ exit 22
+ fi
+}
+
+#
+# Checking if the address passed to us is local.
+# If the second parameter is nonzero, then this function
+# does not check for matches with local domain names:
+#
+is_local_ip()
+{
+ # Rapid recognition of the most common cases:
+ [ "$1" = '127.0.0.1' -o \
+ "$1" = '127.0.0.2' -o \
+ "$1" = 'localhost' -o \
+ "$1" = '::1' ] && return 0
+ # If the address starts with "127." this is probably a local
+ # address, but we need to clarify what follows this prefix:
+ if [ "${1#127.}" != "$1" ]; then
+ # All 127.0.0.0/8 addresses are local:
+ if echo "$1" | grep -q -E '^127\.[0-9]+\.[0-9]+\.[0-9]+$'; then
+ return 0
+ fi
+ fi
+ # If the second parameter is nonzero, then we will skip
+ # the domain name check:
+ if [ "${2:-0}" -eq 0 ]; then
+ # We consider all the names of a given host to be local addresses:
+ [ "$1" = "$(hostname -s)" -o \
+ "$1" = "$(hostname -f)" -o \
+ "$1" = "$(hostname -d)" ] && return 0
+ fi
+ # If the address contains anything other than digits
+ # and separators, it is not a local address:
+ [ "${1#*[!0-9.]}" != "$1" ] && \
+ [ "${1#*[!0-9A-Fa-f:\[\]]}" != "$1" ] && return 1
+ # Now let's check if the given address is assigned to
+ # one of the network cards:
+ local ip_util=$(commandex 'ip')
+ if [ -n "$ip_util" ]; then
+ # ip address show ouput format is " inet[6] <address>/<mask>":
+ "$ip_util" address show \
+ | grep -o -E '^[[:space:]]*inet.?[[:space:]]+[^[:space:]]+/' \
+ | grep -qw -F -- "$1/" && return 0
+ else
+ local ifconfig_util=$(commandex 'ifconfig')
+ if [ -n "$ifconfig_util" ]; then
+ # ifconfig output format is " inet[6] <address> ...":
+ "$ifconfig_util" \
+ | grep -o -E '^[[:space:]]*inet.?[[:space:]]+[^[:space:]]+' \
+ | grep -qw -F -- "$1" && return 0
+ fi
+ fi
+ return 1
+}
+
+check_sockets_utils()
+{
+ lsof_available=0
+ sockstat_available=0
+ ss_available=0
+
+ [ -n "$(commandex lsof)" ] && lsof_available=1
+ [ -n "$(commandex sockstat)" ] && sockstat_available=1
+ [ -n "$(commandex ss)" ] && ss_available=1
+
+ if [ $lsof_available -eq 0 -a \
+ $sockstat_available -eq 0 -a \
+ $ss_available -eq 0 ]
+ then
+ wsrep_log_error "Neither lsof, nor sockstat or ss tool was found in" \
+ "the PATH. Make sure you have it installed."
+ exit 2 # ENOENT
+ fi
+}
+
+#
+# Check if the port is in the "listen" state.
+# The first parameter is the PID of the process that should
+# listen on the port - if it is not known, you can specify
+# an empty string or zero.
+# The second parameter is the port number.
+# The third parameter is a list of the names of utilities
+# (via "|") that can listen on this port during the state
+# transfer.
+#
+check_port()
+{
+ local pid="${1:-0}"
+ local port="$2"
+ local utils="$3"
+
+ [ $pid -le 0 ] && pid='[0-9]+'
+
+ local rc=1
+
+ if [ $lsof_available -ne 0 ]; then
+ lsof -Pnl -i ":$port" 2>/dev/null | \
+ grep -q -E "^($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*\\(LISTEN\\)" && rc=0
+ elif [ $sockstat_available -ne 0 ]; then
+ local opts='-p'
+ if [ "$OS" = 'FreeBSD' ]; then
+ # sockstat on FreeBSD requires the "-s" option
+ # to display the connection state:
+ opts='-sp'
+ fi
+ sockstat "$opts" "$port" 2>/dev/null | \
+ grep -q -E "[[:space:]]+($utils)[^[:space:]]*[[:space:]]+$pid[[:space:]].*[[:space:]]LISTEN" && rc=0
+ elif [ $ss_available -ne 0 ]; then
+ ss -nlpH "( sport = :$port )" 2>/dev/null | \
+ grep -q -E "users:\\(.*\\(\"($utils)[^[:space:]]*\"[^)]*,pid=$pid(,[^)]*)?\\)" && rc=0
+ else
+ wsrep_log_error "Unknown sockets utility"
+ exit 2 # ENOENT
+ fi
+
+ return $rc
+}
+
+#
+# If the ssl_dhparams variable is already set, uses that as a source
+# of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in
+# the datadir, and creates it there if it can't find the file.
+#
+check_for_dhparams()
+{
+ ssl_dhparams="$DATA/dhparams.pem"
+ get_openssl
+ if [ -n "$OPENSSL_BINARY" ]; then
+ wsrep_log_info \
+ "Could not find dhparams file, creating $ssl_dhparams"
+ local bug=0
+ local errmsg
+ errmsg=$("$OPENSSL_BINARY" \
+ dhparam -out "$ssl_dhparams" -dsaparam 2048 2>&1) || bug=1
+ if [ $bug -ne 0 ]; then
+ wsrep_log_info "run: \"$OPENSSL_BINARY\" dhparam"\
+ "-out \"$ssl_dhparams\" -dsaparam 2048"
+ wsrep_log_info "output: $errmsg"
+ wsrep_log_error "******** ERROR *****************************************"
+ wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. *"
+ wsrep_log_error "********************************************************"
+ ssl_dhparams=""
+ fi
+ else
+ # Rollback: if openssl is not installed, then use
+ # the default parameters:
+ ssl_dhparams=""
+ fi
+}
+
+#
+# Verifies that the CA file verifies the certificate.
+# Doing this here lets us generate better error messages.
+#
+# 1st param: path to the CA file.
+# 2nd param: path to the certificate.
+#
+verify_ca_matches_cert()
+{
+ local cert="$1"
+ local ca="$2"
+ local cap="$3"
+
+ local readable=1; [ ! -r "$cert" ] && readable=0
+ [ -n "$ca" -a ! -r "$ca" ] && readable=0
+ [ -n "$cap" -a ! -r "$cap" ] && readable=0
+
+ if [ $readable -eq 0 ]; then
+ wsrep_log_error \
+ "Both PEM file and CA file (or path) must be readable"
+ exit 22
+ fi
+
+ # If the openssl utility is not installed, then
+ # we will not do this certificate check:
+ get_openssl
+ if [ -z "$OPENSSL_BINARY" ]; then
+ wsrep_log_info "openssl utility not found"
+ return
+ fi
+
+ local not_match=0
+ local errmsg
+ errmsg=$("$OPENSSL_BINARY" verify -verbose \
+ ${ca:+ -CAfile} ${ca:+ "$ca"} \
+ ${cap:+ -CApath} ${cap:+ "$cap"} \
+ "$cert" 2>&1) || not_match=1
+
+ if [ $not_match -eq 1 ]; then
+ wsrep_log_info "run: \"$OPENSSL_BINARY\" verify -verbose${ca:+ -CAfile \"$ca\"}${cap:+ -CApath \"$cap\"} \"$cert\""
+ wsrep_log_info "output: $errmsg"
+ wsrep_log_error "******** FATAL ERROR ********************************************"
+ wsrep_log_error "* The certifcate and CA (certificate authority) do not match. *"
+ wsrep_log_error "* It does not appear that the certificate was issued by the CA. *"
+ wsrep_log_error "* Please check your certificate and CA files. *"
+ wsrep_log_error "*****************************************************************"
+ exit 22
+ fi
+}
+
+#
+# Verifies that the certificate matches the private key.
+# Doing this will save us having to wait for a timeout that would
+# otherwise occur.
+#
+# 1st param: path to the certificate.
+# 2nd param: path to the private key.
+#
+verify_cert_matches_key()
+{
+ local cert="$1"
+ local key="$2"
+
+ if [ ! -r "$key" -o ! -r "$cert" ]; then
+ wsrep_log_error "Both the certificate file and the key file" \
+ "must be readable"
+ exit 22
+ fi
+
+ # If the openssl utility is not installed, then
+ # we will not do this certificate check:
+ get_openssl
+ if [ -z "$OPENSSL_BINARY" ]; then
+ wsrep_log_info "openssl utility not found"
+ return
+ fi
+
+ # Generate the public key from the cert and the key.
+ # They should match (otherwise we can't create an SSL connection).
+ local pk1=$("$OPENSSL_BINARY" x509 -in "$cert" -pubkey -noout 2>/dev/null || :)
+ local pk2=$("$OPENSSL_BINARY" pkey -in "$key" -pubout 2>/dev/null || :)
+ if [ "$pk1" != "$pk2" ]; then
+ wsrep_log_error "******************* FATAL ERROR *****************"
+ wsrep_log_error "* The certificate and private key do not match. *"
+ wsrep_log_error "* Please check your certificate and key files. *"
+ wsrep_log_error "*************************************************"
+ exit 22
+ fi
+}
+
+#
+# Compares two version strings.
+# The first parameter is the version to be checked;
+# The second parameter is the minimum version required;
+# Returns 1 (failure) if $1 >= $2, 0 (success) otherwise.
+#
+check_for_version()
+{
+ local y1="${1#*.}"
+ [ "$y1" = "$1" ] && y1=""
+ local z1="${y1#*.}"
+ [ "$z1" = "$y1" ] && z1=""
+ local w1="${z1#*.}"
+ [ "$w1" = "$z1" ] && w1=""
+ local x1="${1%%.*}"
+ y1="${y1%%.*}"
+ z1="${z1%%.*}"
+ w1="${w1%%.*}"
+ [ -z "$y1" ] && y1=0
+ [ -z "$z1" ] && z1=0
+ [ -z "$w1" ] && w1=0
+ local y2="${2#*.}"
+ [ "$y2" = "$2" ] && y2=""
+ local z2="${y2#*.}"
+ [ "$z2" = "$y2" ] && z2=""
+ local w2="${z2#*.}"
+ [ "$w2" = "$z2" ] && w2=""
+ local x2="${2%%.*}"
+ y2="${y2%%.*}"
+ z2="${z2%%.*}"
+ w2="${w2%%.*}"
+ [ -z "$y2" ] && y2=0
+ [ -z "$z2" ] && z2=0
+ [ -z "$w2" ] && w2=0
+ [ $x1 -lt $x2 ] && return 1
+ [ $x1 -gt $x2 ] && return 0
+ [ $y1 -lt $y2 ] && return 1
+ [ $y1 -gt $y2 ] && return 0
+ [ $z1 -lt $z2 ] && return 1
+ [ $z1 -gt $z2 ] && return 0
+ [ $w1 -lt $w2 ] && return 1
+ return 0
+}
+
+#
+# Check whether process is still running.
+# The first parameter contains the name of the PID file.
+# The second parameter is the flag of the need to delete
+# the PID file.
+# If the second parameter is not zero and not empty,
+# then if the process terminates, the corresponding
+# PID file will be deleted.
+# This function also sets the CHECK_PID variable to zero
+# if the process has already exited, or writes the PID
+# of the process there if it is still running.
+#
+check_pid()
+{
+ local pid_file="$1"
+ if [ -r "$pid_file" ]; then
+ local pid=$(cat "$pid_file" 2>/dev/null || :)
+ if [ -n "$pid" ]; then
+ if [ $pid -gt 0 ]; then
+ if ps -p $pid >/dev/null 2>&1; then
+ CHECK_PID=$pid
+ return 0
+ fi
+ fi
+ fi
+ local remove=${2:-0}
+ if [ $remove -ne 0 ]; then
+ rm -f "$pid_file" || :
+ fi
+ fi
+ local config="${3:-}"
+ if [ -n "$config" -a -f "$config" ]; then
+ rm -f "$config" || :
+ fi
+ CHECK_PID=0
+ return 1
+}
+
+#
+# Checking that the process with the specified PID is still
+# running and killing it in this case by sending SIGTERM
+# (using the "kill" operation).
+# The first parameter contains PID of the process.
+# The second and third parameters (both optional) are the names
+# of the PID and the configuration files, which should be removed
+# after the process ends.
+# If the first parameter (PID of the process) is zero, then
+# the function immediately deletes the PID and the configuration
+# files (if specified), without any additional checks.
+#
+cleanup_pid()
+{
+ local pid=$1
+ local pid_file="${2:-}"
+ local config="${3:-}"
+
+ if [ $pid -gt 0 ]; then
+ if ps -p $pid >/dev/null 2>&1; then
+ if kill $pid >/dev/null 2>&1; then
+ sleep 0.5
+ local round=0
+ local force=0
+ while ps -p $pid >/dev/null 2>&1; do
+ sleep 1
+ round=$(( round+1 ))
+ if [ $round -eq 16 ]; then
+ if [ $force -eq 0 ]; then
+ round=8
+ force=1
+ kill -9 $pid >/dev/null 2>&1 || :
+ sleep 0.5
+ else
+ return 1
+ fi
+ fi
+ done
+ elif ps -p $pid >/dev/null 2>&1; then
+ wsrep_log_warning "Unable to kill PID=$pid ($pid_file)"
+ return 1
+ fi
+ fi
+ fi
+
+ [ -n "$pid_file" -a -f "$pid_file" ] && rm -f "$pid_file" || :
+ [ -n "$config" -a -f "$config" ] && rm -f "$config" || :
+
+ return 0
+}
+
+nproc=""
+
+get_proc()
+{
+ if [ -z "$nproc" ]; then
+ set +e
+ if [ "$OS" = 'Linux' ]; then
+ nproc=$(grep -cw -E '^processor' /proc/cpuinfo 2>/dev/null)
+ elif [ "$OS" = 'Darwin' -o "$OS" = 'FreeBSD' ]; then
+ nproc=$(sysctl -n hw.ncpu)
+ fi
+ set -e
+ if [ -z "$nproc" ] || [ $nproc -eq 0 ]; then
+ nproc=1
+ fi
+ fi
+}
+
+check_server_ssl_config()
+{
+ # backward-compatible behavior:
+ tcert=$(parse_cnf 'sst' 'tca')
+ tcap=$(parse_cnf 'sst' 'tcapath')
+ tpem=$(parse_cnf 'sst' 'tcert')
+ tkey=$(parse_cnf 'sst' 'tkey')
+ # reading new ssl configuration options:
+ local tcert2=$(parse_cnf "$encgroups" 'ssl-ca')
+ local tcap2=$(parse_cnf "$encgroups" 'ssl-capath')
+ local tpem2=$(parse_cnf "$encgroups" 'ssl-cert')
+ local tkey2=$(parse_cnf "$encgroups" 'ssl-key')
+ # if there are no old options, then we take new ones:
+ if [ -z "$tcert" -a -z "$tcap" -a -z "$tpem" -a -z "$tkey" ]; then
+ tcert="$tcert2"
+ tcap="$tcap2"
+ tpem="$tpem2"
+ tkey="$tkey2"
+ # checking for presence of the new-style SSL configuration:
+ elif [ -n "$tcert2" -o -n "$tcap2" -o -n "$tpem2" -o -n "$tkey2" ]; then
+ if [ "$tcert" != "$tcert2" -o \
+ "$tcap" != "$tcap2" -o \
+ "$tpem" != "$tpem2" -o \
+ "$tkey" != "$tkey2" ]
+ then
+ wsrep_log_info \
+ "new ssl configuration options (ssl-ca[path], ssl-cert" \
+ "and ssl-key) are ignored by SST due to presence" \
+ "of the tca[path], tcert and/or tkey in the [sst] section"
+ fi
+ fi
+ if [ -n "$tcert" ]; then
+ if [ "${tcert%/}" != "$tcert" -o -d "$tcert" ]; then
+ tcap="$tcert"
+ tcert=""
+ fi
+ fi
+}
+
+simple_cleanup()
+{
+ # Since this is invoked just after exit NNN
+ local estatus=$?
+ if [ $estatus -ne 0 ]; then
+ wsrep_log_error "Cleanup after exit with status: $estatus"
+ fi
+ if [ -n "${SST_PID:-}" ]; then
+ [ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD"
+ [ -f "$SST_PID" ] && rm -f "$SST_PID" || :
+ fi
+ exit $estatus
+}
+
+wsrep_log_info "$WSREP_METHOD $WSREP_TRANSFER_TYPE started on $WSREP_SST_OPT_ROLE"