diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh old mode 100644 new mode 100755 index d19a0dbfdd56f..c98b388a1e255 --- 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 de789dc172878..899f3eb4f3c2a 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 f32689a9e43a9..4f39835e15d46 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 ca9e9c30ae502..c93a8cbdba865 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -727,6 +727,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) { /* @@ -751,22 +794,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 @@ -786,58 +823,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) @@ -880,22 +879,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 @@ -931,13 +924,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--; @@ -966,58 +959,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) { @@ -1040,13 +995,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; }