summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Goryavsky <julius.goryavsky@mariadb.com>2021-05-14 12:51:36 +0200
committerJulius Goryavsky <julius.goryavsky@mariadb.com>2021-05-17 20:39:55 +0200
commit9e8e82cc11e82e5074448d2ecade3cd276621018 (patch)
treea3d817bf0b972854866d83cec038e10989d1565f
parent69feb040bfb73c5aece9cc815e33a91eb6a1f15f (diff)
downloadmariadb-git-9e8e82cc11e82e5074448d2ecade3cd276621018.tar.gz
MDEV-25669: SST scripts should check all server groups in config files
1) This commit implements reading all sections from configuration files while looking for the current value of any server variable, which were previously only read from the [mysqld.suffix] group and from [mysqld], but not from other groups such as [mariadb.suffix], [mariadb] or, for example, [server]. 2) This commit also fixes misrecognition of some parameters when parsing a command line containing a special marker for the end of the list of options ("--") or when short option names (such as "-s", "-a" and "-h arg") chained together (like a "-sah arg"). Such parameters can be passed to the SST script in the list of arguments after "--mysqld-args" if the server is started with a complex set of options - this was revealed during manual testing of changes to read configuration files. 3) The server-side preparation code for the "--mysqld-args" option list has also been simplified to make it easier to change in the future (if needed), and has been improved to properly handle the special backquote ("`") character in the argument values.
-rwxr-xr-x[-rw-r--r--]scripts/wsrep_sst_common.sh159
-rw-r--r--scripts/wsrep_sst_mariabackup.sh14
-rw-r--r--scripts/wsrep_sst_rsync.sh20
-rw-r--r--sql/wsrep_sst.cc199
4 files changed, 201 insertions, 191 deletions
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
index d19a0dbfdd5..c98b388a1e2 100644..100755
--- a/scripts/wsrep_sst_common.sh
+++ b/scripts/wsrep_sst_common.sh
@@ -240,44 +240,108 @@ case "$1" in
original_cmd=""
shift
while [ $# -gt 0 ]; do
- # check if the argument is the short option
- # (starting with "-" instead of "--"):
- if [ "${1#--}" = "$1" -a "${1#-}" != "$1" ]; then
- option="${1#-}"
- value=""
- # check that the option value follows the name,
- # without a space:
- if [ ${#option} -gt 1 ]; then
- # let's separate the first character as the option name,
- # and the subsequent characters consider its value:
- value="${1#-?}"
- option="${1%$value}"
- # check that the option name consists of one letter
- # and there are the following arguments:
- elif [ ${#option} -eq 1 -a $# -gt 1 ]; then
- # if the next argument does not start with a "-" character,
- # then this is the value of the current option:
- if [ "${2#-}" = "$2" ]; then
- value="$2"
+ 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
- fi
+ done
fi
- shift
- if [ "$option" = 'h' ]; then
- if [ -z "$WSREP_SST_OPT_DATA" ]; then
- MYSQLD_OPT_DATADIR="${value%/}"
- fi
- elif [ "$option" != 'u' -a \
- "$option" != 'P' ]; then
- if [ -z "$original_cmd" ]; then
- original_cmd="'-$option$value'"
- else
- original_cmd="$original_cmd '-$option$value'"
+ 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-1)
+ 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"
+ fi
+ fi
+ if [ $option == 'h' ]; then
+ if [ -z "$WSREP_SST_OPT_DATA" ]; then
+ MYSQLD_OPT_DATADIR="${value%/}"
+ fi
+ elif [ $option != 'u' -a \
+ $option != 'P' ]
+ then
+ if [ -z "$value" ]; then
+ slist="$slist$option"
+ elif [ -z "$slist" ]; then
+ slist="$option '$value'"
+ else
+ slist="$slist -$option '$value'"
+ 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 equal 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
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%%=*}"
+ # 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 \
@@ -340,22 +404,17 @@ case "$1" in
;;
esac
if [ $skip_mysqld_arg -eq 0 ]; then
- if [ -z "$original_cmd" ]; then
- original_cmd="'$1'"
- else
- original_cmd="$original_cmd '$1'"
- fi
+ original_cmd="$original_cmd '$1'"
fi
- fi
- shift
+ fi
+ shift
done
- WSREP_SST_OPT_MYSQLD="$original_cmd"
+ WSREP_SST_OPT_MYSQLD="${original_cmd# *}"
break
;;
- *) # must be command
- # usage
- # exit 1
- ;;
+ *) # Must be command usage
+ # exit 1
+ ;;
esac
shift
done
@@ -601,9 +660,9 @@ parse_cnf()
# of the groups list (as if it were a prefix):
groups="${groups#$group}"
groups="${groups#\|}"
- # if the group name is the same as the "[--]mysqld", then
- # try to use it together with the group suffix:
- if [ "${group#--}" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
+ # 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 "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
if [ -n "$reval" ]; then
break
@@ -616,7 +675,7 @@ parse_cnf()
fi
done
- # use default if we haven't found a value:
+ # Use default if we haven't found a value:
if [ -z "$reval" ]; then
[ -n "${3:-}" ] && reval="$3"
fi
@@ -648,9 +707,9 @@ in_config()
# of the groups list (as if it were a prefix):
groups="${groups#$group}"
groups="${groups#\|}"
- # if the group name is the same as the "[--]mysqld", then
- # try to use it together with the group suffix:
- if [ "${group#--}" = 'mysqld' -a -n "$WSREP_SST_OPT_SUFFIX_VALUE" ]; then
+ # 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 "mysqld$WSREP_SST_OPT_SUFFIX_VALUE" | awk "$pattern")
if [ $found -ne 0 ]; then
break
diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh
index de789dc1728..899f3eb4f3c 100644
--- a/scripts/wsrep_sst_mariabackup.sh
+++ b/scripts/wsrep_sst_mariabackup.sh
@@ -404,7 +404,6 @@ read_cnf()
# avoid CA verification if not set explicitly:
# nodes may happen to have different CA if self-generated
# zeroing up tcert does the trick
- local mode=$(parse_cnf 'sst' 'ssl-mode')
[ "${tmode#VERIFY}" != "$tmode" ] || tcert=""
fi
fi
@@ -421,8 +420,9 @@ read_cnf()
sockopt=$(parse_cnf sst sockopt "")
progress=$(parse_cnf sst progress "")
ttime=$(parse_cnf sst time 0)
- cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$')
- [ $OS = 'FreeBSD' ] && cpat=$(parse_cnf sst cpat '.*galera\.cache$|.*sst_in_progress$|.*\.sst$|.*gvwstate\.dat$|.*grastate\.dat$|.*\.err$|.*\.log$|.*RPM_UPGRADE_MARKER$|.*RPM_UPGRADE_HISTORY$')
+ cpat='.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$'
+ [ "$OS" = 'FreeBSD' ] && cpat=$(echo "$cpat" | sed 's/\\|/|/g')
+ cpat=$(parse_cnf sst cpat "$cpat")
scomp=$(parse_cnf sst compressor "")
sdecomp=$(parse_cnf sst decompressor "")
@@ -445,9 +445,7 @@ read_cnf()
fi
if [ $ssyslog -ne -1 ]; then
- if $MY_PRINT_DEFAULTS mysqld_safe | grep -q -- "--syslog"; then
- ssyslog=1
- fi
+ ssyslog=$(in_config 'mysqld_safe' 'syslog')
fi
}
@@ -771,7 +769,7 @@ monitor_process()
while true ; do
if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null; then
- wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly."
+ wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly."
exit 32
fi
if ! ps -p "$sst_stream_pid" &>/dev/null; then
@@ -1139,7 +1137,7 @@ then
if ! ps -p "$WSREP_SST_OPT_PARENT" &>/dev/null
then
- wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly."
+ wsrep_log_error "Parent mysqld process (PID: $WSREP_SST_OPT_PARENT) terminated unexpectedly."
exit 32
fi
diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh
index f32689a9e43..4f39835e15d 100644
--- a/scripts/wsrep_sst_rsync.sh
+++ b/scripts/wsrep_sst_rsync.sh
@@ -218,23 +218,21 @@ SSTKEY=$(parse_cnf 'sst' 'tkey')
SSTCERT=$(parse_cnf 'sst' 'tcert')
SSTCA=$(parse_cnf 'sst' 'tca')
+SST_SECTIONS="--mysqld|sst"
+
check_server_ssl_config()
{
- local section="$1"
- SSTKEY=$(parse_cnf "$section" 'ssl-key')
- SSTCERT=$(parse_cnf "$section" 'ssl-cert')
- SSTCA=$(parse_cnf "$section" 'ssl-ca')
+ SSTKEY=$(parse_cnf "$SST_SECTIONS" 'ssl-key')
+ SSTCERT=$(parse_cnf "$SST_SECTIONS" 'ssl-cert')
+ SSTCA=$(parse_cnf "$SST_SECTIONS" 'ssl-ca')
}
-SSLMODE=$(parse_cnf 'sst' 'ssl-mode' | tr [:lower:] [:upper:])
+SSLMODE=$(parse_cnf "$SST_SECTIONS" 'ssl-mode' | tr [:lower:] [:upper:])
+# no old-style SSL config in [sst], check for new one:
if [ -z "$SSTKEY" -a -z "$SSTCERT" -a -z "$SSTCA" ]
then
- # no old-style SSL config in [sst], check for new one
- check_server_ssl_config 'sst'
- if [ -z "$SSTKEY" -a -z "$SSTCERT" -a -z "$SSTCA" ]; then
- check_server_ssl_config '--mysqld'
- fi
+ check_server_ssl_config
fi
if [ -z "$SSLMODE" ]; then
@@ -602,7 +600,7 @@ EOF
if ! ps -p $MYSQLD_PID >/dev/null
then
wsrep_log_error \
- "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly."
+ "Parent mysqld process (PID: $MYSQLD_PID) terminated unexpectedly."
kill -- -$MYSQLD_PID
sleep 1
exit 32
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index e8555bcfbe3..f6bc0e7c63f 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -729,6 +729,49 @@ static int sst_append_env_var(wsp::env& env,
return -env.error();
}
+#ifdef __WIN__
+/*
+ Space, single quote, ampersand, backquote, I/O redirection
+ characters, caret, all brackets, plus, exclamation and comma
+ characters require text to be enclosed in double quotes:
+*/
+#define IS_SPECIAL(c) \
+ (isspace(c) || c == '\'' || c == '&' || c == '`' || c == '|' || \
+ c == '>' || c == '<' || c == ';' || c == '^' || \
+ c == '[' || c == ']' || c == '{' || c == '}' || \
+ c == '(' || c == ')' || c == '+' || c == '!' || \
+ c == ',')
+/*
+ Inside values, equals character are interpreted as special
+ character and requires quotation:
+*/
+#define IS_SPECIAL_V(c) (IS_SPECIAL(c) || c == '=')
+/*
+ Double quotation mark and percent characters require escaping:
+*/
+#define IS_REQ_ESCAPING(c) (c == '""' || c == '%')
+#else
+/*
+ Space, single quote, ampersand, backquote, and I/O redirection
+ characters require text to be enclosed in double quotes. The
+ semicolon is used to separate shell commands, so it must be
+ enclosed in double quotes as well:
+*/
+#define IS_SPECIAL(c) \
+ (isspace(c) || c == '\'' || c == '&' || c == '`' || c == '|' || \
+ c == '>' || c == '<' || c == ';')
+/*
+ Inside values, characters are interpreted as in parameter names:
+*/
+#define IS_SPECIAL_V(c) IS_SPECIAL(c)
+/*
+ Double quotation mark and backslash characters require
+ backslash prefixing, the dollar symbol is used to substitute
+ a variable value, therefore it also requires escaping:
+*/
+#define IS_REQ_ESCAPING(c) (c == '"' || c == '\\' || c == '$')
+#endif
+
static size_t estimate_cmd_len (bool* extra_args)
{
/*
@@ -753,22 +796,16 @@ static size_t estimate_cmd_len (bool* extra_args)
char c;
while ((c = *arg++) != 0)
{
- /*
- Space, single quote, ampersand, and I/O redirection characters
- require text to be enclosed in double quotes:
- */
- if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
-#ifdef __WIN__
- c == '>' || c == '<')
-#else
- /*
- The semicolon is used to separate shell commands, so it must be
- enclosed in double quotes as well:
- */
- c == '>' || c == '<' || c == ';')
-#endif
+ if (IS_SPECIAL(c))
+ {
+ quotation= true;
+ }
+ else if (IS_REQ_ESCAPING(c))
{
+ cmd_len++;
+#ifdef __WIN__
quotation= true;
+#endif
}
/*
If the equals symbol is encountered, then we need to separately
@@ -788,58 +825,20 @@ static size_t estimate_cmd_len (bool* extra_args)
}
while ((c = *arg++) != 0)
{
- /*
- Space, single quote, ampersand, and I/O redirection characters
- require text to be enclosed in double quotes:
- */
- if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
-#ifdef __WIN__
- c == '>' || c == '<')
-#else
- /*
- The semicolon is used to separate shell commands, so it must be
- enclosed in double quotes as well:
- */
- c == '>' || c == '<' || c == ';')
-#endif
+ if (IS_SPECIAL_V(c))
{
quotation= true;
}
- /*
- Double quotation mark or backslash symbol requires backslash
- prefixing:
- */
-#ifdef __WIN__
- else if (c == '"' || c == '\\')
-#else
- /*
- The dollar symbol is used to substitute a variable, therefore
- it also requires escaping:
- */
- else if (c == '"' || c == '\\' || c == '$')
-#endif
+ else if (IS_REQ_ESCAPING(c))
{
cmd_len++;
+#ifdef __WIN__
+ quotation= true;
+#endif
}
}
break;
}
- /*
- Double quotation mark or backslash symbol requires backslash
- prefixing:
- */
-#ifdef __WIN__
- else if (c == '"' || c == '\\')
-#else
- /*
- The dollar symbol is used to substitute a variable, therefore
- it also requires escaping:
- */
- else if (c == '"' || c == '\\' || c == '$')
-#endif
- {
- cmd_len++;
- }
}
/* Perhaps we need to quote the entire argument or its right part: */
if (quotation)
@@ -882,22 +881,16 @@ static void copy_orig_argv (char* cmd_str)
char c;
while ((c = *arg_scan++) != 0)
{
- /*
- Space, single quote, ampersand, and I/O redirection characters
- require text to be enclosed in double quotes:
- */
- if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
-#ifdef __WIN__
- c == '>' || c == '<')
-#else
- /*
- The semicolon is used to separate shell commands, so it must be
- enclosed in double quotes as well:
- */
- c == '>' || c == '<' || c == ';')
-#endif
+ if (IS_SPECIAL(c))
+ {
+ quotation= true;
+ }
+ else if (IS_REQ_ESCAPING(c))
{
+ plain= false;
+#ifdef __WIN__
quotation= true;
+#endif
}
/*
If the equals symbol is encountered, then we need to separately
@@ -933,13 +926,13 @@ static void copy_orig_argv (char* cmd_str)
while (m)
{
c = *arg++;
+ if (IS_REQ_ESCAPING(c))
+ {
#ifdef __WIN__
- if (c == '"' || c == '\\')
+ *cmd_str++ = c;
#else
- if (c == '"' || c == '\\' || c == '$')
-#endif
- {
*cmd_str++ = '\\';
+#endif
}
*cmd_str++ = c;
m--;
@@ -968,58 +961,20 @@ static void copy_orig_argv (char* cmd_str)
/* Let's deal with the left side of the expression: */
while ((c = *arg_scan++) != 0)
{
- /*
- Space, single quote, ampersand, and I/O redirection characters
- require text to be enclosed in double quotes:
- */
- if (isspace(c) || c == '\'' || c == '&' || c == '|' ||
-#ifdef __WIN__
- c == '>' || c == '<')
-#else
- /*
- The semicolon is used to separate shell commands, so it must be
- enclosed in double quotes as well:
- */
- c == '>' || c == '<' || c == ';')
-#endif
+ if (IS_SPECIAL_V(c))
{
quotation= true;
}
- /*
- Double quotation mark or backslash symbol requires backslash
- prefixing:
- */
-#ifdef __WIN__
- else if (c == '"' || c == '\\')
-#else
- /*
- The dollar symbol is used to substitute a variable, therefore
- it also requires escaping:
- */
- else if (c == '"' || c == '\\' || c == '$')
-#endif
+ else if (IS_REQ_ESCAPING(c))
{
plain= false;
+#ifdef __WIN__
+ quotation= true;
+#endif
}
}
break;
}
- /*
- Double quotation mark or backslash symbol requires backslash
- prefixing:
- */
-#ifdef __WIN__
- else if (c == '"' || c == '\\')
-#else
- /*
- The dollar symbol is used to substitute a variable, therefore
- it also requires escaping:
- */
- else if (c == '"' || c == '\\' || c == '$')
-#endif
- {
- plain= false;
- }
}
if (n)
{
@@ -1042,13 +997,13 @@ static void copy_orig_argv (char* cmd_str)
{
while ((c = *arg++) != 0)
{
+ if (IS_REQ_ESCAPING(c))
+ {
#ifdef __WIN__
- if (c == '"' || c == '\\')
+ *cmd_str++ = c;
#else
- if (c == '"' || c == '\\' || c == '$')
-#endif
- {
*cmd_str++ = '\\';
+#endif
}
*cmd_str++ = c;
}