Refs codership/mysql-wsrep#141: this commit
1. Passes wsrep_sst_auth_value to SST scripts via WSREP_SST_OPT_AUTH envronmental variable, so it never appears on the command line 2. In mysqldump and xtrabackup* SST scripts which rely on MySQL authentication, instead of passing password on the command line, SST script sets MYSQL_PWD environment variable, so that password also never appears on the mysqldump/innobackupex command line.
This commit is contained in:
parent
4f4f3a5e32
commit
d78110e7fa
@ -1,4 +1,4 @@
|
|||||||
# Copyright (C) 2012-2014 Codership Oy
|
# Copyright (C) 2012-2015 Codership Oy
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -20,7 +20,9 @@ set -u
|
|||||||
|
|
||||||
WSREP_SST_OPT_BYPASS=0
|
WSREP_SST_OPT_BYPASS=0
|
||||||
WSREP_SST_OPT_DATA=""
|
WSREP_SST_OPT_DATA=""
|
||||||
WSREP_SST_OPT_AUTH=""
|
WSREP_SST_OPT_AUTH=${WSREP_SST_OPT_AUTH:-}
|
||||||
|
WSREP_SST_OPT_USER=${WSREP_SST_OPT_USER:-}
|
||||||
|
WSREP_SST_OPT_PSWD=${WSREP_SST_OPT_PSWD:-}
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -28,10 +30,6 @@ case "$1" in
|
|||||||
readonly WSREP_SST_OPT_ADDR="$2"
|
readonly WSREP_SST_OPT_ADDR="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
'--auth')
|
|
||||||
WSREP_SST_OPT_AUTH="$2"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--bypass')
|
'--bypass')
|
||||||
WSREP_SST_OPT_BYPASS=1
|
WSREP_SST_OPT_BYPASS=1
|
||||||
;;
|
;;
|
||||||
@ -114,12 +112,30 @@ else
|
|||||||
MY_PRINT_DEFAULTS=$(which my_print_defaults)
|
MY_PRINT_DEFAULTS=$(which my_print_defaults)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
wsrep_auth_not_set()
|
||||||
|
{
|
||||||
|
[ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ]
|
||||||
|
}
|
||||||
|
|
||||||
# For Bug:1200727
|
# For Bug:1200727
|
||||||
if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth";then
|
if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth"
|
||||||
if [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ];then
|
then
|
||||||
WSREP_SST_OPT_AUTH=$(my_print_defaults -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2)
|
if wsrep_auth_not_set
|
||||||
|
then
|
||||||
|
WSREP_SST_OPT_AUTH=$(MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -- "--wsrep_sst_auth" | cut -d= -f2)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
readonly WSREP_SST_OPT_AUTH
|
||||||
|
|
||||||
|
# Splitting AUTH into potential user:password pair
|
||||||
|
if ! wsrep_auth_not_set
|
||||||
|
then
|
||||||
|
readonly AUTH_VEC=(${WSREP_SST_OPT_AUTH//:/ })
|
||||||
|
[ -n "${AUTH_VEC[0]}" ] && WSREP_SST_OPT_USER="${AUTH_VEC[0]}"
|
||||||
|
[ -n "${AUTH_VEC[1]}" ] && WSREP_SST_OPT_PSWD="${AUTH_VEC[1]}"
|
||||||
|
fi
|
||||||
|
readonly WSREP_SST_OPT_USER
|
||||||
|
readonly WSREP_SST_OPT_PSWD
|
||||||
|
|
||||||
if [ -n "${WSREP_SST_OPT_DATA:-}" ]
|
if [ -n "${WSREP_SST_OPT_DATA:-}" ]
|
||||||
then
|
then
|
||||||
@ -128,7 +144,6 @@ else
|
|||||||
SST_PROGRESS_FILE=""
|
SST_PROGRESS_FILE=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
wsrep_log()
|
wsrep_log()
|
||||||
{
|
{
|
||||||
# echo everything to stderr so that it gets into common error log
|
# echo everything to stderr so that it gets into common error log
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash -e
|
#!/bin/bash -ue
|
||||||
# Copyright (C) 2009 Codership Oy
|
# Copyright (C) 2009-2015 Codership Oy
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -38,7 +38,6 @@ local_ip()
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if test -z "$WSREP_SST_OPT_USER"; then wsrep_log_error "USER cannot be nil"; exit $EINVAL; fi
|
|
||||||
if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi
|
if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi
|
||||||
if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi
|
if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi
|
||||||
if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi
|
if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi
|
||||||
@ -54,7 +53,7 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check client version
|
# Check client version
|
||||||
CLIENT_MINOR=$(mysql --version | cut -d ' ' -f 6 | cut -d '.' -f 2)
|
CLIENT_MINOR=$($MYSQL_CLIENT --version | cut -d ' ' -f 6 | cut -d '.' -f 2)
|
||||||
if [ $CLIENT_MINOR -lt "5" ]
|
if [ $CLIENT_MINOR -lt "5" ]
|
||||||
then
|
then
|
||||||
$MYSQL_CLIENT --version >&2
|
$MYSQL_CLIENT --version >&2
|
||||||
@ -62,13 +61,18 @@ then
|
|||||||
exit $EINVAL
|
exit $EINVAL
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For Bug:1293798
|
[ -n "$WSREP_SST_OPT_USER" ] && AUTH="-u$WSREP_SST_OPT_USER" || AUTH=
|
||||||
if [ -z "$WSREP_SST_OPT_PSWD" -a -n "$WSREP_SST_OPT_AUTH" ]; then
|
|
||||||
WSREP_SST_OPT_USER=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f1)
|
# Refs https://github.com/codership/mysql-wsrep/issues/141
|
||||||
WSREP_SST_OPT_PSWD=$(echo $WSREP_SST_OPT_AUTH | cut -d: -f2)
|
# Passing password in MYSQL_PWD environment variable is considered
|
||||||
fi
|
# "extremely insecure" by MySQL Guidelines for Password Security
|
||||||
AUTH="-u$WSREP_SST_OPT_USER"
|
# (https://dev.mysql.com/doc/refman/5.6/en/password-security-user.html)
|
||||||
if test -n "$WSREP_SST_OPT_PSWD"; then AUTH="$AUTH -p$WSREP_SST_OPT_PSWD"; fi
|
# that is even less secure than passing it on a command line! It is doubtful:
|
||||||
|
# the whole command line is easily observable by any unprivileged user via ps,
|
||||||
|
# whereas (at least on Linux) unprivileged user can't see process environment
|
||||||
|
# that he does not own. So while it may be not secure in the NSA sense of the
|
||||||
|
# word, it is arguably more secure than passing password on the command line.
|
||||||
|
[ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
|
||||||
|
|
||||||
STOP_WSREP="SET wsrep_on=OFF;"
|
STOP_WSREP="SET wsrep_on=OFF;"
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ wsrep_check_programs rsync
|
|||||||
|
|
||||||
cleanup_joiner()
|
cleanup_joiner()
|
||||||
{
|
{
|
||||||
wsrep_log_info "Joiner cleanup."
|
|
||||||
local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0)
|
local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0)
|
||||||
|
wsrep_log_info "Joiner cleanup. rsync PID: $PID"
|
||||||
[ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \
|
[ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \
|
||||||
|| :
|
|| :
|
||||||
rm -rf "$RSYNC_CONF"
|
rm -rf "$RSYNC_CONF"
|
||||||
|
@ -77,7 +77,6 @@ pcmd="pv $pvopts"
|
|||||||
declare -a RC
|
declare -a RC
|
||||||
|
|
||||||
INNOBACKUPEX_BIN=innobackupex
|
INNOBACKUPEX_BIN=innobackupex
|
||||||
readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ })
|
|
||||||
DATA="${WSREP_SST_OPT_DATA}"
|
DATA="${WSREP_SST_OPT_DATA}"
|
||||||
INFO_FILE="xtrabackup_galera_info"
|
INFO_FILE="xtrabackup_galera_info"
|
||||||
IST_FILE="xtrabackup_ist"
|
IST_FILE="xtrabackup_ist"
|
||||||
@ -576,13 +575,14 @@ then
|
|||||||
itmpdir=$(mktemp -d)
|
itmpdir=$(mktemp -d)
|
||||||
wsrep_log_info "Using $itmpdir as innobackupex temporary directory"
|
wsrep_log_info "Using $itmpdir as innobackupex temporary directory"
|
||||||
|
|
||||||
if [ "${AUTH[0]}" != "(null)" ]; then
|
if [ "$WSREP_SST_OPT_USER" != "(null)" ]; then
|
||||||
INNOEXTRA+=" --user=${AUTH[0]}"
|
INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#AUTH[*]} -eq 2 ]; then
|
if [ -n "$WSREP_SST_OPT_PSWD" ]; then
|
||||||
INNOEXTRA+=" --password=${AUTH[1]}"
|
# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
|
||||||
elif [ "${AUTH[0]}" != "(null)" ]; then
|
export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
|
||||||
|
else
|
||||||
# Empty password, used for testing, debugging etc.
|
# Empty password, used for testing, debugging etc.
|
||||||
INNOEXTRA+=" --password="
|
INNOEXTRA+=" --password="
|
||||||
fi
|
fi
|
||||||
|
@ -61,7 +61,6 @@ pcmd="pv $pvopts"
|
|||||||
declare -a RC
|
declare -a RC
|
||||||
|
|
||||||
INNOBACKUPEX_BIN=innobackupex
|
INNOBACKUPEX_BIN=innobackupex
|
||||||
readonly AUTH=(${WSREP_SST_OPT_AUTH//:/ })
|
|
||||||
DATA="${WSREP_SST_OPT_DATA}"
|
DATA="${WSREP_SST_OPT_DATA}"
|
||||||
INFO_FILE="xtrabackup_galera_info"
|
INFO_FILE="xtrabackup_galera_info"
|
||||||
IST_FILE="xtrabackup_ist"
|
IST_FILE="xtrabackup_ist"
|
||||||
@ -435,13 +434,14 @@ then
|
|||||||
then
|
then
|
||||||
TMPDIR="${TMPDIR:-/tmp}"
|
TMPDIR="${TMPDIR:-/tmp}"
|
||||||
|
|
||||||
if [ "${AUTH[0]}" != "(null)" ]; then
|
if [ "$WSREP_SST_OPT_USER" != "(null)" ]; then
|
||||||
INNOEXTRA+=" --user=${AUTH[0]}"
|
INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#AUTH[*]} -eq 2 ]; then
|
if [ -n "$WSREP_SST_OPT_PSWD" ]; then
|
||||||
INNOEXTRA+=" --password=${AUTH[1]}"
|
# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
|
||||||
elif [ "${AUTH[0]}" != "(null)" ]; then
|
export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
|
||||||
|
else
|
||||||
# Empty password, used for testing, debugging etc.
|
# Empty password, used for testing, debugging etc.
|
||||||
INNOEXTRA+=" --password="
|
INNOEXTRA+=" --password="
|
||||||
fi
|
fi
|
||||||
|
@ -97,7 +97,7 @@ void wsrep_notify_status (wsrep_member_status_t status,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wsp::process p(cmd_ptr, "r");
|
wsp::process p(cmd_ptr, "r", NULL);
|
||||||
|
|
||||||
p.wait();
|
p.wait();
|
||||||
int err = p.error();
|
int err = p.error();
|
||||||
|
166
sql/wsrep_sst.cc
166
sql/wsrep_sst.cc
@ -270,12 +270,14 @@ void wsrep_sst_continue ()
|
|||||||
struct sst_thread_arg
|
struct sst_thread_arg
|
||||||
{
|
{
|
||||||
const char* cmd;
|
const char* cmd;
|
||||||
int err;
|
char** env;
|
||||||
char* ret_str;
|
char* ret_str;
|
||||||
|
int err;
|
||||||
mysql_mutex_t lock;
|
mysql_mutex_t lock;
|
||||||
mysql_cond_t cond;
|
mysql_cond_t cond;
|
||||||
|
|
||||||
sst_thread_arg (const char* c) : cmd(c), err(-1), ret_str(0)
|
sst_thread_arg (const char* c, char** e)
|
||||||
|
: cmd(c), env(e), ret_str(0), err(-1)
|
||||||
{
|
{
|
||||||
mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST);
|
mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST);
|
||||||
mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL);
|
mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL);
|
||||||
@ -333,7 +335,7 @@ static void* sst_joiner_thread (void* a)
|
|||||||
|
|
||||||
WSREP_INFO("Running: '%s'", arg->cmd);
|
WSREP_INFO("Running: '%s'", arg->cmd);
|
||||||
|
|
||||||
wsp::process proc (arg->cmd, "r");
|
wsp::process proc (arg->cmd, "r", arg->env);
|
||||||
|
|
||||||
if (proc.pipe() && !proc.error())
|
if (proc.pipe() && !proc.error())
|
||||||
{
|
{
|
||||||
@ -407,23 +409,54 @@ static void* sst_joiner_thread (void* a)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH"
|
||||||
|
|
||||||
|
static int sst_append_auth_env(wsp::env& env, const char* sst_auth)
|
||||||
|
{
|
||||||
|
int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */
|
||||||
|
+ (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */;
|
||||||
|
|
||||||
|
wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return
|
||||||
|
if (!sst_auth_str()) return -ENOMEM;
|
||||||
|
|
||||||
|
int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s",
|
||||||
|
WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : "");
|
||||||
|
|
||||||
|
if (ret < 0 || ret >= sst_auth_size)
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret);
|
||||||
|
return (ret < 0 ? ret : -EMSGSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
env.append(sst_auth_str());
|
||||||
|
return -env.error();
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t sst_prepare_other (const char* method,
|
static ssize_t sst_prepare_other (const char* method,
|
||||||
|
const char* sst_auth,
|
||||||
const char* addr_in,
|
const char* addr_in,
|
||||||
const char** addr_out)
|
const char** addr_out)
|
||||||
{
|
{
|
||||||
char cmd_str[1024];
|
int const cmd_len= 4096;
|
||||||
const char* sst_dir= mysql_real_data_home;
|
wsp::string cmd_str(cmd_len);
|
||||||
|
|
||||||
int ret= snprintf (cmd_str, sizeof(cmd_str),
|
if (!cmd_str())
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes",
|
||||||
|
cmd_len);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret= snprintf (cmd_str(), cmd_len,
|
||||||
"wsrep_sst_%s "
|
"wsrep_sst_%s "
|
||||||
WSREP_SST_OPT_ROLE" 'joiner' "
|
WSREP_SST_OPT_ROLE" 'joiner' "
|
||||||
WSREP_SST_OPT_ADDR" '%s' "
|
WSREP_SST_OPT_ADDR" '%s' "
|
||||||
WSREP_SST_OPT_AUTH" '%s' "
|
|
||||||
WSREP_SST_OPT_DATA" '%s' "
|
WSREP_SST_OPT_DATA" '%s' "
|
||||||
WSREP_SST_OPT_CONF" '%s' "
|
WSREP_SST_OPT_CONF" '%s' "
|
||||||
WSREP_SST_OPT_PARENT" '%d'",
|
WSREP_SST_OPT_PARENT" '%d'",
|
||||||
method, addr_in, (sst_auth_real) ? sst_auth_real : "",
|
method, addr_in,
|
||||||
sst_dir, wsrep_defaults_file, (int)getpid());
|
mysql_real_data_home,
|
||||||
|
wsrep_defaults_file, (int)getpid());
|
||||||
|
|
||||||
if (ret < 0 || ret >= (int)sizeof(cmd_str))
|
if (ret < 0 || ret >= (int)sizeof(cmd_str))
|
||||||
{
|
{
|
||||||
@ -431,8 +464,21 @@ static ssize_t sst_prepare_other (const char* method,
|
|||||||
return (ret < 0 ? ret : -EMSGSIZE);
|
return (ret < 0 ? ret : -EMSGSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wsp::env env(NULL);
|
||||||
|
if (env.error())
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error());
|
||||||
|
return -env.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret= sst_append_auth_env(env, sst_auth)))
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_t tmp;
|
pthread_t tmp;
|
||||||
sst_thread_arg arg(cmd_str);
|
sst_thread_arg arg(cmd_str(), env());
|
||||||
mysql_mutex_lock (&arg.lock);
|
mysql_mutex_lock (&arg.lock);
|
||||||
ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
|
ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -582,7 +628,8 @@ ssize_t wsrep_sst_prepare (void** msg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_len = sst_prepare_other (wsrep_sst_method, addr_in, &addr_out);
|
addr_len = sst_prepare_other (wsrep_sst_method, sst_auth_real,
|
||||||
|
addr_in, &addr_out);
|
||||||
if (addr_len < 0)
|
if (addr_len < 0)
|
||||||
{
|
{
|
||||||
WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
|
WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
|
||||||
@ -615,13 +662,13 @@ ssize_t wsrep_sst_prepare (void** msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// helper method for donors
|
// helper method for donors
|
||||||
static int sst_run_shell (const char* cmd_str, int max_tries)
|
static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
for (int tries=1; tries <= max_tries; tries++)
|
for (int tries=1; tries <= max_tries; tries++)
|
||||||
{
|
{
|
||||||
wsp::process proc (cmd_str, "r");
|
wsp::process proc (cmd_str, "r", env);
|
||||||
|
|
||||||
if (NULL != proc.pipe())
|
if (NULL != proc.pipe())
|
||||||
{
|
{
|
||||||
@ -651,17 +698,12 @@ static void sst_reject_queries(my_bool close_conn)
|
|||||||
if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
|
if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sst_mysqldump_check_addr (const char* user, const char* pswd,
|
|
||||||
const char* host, const char* port)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sst_donate_mysqldump (const char* addr,
|
static int sst_donate_mysqldump (const char* addr,
|
||||||
const wsrep_uuid_t* uuid,
|
const wsrep_uuid_t* uuid,
|
||||||
const char* uuid_str,
|
const char* uuid_str,
|
||||||
wsrep_seqno_t seqno,
|
wsrep_seqno_t seqno,
|
||||||
bool bypass)
|
bool bypass,
|
||||||
|
char** env) // carries auth info
|
||||||
{
|
{
|
||||||
size_t host_len;
|
size_t host_len;
|
||||||
const char* port = strchr (addr, ':');
|
const char* port = strchr (addr, ':');
|
||||||
@ -682,37 +724,20 @@ static int sst_donate_mysqldump (const char* addr,
|
|||||||
strncpy (host, addr, host_len - 1);
|
strncpy (host, addr, host_len - 1);
|
||||||
host[host_len - 1] = '\0';
|
host[host_len - 1] = '\0';
|
||||||
|
|
||||||
const char* auth = sst_auth_real;
|
int const cmd_len= 4096;
|
||||||
const char* pswd = (auth) ? strchr (auth, ':') : NULL;
|
wsp::string cmd_str(cmd_len);
|
||||||
size_t user_len;
|
|
||||||
|
|
||||||
if (pswd)
|
if (!cmd_str())
|
||||||
{
|
{
|
||||||
pswd += 1;
|
WSREP_ERROR("sst_donate_mysqldump(): "
|
||||||
user_len = pswd - auth;
|
"could not allocate cmd buffer of %d bytes", cmd_len);
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
pswd = "";
|
|
||||||
user_len = (auth) ? strlen (auth) + 1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *user= (char *) alloca(user_len);
|
|
||||||
|
|
||||||
strncpy (user, (auth) ? auth : "", user_len - 1);
|
|
||||||
user[user_len - 1] = '\0';
|
|
||||||
|
|
||||||
int ret = sst_mysqldump_check_addr (user, pswd, host, port);
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
char cmd_str[1024];
|
|
||||||
|
|
||||||
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
|
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
|
||||||
|
|
||||||
snprintf (cmd_str, sizeof(cmd_str),
|
int ret= snprintf (cmd_str(), cmd_len,
|
||||||
"wsrep_sst_mysqldump "
|
"wsrep_sst_mysqldump "
|
||||||
WSREP_SST_OPT_USER" '%s' "
|
|
||||||
WSREP_SST_OPT_PSWD" '%s' "
|
|
||||||
WSREP_SST_OPT_HOST" '%s' "
|
WSREP_SST_OPT_HOST" '%s' "
|
||||||
WSREP_SST_OPT_PORT" '%s' "
|
WSREP_SST_OPT_PORT" '%s' "
|
||||||
WSREP_SST_OPT_LPORT" '%u' "
|
WSREP_SST_OPT_LPORT" '%u' "
|
||||||
@ -721,15 +746,20 @@ static int sst_donate_mysqldump (const char* addr,
|
|||||||
WSREP_SST_OPT_CONF" '%s' "
|
WSREP_SST_OPT_CONF" '%s' "
|
||||||
WSREP_SST_OPT_GTID" '%s:%lld'"
|
WSREP_SST_OPT_GTID" '%s:%lld'"
|
||||||
"%s",
|
"%s",
|
||||||
user, pswd, host, port, mysqld_port, mysqld_unix_port,
|
host, port, mysqld_port, mysqld_unix_port,
|
||||||
mysql_real_data_home, wsrep_defaults_file, uuid_str,
|
mysql_real_data_home, wsrep_defaults_file, uuid_str,
|
||||||
(long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : "");
|
(long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : "");
|
||||||
|
|
||||||
WSREP_DEBUG("Running: '%s'", cmd_str);
|
if (ret < 0 || ret >= cmd_len)
|
||||||
|
{
|
||||||
ret= sst_run_shell (cmd_str, 3);
|
WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret);
|
||||||
|
return (ret < 0 ? ret : -EMSGSIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WSREP_DEBUG("Running: '%s'", cmd_str());
|
||||||
|
|
||||||
|
ret= sst_run_shell (cmd_str(), env, 3);
|
||||||
|
|
||||||
wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
|
wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
|
||||||
|
|
||||||
wsrep->sst_sent (wsrep, &state_id, ret);
|
wsrep->sst_sent (wsrep, &state_id, ret);
|
||||||
@ -883,7 +913,7 @@ static void* sst_donor_thread (void* a)
|
|||||||
|
|
||||||
wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can
|
wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can
|
||||||
// operate with wsrep_ready == OFF
|
// operate with wsrep_ready == OFF
|
||||||
wsp::process proc(arg->cmd, "r");
|
wsp::process proc(arg->cmd, "r", arg->env);
|
||||||
|
|
||||||
err= proc.error();
|
err= proc.error();
|
||||||
|
|
||||||
@ -968,21 +998,29 @@ static int sst_donate_other (const char* method,
|
|||||||
const char* addr,
|
const char* addr,
|
||||||
const char* uuid,
|
const char* uuid,
|
||||||
wsrep_seqno_t seqno,
|
wsrep_seqno_t seqno,
|
||||||
bool bypass)
|
bool bypass,
|
||||||
|
char** env) // carries auth info
|
||||||
{
|
{
|
||||||
char cmd_str[4096];
|
int const cmd_len= 4096;
|
||||||
|
wsp::string cmd_str(cmd_len);
|
||||||
|
|
||||||
int ret= snprintf (cmd_str, sizeof(cmd_str),
|
if (!cmd_str())
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_donate_other(): "
|
||||||
|
"could not allocate cmd buffer of %d bytes", cmd_len);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret= snprintf (cmd_str(), cmd_len,
|
||||||
"wsrep_sst_%s "
|
"wsrep_sst_%s "
|
||||||
WSREP_SST_OPT_ROLE" 'donor' "
|
WSREP_SST_OPT_ROLE" 'donor' "
|
||||||
WSREP_SST_OPT_ADDR" '%s' "
|
WSREP_SST_OPT_ADDR" '%s' "
|
||||||
WSREP_SST_OPT_AUTH" '%s' "
|
|
||||||
WSREP_SST_OPT_SOCKET" '%s' "
|
WSREP_SST_OPT_SOCKET" '%s' "
|
||||||
WSREP_SST_OPT_DATA" '%s' "
|
WSREP_SST_OPT_DATA" '%s' "
|
||||||
WSREP_SST_OPT_CONF" '%s' "
|
WSREP_SST_OPT_CONF" '%s' "
|
||||||
WSREP_SST_OPT_GTID" '%s:%lld'"
|
WSREP_SST_OPT_GTID" '%s:%lld'"
|
||||||
"%s",
|
"%s",
|
||||||
method, addr, sst_auth_real, mysqld_unix_port,
|
method, addr, mysqld_unix_port,
|
||||||
mysql_real_data_home, wsrep_defaults_file,
|
mysql_real_data_home, wsrep_defaults_file,
|
||||||
uuid, (long long) seqno,
|
uuid, (long long) seqno,
|
||||||
bypass ? " "WSREP_SST_OPT_BYPASS : "");
|
bypass ? " "WSREP_SST_OPT_BYPASS : "");
|
||||||
@ -996,7 +1034,7 @@ static int sst_donate_other (const char* method,
|
|||||||
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
|
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
|
||||||
|
|
||||||
pthread_t tmp;
|
pthread_t tmp;
|
||||||
sst_thread_arg arg(cmd_str);
|
sst_thread_arg arg(cmd_str(), env);
|
||||||
mysql_mutex_lock (&arg.lock);
|
mysql_mutex_lock (&arg.lock);
|
||||||
ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg);
|
ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1029,15 +1067,29 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
|
|||||||
char uuid_str[37];
|
char uuid_str[37];
|
||||||
wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str));
|
wsrep_uuid_print (¤t_gtid->uuid, uuid_str, sizeof(uuid_str));
|
||||||
|
|
||||||
|
wsp::env env(NULL);
|
||||||
|
if (env.error())
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_donate_other(): env var ctor failed: %d", -env.error());
|
||||||
|
return WSREP_CB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
if ((ret= sst_append_auth_env(env, sst_auth_real)))
|
||||||
|
{
|
||||||
|
WSREP_ERROR("sst_donate_other(): appending auth env failed: %d", ret);
|
||||||
|
return WSREP_CB_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
|
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
|
||||||
{
|
{
|
||||||
ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str,
|
ret = sst_donate_mysqldump(data, ¤t_gtid->uuid, uuid_str,
|
||||||
current_gtid->seqno, bypass);
|
current_gtid->seqno, bypass, env());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = sst_donate_other(method, data, uuid_str, current_gtid->seqno,bypass);
|
ret = sst_donate_other(method, data, uuid_str,
|
||||||
|
current_gtid->seqno, bypass, env());
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
|
return (ret > 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
|
||||||
|
@ -63,7 +63,7 @@ wsrep_prepend_PATH (const char* path)
|
|||||||
size_t const new_path_len(strlen(old_path) + strlen(":") +
|
size_t const new_path_len(strlen(old_path) + strlen(":") +
|
||||||
strlen(path) + 1);
|
strlen(path) + 1);
|
||||||
|
|
||||||
char* const new_path (reinterpret_cast<char*>(malloc(new_path_len)));
|
char* const new_path (static_cast<char*>(malloc(new_path_len)));
|
||||||
|
|
||||||
if (new_path)
|
if (new_path)
|
||||||
{
|
{
|
||||||
@ -89,6 +89,91 @@ wsrep_prepend_PATH (const char* path)
|
|||||||
namespace wsp
|
namespace wsp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
bool
|
||||||
|
env::ctor_common(char** e)
|
||||||
|
{
|
||||||
|
env_ = static_cast<char**>(malloc((len_ + 1) * sizeof(char*)));
|
||||||
|
|
||||||
|
if (env_)
|
||||||
|
{
|
||||||
|
for (size_t i(0); i < len_; ++i)
|
||||||
|
{
|
||||||
|
assert(e[i]); // caller should make sure about len_
|
||||||
|
env_[i] = strdup(e[i]);
|
||||||
|
if (!env_[i])
|
||||||
|
{
|
||||||
|
errno_ = errno;
|
||||||
|
WSREP_ERROR("Failed to allocate env. var: %s", e[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env_[len_] = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno_ = errno;
|
||||||
|
WSREP_ERROR("Failed to allocate env. var vector of length: %zu", len_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
env::dtor()
|
||||||
|
{
|
||||||
|
if (env_)
|
||||||
|
{
|
||||||
|
/* don't need to go beyond the first NULL */
|
||||||
|
for (size_t i(0); env_[i] != NULL; ++i) { free(env_[i]); }
|
||||||
|
free(env_);
|
||||||
|
env_ = NULL;
|
||||||
|
}
|
||||||
|
len_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
env::env(char** e)
|
||||||
|
: len_(0), env_(NULL), errno_(0)
|
||||||
|
{
|
||||||
|
if (!e) { e = environ; }
|
||||||
|
/* count the size of the vector */
|
||||||
|
while (e[len_]) { ++len_; }
|
||||||
|
|
||||||
|
if (ctor_common(e)) dtor();
|
||||||
|
}
|
||||||
|
|
||||||
|
env::env(const env& e)
|
||||||
|
: len_(e.len_), env_(0), errno_(0)
|
||||||
|
{
|
||||||
|
if (ctor_common(e.env_)) dtor();
|
||||||
|
}
|
||||||
|
|
||||||
|
env::~env() { dtor(); }
|
||||||
|
|
||||||
|
int
|
||||||
|
env::append(const char* val)
|
||||||
|
{
|
||||||
|
char** tmp = static_cast<char**>(realloc(env_, (len_ + 2)*sizeof(char*)));
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
env_ = tmp;
|
||||||
|
env_[len_] = strdup(val);
|
||||||
|
|
||||||
|
if (env_[len_])
|
||||||
|
{
|
||||||
|
++len_;
|
||||||
|
env_[len_] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if either realloc() or strdup() failed, errno had been set */
|
||||||
|
errno_ = errno;
|
||||||
|
|
||||||
|
return errno_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define PIPE_READ 0
|
#define PIPE_READ 0
|
||||||
#define PIPE_WRITE 1
|
#define PIPE_WRITE 1
|
||||||
#define STDIN_FD 0
|
#define STDIN_FD 0
|
||||||
@ -98,7 +183,7 @@ namespace wsp
|
|||||||
# define POSIX_SPAWN_USEVFORK 0
|
# define POSIX_SPAWN_USEVFORK 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
process::process (const char* cmd, const char* type)
|
process::process (const char* cmd, const char* type, char** env)
|
||||||
: str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0)
|
: str_(cmd ? strdup(cmd) : strdup("")), io_(NULL), err_(EINVAL), pid_(0)
|
||||||
{
|
{
|
||||||
if (0 == str_)
|
if (0 == str_)
|
||||||
@ -120,6 +205,8 @@ process::process (const char* cmd, const char* type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NULL == env) { env = environ; } // default to global environment
|
||||||
|
|
||||||
int pipe_fds[2] = { -1, };
|
int pipe_fds[2] = { -1, };
|
||||||
if (::pipe(pipe_fds))
|
if (::pipe(pipe_fds))
|
||||||
{
|
{
|
||||||
@ -215,7 +302,7 @@ process::process (const char* cmd, const char* type)
|
|||||||
goto cleanup_fact;
|
goto cleanup_fact;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, environ);
|
err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, env);
|
||||||
if (err_)
|
if (err_)
|
||||||
{
|
{
|
||||||
WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)",
|
WSREP_ERROR ("posix_spawnp(%s) failed: %d (%s)",
|
||||||
@ -309,6 +396,7 @@ process::wait ()
|
|||||||
{
|
{
|
||||||
case 126: err_ = EACCES; break; /* Permission denied */
|
case 126: err_ = EACCES; break; /* Permission denied */
|
||||||
case 127: err_ = ENOENT; break; /* No such file or directory */
|
case 127: err_ = ENOENT; break; /* No such file or directory */
|
||||||
|
case 143: err_ = EINTR; break; /* Subprocess killed */
|
||||||
}
|
}
|
||||||
WSREP_ERROR("Process completed with error: %s: %d (%s)",
|
WSREP_ERROR("Process completed with error: %s: %d (%s)",
|
||||||
str_, err_, strerror(err_));
|
str_, err_, strerror(err_));
|
||||||
|
@ -44,6 +44,25 @@ private:
|
|||||||
extern wsp::node_status local_status;
|
extern wsp::node_status local_status;
|
||||||
|
|
||||||
namespace wsp {
|
namespace wsp {
|
||||||
|
/* a class to manage env vars array */
|
||||||
|
class env
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
size_t len_;
|
||||||
|
char** env_;
|
||||||
|
int errno_;
|
||||||
|
bool ctor_common(char** e);
|
||||||
|
void dtor();
|
||||||
|
env& operator =(env);
|
||||||
|
public:
|
||||||
|
explicit env(char** env);
|
||||||
|
explicit env(const env&);
|
||||||
|
~env();
|
||||||
|
int append(const char* var); /* add a new env. var */
|
||||||
|
int error() const { return errno_; }
|
||||||
|
char** operator()() { return env_; }
|
||||||
|
};
|
||||||
|
|
||||||
/* A small class to run external programs. */
|
/* A small class to run external programs. */
|
||||||
class process
|
class process
|
||||||
{
|
{
|
||||||
@ -56,8 +75,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
/*! @arg type is a pointer to a null-terminated string which must contain
|
/*! @arg type is a pointer to a null-terminated string which must contain
|
||||||
either the letter 'r' for reading or the letter 'w' for writing.
|
either the letter 'r' for reading or the letter 'w' for writing.
|
||||||
|
@arg env optional null-terminated vector of environment variables
|
||||||
*/
|
*/
|
||||||
process (const char* cmd, const char* type);
|
process (const char* cmd, const char* type, char** env);
|
||||||
~process ();
|
~process ();
|
||||||
|
|
||||||
FILE* pipe () { return io_; }
|
FILE* pipe () { return io_; }
|
||||||
@ -90,6 +110,8 @@ class string
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
string() : string_(0) {}
|
string() : string_(0) {}
|
||||||
|
explicit string(size_t s) : string_(static_cast<char*>(malloc(s))) {}
|
||||||
|
char* operator()() { return string_; }
|
||||||
void set(char* str) { if (string_) free (string_); string_ = str; }
|
void set(char* str) { if (string_) free (string_); string_ = str; }
|
||||||
~string() { set (0); }
|
~string() { set (0); }
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user