mysql5/mysql-5.7.27/client/mysql_install_db.cc

1822 lines
51 KiB
C++

/*
Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
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; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// C headers
#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
// MySQL headers
#include "my_global.h"
#include "my_default.h"
#include "my_getopt.h"
#include "welcome_copyright_notice.h"
#include "mysql_version.h"
#include "auth_utils.h"
#include "path.h"
#include "logger.h"
#include "infix_ostream_it.h"
#include "my_dir.h"
// Additional C++ headers
#include <string>
#include <algorithm>
#include <locale>
#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
#include <sstream>
#include <map>
#include <iomanip>
using namespace std;
#include "../scripts/sql_commands_system_tables.h"
#include "../scripts/sql_commands_system_data.h"
#include "../scripts/sql_commands_help_data.h"
#include "../scripts/sql_commands_sys_schema.h"
#define PROGRAM_NAME "mysql_install_db"
#define MYSQLD_EXECUTABLE "mysqld"
#if defined(HAVE_YASSL)
#define MYSQL_CERT_SETUP_EXECUTABLE "mysql_ssl_rsa_setup"
#endif /* HAVE_YASSL */
#define MAX_MYSQLD_ARGUMENTS 10
#define MAX_USER_NAME_LEN 32
char *opt_euid= 0;
char *opt_basedir= 0;
char *opt_datadir= 0;
char *opt_adminlogin= 0;
char *opt_loginpath= 0;
char default_loginpath[]= "client";
char *opt_sqlfile= 0;
char default_adminuser[]= "root";
char *opt_adminuser= 0;
char default_adminhost[]= "localhost";
char *opt_adminhost= 0;
char default_authplugin[]= "mysql_native_password";
char *opt_authplugin= 0;
char *opt_mysqldfile= 0;
#if defined (HAVE_YASSL)
char *opt_mysql_cert_setup_file= 0;
char default_mysql_cert_setup_file[]= MYSQL_CERT_SETUP_EXECUTABLE;
#endif
char *opt_randpwdfile= 0;
char default_randpwfile[]= ".mysql_secret";
char *opt_langpath= 0;
char *opt_lang= 0;
char default_lang[]= "en_US";
char *opt_defaults_file= 0;
char *opt_def_extra_file= 0;
char *opt_builddir= 0;
char *opt_srcdir= 0;
my_bool opt_no_defaults= FALSE;
my_bool opt_insecure= FALSE;
my_bool opt_verbose= FALSE;
my_bool opt_ssl= FALSE;
my_bool opt_skipsys= FALSE;
/**
Connection options.
@note first element must be 'help' and last element must be
the end token: {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
*/
static struct my_option my_connection_options[]=
{
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "The effective user id used when executing the bootstrap "
"sequence.", &opt_euid, &opt_euid, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
0, 0, 0},
{"builddir", 0, "For use with --srcdir and out-of-source builds. Set this to "
"the location of the directory where the built files reside.",
&opt_builddir, 0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"srcdir", 0, "For internal use. This option specifies the directory under"
" which mysql_install_db looks for support files such as the error"
" message file and the file for populating the help tables.", &opt_srcdir,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"basedir", 0, "The path to the MySQL installation directory.",
&opt_basedir, 0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"datadir", 0, "The path to the MySQL data directory.", &opt_datadir,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"login-path", 0, "Set the credential category to use with the MySQL password"
" store when setting default credentials. This option takes precedence over "
"admin-user, admin-host options.",
&opt_loginpath, 0, 0, GET_STR_ALLOC, REQUIRED_ARG,
(longlong)&default_loginpath, 0, 0, 0, 0, 0},
{"login-file", 0, "Use the MySQL password store at the specified location "
" to set the default password. This option takes precedence over admin-user, "
"admin-host options. Use the login-path option to change the default "
"credential category (default is 'client').",
&opt_adminlogin, 0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"extra-sql-file", 'f', "Optional SQL file to execute during bootstrap.",
&opt_sqlfile, 0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"admin-user", 0, "Username part of the default admin account.",
&opt_adminuser, 0, 0, GET_STR_ALLOC, REQUIRED_ARG,
(longlong)&default_adminuser, 0, 0, 0, 0, 0},
{"admin-host", 0, "Hostname part of the default admin account.",
&opt_adminhost, 0, 0, GET_STR_ALLOC,REQUIRED_ARG,
(longlong)&default_adminhost, 0, 0, 0, 0, 0},
{"admin-auth-plugin", 0, "Plugin to use for the default admin account.",
&opt_authplugin, 0, 0, GET_STR_ALLOC, REQUIRED_ARG,
(longlong)&default_authplugin, 0, 0, 0, 0, 0},
{"admin-require-ssl", 0, "Require SSL/TLS for the default admin account.",
&opt_ssl, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"mysqld-file", 0, "Qualified path to the mysqld binary.", &opt_mysqldfile,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#if defined(HAVE_YASSL)
{"ssl-setup-file", 0, "Qualified path to the mysql_ssl_setup binary", &opt_mysql_cert_setup_file,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"random-password-file", 0, "Specifies the qualified path to the "
".mysql_secret temporary password file.", &opt_randpwdfile,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0,
0, 0, 0, 0, 0},
{"insecure", 0, "Disables random passwords for the default admin account.",
&opt_insecure, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
{"verbose", 'v', "Be more verbose when running program.",
&opt_verbose, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Print program version and exit.",
&opt_verbose, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"lc-messages-dir", 'l', "Specifies the path to the language files.",
&opt_langpath, 0, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"lc-messages", 0, "Specifies the language to use.", &opt_lang,
0, 0, GET_STR_ALLOC, REQUIRED_ARG, (longlong)&default_lang, 0, 0, 0, 0, 0},
{"skip-sys-schema", 0, "Skip installation of the sys schema.",
&opt_skipsys, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
/* End token */
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
Log info(cout,"NOTE");
Log error(cerr,"ERROR");
Log warning(cout, "WARNING");
/**
Escapes quotes and backslash.
@param str The string which needs to be quoted
@note This is not a replacement for the mysql_real_escape_string() function
as it only does what is necessary for this application.
@return A quoted copy of the original string.
*/
string escape_string(string str)
{
string esc("'\"\\");
for(string::iterator it= esc.begin(); it != esc.end(); ++it)
{
string::size_type idx= 0;
while ((idx= str.find(*it, idx)) != string::npos)
{
str.insert(idx, 1, '\\');
idx +=2;
}
}
return str;
}
/**
*/
struct Proxy_user
{
Proxy_user(string opt_host, string opt_user) : host(opt_host), user(opt_user)
{}
string host;
string user;
void to_str(string *sql)
{
sql->clear();
sql->append("INSERT INTO proxies_priv VALUES ('");
sql->append(escape_string(host)).
append("','");
sql->append(escape_string(user)).
append("','','',TRUE,'',now());\n");
}
};
/**
A trivial container for attributes associated with the creation of a MySQL
user.
*/
struct Sql_user
{
Sql_user(string opt_host,
string opt_user,
string opt_password,
Access_privilege opt_priv,
string opt_ssl_type,
string opt_ssl_cipher,
string opt_x509_issuer,
string opt_x509_subject,
int opt_max_questions,
int opt_max_updates,
int opt_max_connections,
int opt_max_user_connections,
string opt_plugin,
string opt_authentication_string,
bool opt_password_expired,
int opt_password_lifetime) :
host(opt_host),
user(opt_user),
password(opt_password),
priv(opt_priv),
ssl_type(opt_ssl_type),
ssl_cipher(opt_ssl_cipher),
x509_issuer(opt_x509_issuer),
x509_subject(opt_x509_subject),
max_questions(opt_max_questions),
max_updates(opt_max_updates),
max_connections(opt_max_connections),
max_user_connections(opt_max_user_connections),
plugin(opt_plugin),
authentication_string(opt_authentication_string),
password_expired(opt_password_expired),
password_lifetime(opt_password_lifetime) {}
string host;
string user;
string password;
Access_privilege priv;
string ssl_type;
string ssl_cipher;
string x509_issuer;
string x509_subject;
int max_questions;
int max_updates;
int max_connections;
int max_user_connections;
string plugin;
string authentication_string;
bool password_expired;
int password_lifetime;
void to_sql(string *cmdstr)
{
stringstream set_passcmd,ss, flush_priv;
ss << "INSERT INTO mysql.user VALUES ("
<< "'" << escape_string(host) << "','" << escape_string(user) << "',";
uint64_t acl= priv.to_int();
for(int i= 0; i< NUM_ACLS; ++i)
{
if( (acl & (1L << i)) != 0 )
ss << "'Y',";
else
ss << "'N',";
}
ss << "'" << escape_string(ssl_type) << "',"
<< "'" << escape_string(ssl_cipher) << "',"
<< "'" << escape_string(x509_issuer) << "',"
<< "'" << escape_string(x509_subject) << "',"
<< max_questions << ","
<< max_updates << ","
<< max_connections << ","
<< max_user_connections << ","
<< "'" << plugin << "',";
ss << "'',";
if (password_expired)
ss << "'Y',";
else
ss << "'N',";
ss << "now(), NULL, 'N');\n";
flush_priv << "FLUSH PRIVILEGES;\n";
if (password_expired)
{
set_passcmd << "ALTER USER '" << escape_string(user) << "'@'"
<< escape_string(host) << "' IDENTIFIED BY '"
<< escape_string(password) << "' PASSWORD EXPIRE;\n";
}
cmdstr->append(ss.str()).append(flush_priv.str()).append(set_passcmd.str());
}
};
static const char *load_default_groups[]= { PROGRAM_NAME, 0 };
void print_version(const string &p)
{
cout << p
<< " Ver " << MYSQL_SERVER_VERSION << ", for "
<< SYSTEM_TYPE << " on "
<< MACHINE_TYPE << "\n";
}
void usage(const string &p)
{
print_version(p);
cout << ORACLE_WELCOME_COPYRIGHT_NOTICE("2015") << endl
<< "MySQL Database Deployment Utility." << endl
<< "Usage: "
<< p
<< " [OPTIONS]" << endl;
my_print_help(my_connection_options);
cout << endl
<< "The following options may be given as the first argument:"
<< endl
<< "--print-defaults Print the program argument list and exit."
<< endl
<< "--no-defaults Don't read default options from any option file,"
<< endl
<< " except for login file."
<< endl
<< "--defaults-file=# Only read default options from the given file #."
<< endl
<< "--defaults-extra-file=# Read this file after the global files are read."
<< endl;
my_print_variables(my_connection_options);
}
extern "C" my_bool
my_arguments_get_one_option(int optid,
const struct my_option *opt MY_ATTRIBUTE((unused)),
char *argument)
{
switch(optid)
{
case '?':
usage(PROGRAM_NAME);
exit(0);
case 'V':
print_version(PROGRAM_NAME);
exit(0);
}
return 0;
}
/**
The string class will break if constructed with a NULL pointer. This wrapper
provides a systematic protection when importing char pointers.
*/
string create_string(char *ptr)
{
if (ptr)
return string(ptr);
else
return string("");
}
template <class InputIterator, class UnaryPredicate >
bool my_all_of(InputIterator first, InputIterator last, UnaryPredicate pred)
{
while (first != last)
{
if (!pred(*first)) return false;
++first;
}
return true;
}
bool my_legal_username_chars(const char &c)
{
return isalnum(c) || c == '_';
}
bool my_legal_hostname_chars(const char &c)
{
return isalnum(c) || c == '_' || c == '.';
}
bool my_legal_plugin_chars(const char &c)
{
return isalnum(c) || c == '_';
}
// defined in auth_utils.cc
extern const string g_allowed_pwd_chars;
bool my_legal_password(const char &c)
{
return (get_allowed_pwd_chars().find(c) != string::npos);
}
/**
Verify that the default admin account follows the recommendations and
restrictions.
*/
bool assert_valid_root_account(const string &username, const string &host,
const string &plugin, bool ssl)
{
if( username.length() > MAX_USER_NAME_LEN || username.length() < 1)
{
error << "Username must be between 1 and "
<< MAX_USER_NAME_LEN
<< " characters in length."
<< endl;
return false;
}
if (!my_all_of(username.begin(), username.end(), my_legal_username_chars) ||
!my_all_of(host.begin(), host.end(), my_legal_hostname_chars))
{
error << "Recommended practice is to use only alpha-numericals in "
"the user / host name."
<< endl;
return false;
}
if (!my_all_of(plugin.begin(), plugin.end(), my_legal_plugin_chars))
{
error << "Only use alpha-numericals in the the plugin name."
<< endl;
return false;
}
if (plugin != "mysql_native_password" && plugin != "sha256_password")
{
error << "Unsupported authentication plugin specified."
<< endl;
return false;
}
return true;
}
bool assert_valid_datadir(const string &datadir, Path *target)
{
if (datadir.length() == 0)
{
error << "The data directory needs to be specified."
<< endl;
return false;
}
target->append(datadir);
if (target->exists())
{
if (!target->empty())
{
error << "The data directory '"
<< datadir.c_str()
<< "' already exist and is not empty." << endl;
return false;
}
}
return true;
}
class File_exists
{
public:
File_exists(const string *file, Path *qp) : m_file(file), m_qpath(qp)
{}
bool operator()(const Path &path)
{
Path tmp_path(path);
tmp_path.filename(*m_file);
if (tmp_path.exists())
{
m_qpath->path(path);
m_qpath->filename(*m_file);
return true;
}
return false;
}
private:
const string *m_file;
Path *m_qpath;
};
/**
Given a list of search paths; find the file.
If search_paths=0 then the filename is considered to be a qualified path.
If filename is empty then the qpath will be the first directory which
is found.
@param filename The file to look for
@search_paths paths to search
@qpath[out] The qualified path to the first found file
@return true if a file is found, false if not.
*/
bool locate_file(const string &filename, vector<Path > *search_paths,
Path *qpath)
{
if (search_paths == 0)
{
MY_STAT s;
if (my_stat(filename.c_str(), &s, MYF(0)) == NULL)
return false;
qpath->qpath(filename);
}
else
{
vector<Path>::iterator qpath_it=
find_if(search_paths->begin(), search_paths->end(),
File_exists(&filename, qpath));
if (qpath_it == search_paths->end())
return false;
}
return true;
}
void add_standard_search_paths(vector<Path > *spaths)
{
Path p;
if (!p.path_getcwd())
warning << "Can't determine current working directory." << endl;
spaths->push_back(p);
spaths->push_back(Path(p).append("/bin"));
spaths->push_back(Path("/usr/bin"));
spaths->push_back(Path("/usr/local/bin"));
spaths->push_back(Path("/opt/mysql/bin"));
#ifdef INSTALL_SBINDIR
spaths->push_back(Path(INSTALL_SBINDIR));
#endif
#ifdef INSTALL_BINDIR
spaths->push_back(Path(INSTALL_BINDIR));
#endif
}
/**
Attempts to locate the mysqld file.
If opt_mysqldfile is specified then the this assumed to be a correct qualified
path to the mysqld executable.
If opt_basedir is specified then opt_basedir+"/bin" is assumed to be a
candidate path for the mysqld executable.
If opt_srcdir is set then opt_srcdir+"/bin" is assumed to be a
candidate path for the mysqld executable.
If opt_builddir is set then opt_builddir+"/sql" is assumed to be a
candidate path for the mysqld executable.
If the executable isn't found in any of these locations,
attempt to search the local directory and "bin" and "sbin" subdirectories.
Finally check "/usr/bin","/usr/sbin", "/usr/local/bin","/usr/local/sbin",
"/opt/mysql/bin","/opt/mysql/sbin"
*/
bool assert_mysqld_exists(const string &opt_mysqldfile,
const string &opt_basedir,
const string &opt_builddir,
const string &opt_srcdir,
Path *qpath)
{
vector<Path > spaths;
if (opt_mysqldfile.length() > 0)
{
/* Use explicit option to file mysqld */
if (!locate_file(opt_mysqldfile, 0, qpath))
{
error << "No such file: " << opt_mysqldfile << endl;
return false;
}
}
else
{
if (opt_basedir.length() > 0)
{
spaths.push_back(Path(opt_basedir).
append("bin"));
/* cater for RPM installs : mysqld in sbin */
spaths.push_back(Path(opt_basedir).
append("sbin"));
}
if (opt_builddir.length() > 0)
{
spaths.push_back(Path(opt_builddir).
append("sql"));
}
add_standard_search_paths(&spaths);
if (!locate_file(MYSQLD_EXECUTABLE, &spaths, qpath))
{
error << "Can't locate the server executable (mysqld)." << endl;
info << "The following paths were searched: ";
copy(spaths.begin(), spaths.end(),
infix_ostream_iterator<Path >(info, ", "));
info << endl;
return false;
}
}
return true;
}
#if defined(HAVE_YASSL)
/**
Attempts to locate the mysql_ssl_rsa_setup file.
If opt_mysql_cert_setup_file is specified then the this assumed to be a
correct qualified path to the mysql_ssl_rsa_setup executable.
If opt_basedir is specified then opt_basedir+"/bin" is assumed to be a
candidate path for the mysql_ssl_rsa_setup executable.
If opt_srcdir is set then opt_srcdir+"/bin" is assumed to be a
candidate path for the mysql_ssl_rsa_setup executable.
If opt_builddir is set then opt_builddir+"/client" is assumed to be a
candidate path for the mysql_system_tables executable.
If the executable isn't found in any of these locations,
attempt to search the local directory and "bin" subdirectory.
Finally check "/usr/bin","/usr/sbin", "/usr/local/bin","/usr/local/sbin",
"/opt/mysql/bin","/opt/mysql/sbin"
*/
bool assert_cert_generator_exists(const string &opt_mysql_cert_setup_file,
const string &opt_basedir,
const string &opt_builddir,
const string &opt_srcdir,
Path *qpath)
{
vector<Path > spaths;
if (opt_mysql_cert_setup_file.length() > 0)
{
/* Use explicit option to file mysql_ssl_rsa_setup */
if (!locate_file(opt_mysql_cert_setup_file, 0, qpath))
{
error << "No such file: " << opt_mysql_cert_setup_file << endl;
return false;
}
}
else
{
if (opt_basedir.length() > 0)
{
spaths.push_back(Path(opt_basedir).
append("bin"));
}
if (opt_builddir.length() > 0)
{
spaths.push_back(Path(opt_builddir).
append("client"));
}
add_standard_search_paths(&spaths);
if (!locate_file(MYSQL_CERT_SETUP_EXECUTABLE, &spaths, qpath))
{
error << "Can't locate the server executable (mysql_ssl_rsa_setup)."
<< endl;
info << "The following paths were searched: ";
copy(spaths.begin(), spaths.end(),
infix_ostream_iterator<Path >(info, ", "));
info << endl;
return false;
}
}
return true;
}
#endif /* HAVE_YASSL */
bool assert_valid_language_directory(const string &opt_langpath,
const string &opt_basedir,
const string &opt_builddir,
const string &opt_srcdir,
Path *language_directory)
{
vector<Path > search_paths;
bool found_subdir= false;
if (opt_langpath.length() > 0)
{
search_paths.push_back(opt_langpath);
}
else
{
if(opt_basedir.length() > 0)
{
Path ld(opt_basedir);
ld.append("/share/english");
search_paths.push_back(ld);
/* cater for RPMs */
Path ld2(opt_basedir);
ld2.append("/share/mysql/english");
search_paths.push_back(ld2);
}
if (opt_builddir.length() > 0)
{
Path ld(opt_builddir);
ld.append("/sql/share/english");
search_paths.push_back(ld);
}
if (opt_srcdir.length() > 0)
{
Path ld(opt_srcdir);
ld.append("/sql/share/english");
search_paths.push_back(ld);
}
search_paths.push_back(Path("/usr/share/mysql/english"));
search_paths.push_back(Path("/opt/mysql/share/english"));
#ifdef INSTALL_MYSQLSHAREDIR
search_paths.push_back(Path(INSTALL_MYSQLSHAREDIR).append("/english"));
#endif
found_subdir= true;
}
if (!locate_file("", &search_paths, language_directory))
{
error << "Can't locate the language directory." << endl;
info << "Attempted the following paths: ";
copy(search_paths.begin(), search_paths.end(),
infix_ostream_iterator<Path>(info, ", "));
info << endl;
return false;
}
if (found_subdir)
language_directory->up();
return true;
}
/**
Parse the login.cnf file and extract the missing admin credentials.
If any of adminuser or adminhost contains information, it won't be overwritten
by new data. Password is always updated.
@return Error
@retval ALL_OK Reporting success
@retval ERR_FILE File not found
@retval ERR_ENCRYPTION Error while decrypting
@retval ERR_SYNTAX Error while parsing
*/
int get_admin_credentials(const string &opt_adminlogin,
const string &login_path,
string *adminuser,
string *adminhost,
string *password)
{
Path path;
int ret= ERR_OTHER;
if (!path.qpath(opt_adminlogin) || !path.exists())
return ERR_FILE;
ifstream fin(opt_adminlogin.c_str(), ifstream::binary);
stringstream sout;
if (decrypt_login_cnf_file(fin, sout) != ALL_OK)
return ERR_ENCRYPTION;
map<string, string > options;
if ((ret= parse_cnf_file(sout, &options, login_path)) != ALL_OK)
return ret;
for( map<string, string >::iterator it= options.begin();
it != options.end(); ++it)
{
if (it->first == "user")
*adminuser= it->second;
if (it->first == "host")
*adminhost= it->second;
if (it->first == "password")
*password= it->second;
}
return ALL_OK;
}
void create_ssl_policy(string *ssl_type, string *ssl_cipher,
string *x509_issuer, string *x509_subject)
{
/* TODO set up a specific SSL restriction on the default account */
*ssl_type= "ANY";
*ssl_cipher= "";
*x509_issuer= "";
*x509_subject= "";
}
#if defined(HAVE_YASSL)
class SSL_generator_writer
{
public:
bool operator()(int fh MY_ATTRIBUTE((unused)))
{
return true;
}
};
#endif /* HAVE_YASSL */
#define READ_BUFFER_SIZE 2048
#define TIMEOUT_IN_SEC 30
class Process_reader
{
public:
Process_reader(string *buffer) : m_buffer(buffer)
{}
bool operator()(int fh)
{
errno= 0;
char ch[READ_BUFFER_SIZE];
ssize_t n= 1;
int select_ret= 0;
fd_set rd, ex;
struct timeval tm;
tm.tv_sec = TIMEOUT_IN_SEC;
tm.tv_usec = 0;
int flags = fcntl(fh, F_GETFL, 0);
fcntl(fh, F_SETFL, flags | O_NONBLOCK);
FD_ZERO(&rd);
FD_ZERO(&ex);
FD_SET(fh, &rd);
FD_SET(fh, &ex);
errno= 0;
/* Wait for something to read */
if ((select_ret= select(fh + 1, &rd, NULL, &ex, &tm)) == 0)
{
/* if 30 s passed we attempt to read anyway */
warning << "select() timed out." << endl;
}
/* Read any error reports from the child process */
while((n= read(fh, ch, READ_BUFFER_SIZE)) > 0 && ch[0] != 0 && errno == 0)
{
m_buffer->append(ch, n);
}
return true;
}
private:
string *m_buffer;
};
struct Delimiter_parser
{
Delimiter_parser() : m_delimiter(";") {}
~Delimiter_parser() {}
bool operator()(std::string &line);
private:
string m_agg;
string m_delimiter;
};
bool Delimiter_parser::operator()(std::string &line)
{
if (line.empty() || line.size() == m_delimiter.size())
return false;
const string delimiter_tok("delimiter ");
string::size_type pos= line.find(delimiter_tok);
string::size_type curr_del_pos= line.find(m_delimiter);
if (pos != string::npos && curr_del_pos != string::npos)
{
/* replace old delimiter with new */
m_delimiter= line.substr(pos+delimiter_tok.size(), curr_del_pos - (pos+delimiter_tok.size()));
line.clear();
return false;
}
if (curr_del_pos != string::npos)
{
line.erase(curr_del_pos, m_delimiter.length());
line.append(";\n");
line= m_agg.append(line);
m_agg.clear();
}
else
{
m_agg.append(line.append(" "));
line.clear();
return false;
}
return true; /* line has delimiter */
}
struct Comment_extractor
{
Comment_extractor() : m_in_comment(false) {}
~Comment_extractor() {}
bool operator()(string &line);
private:
bool m_in_comment;
};
bool Comment_extractor::operator ()(string& line)
{
/* Are we in a multi comment? */
if (m_in_comment)
{
string::size_type i= line.find("*/");
if (i != string::npos)
{
m_in_comment= false;
string::iterator b= line.begin();
advance(b, i+2);
line.erase(line.begin(), b);
if (line.empty())
return true;
}
else
{
/* We're still in a multi comment clear the line */
line.clear();
}
}
else
{
string::size_type i= line.find("--");
if (i != string::npos)
{
string::iterator it= line.begin();
advance(it, i);
line.erase(it,line.end());
return true;
}
i= line.find("/*");
if (i != string::npos)
{
m_in_comment= true;
string::iterator a= line.begin();
advance(a, i);
string::iterator b;
string::size_type j= line.find("*/");
if (j != string::npos)
{
b= line.begin();
advance(b, j+2);
m_in_comment= false;
}
else
b= line.end();
line.erase(a, b);
if (line.empty())
return true;
}
}
return m_in_comment;
}
class Process_writer
{
public:
Process_writer(Sql_user *user, const string &opt_sqlfile) : m_user(user),
m_opt_sqlfile(opt_sqlfile) {}
bool operator()(int fh)
{
errno= 0;
info << "Creating system tables...";
string create_db("CREATE DATABASE mysql;\n");
string use_db("USE mysql;\n");
// ssize_t write() may be declared with attribute warn_unused_result
size_t w1= write(fh, create_db.c_str(), create_db.length());
size_t w2= write(fh, use_db.c_str(), use_db.length());
if (w1 != create_db.length() || w2 != use_db.length())
{
info << "failed." << endl;
return false;
}
unsigned s= 0;
s= sizeof(mysql_system_tables)/sizeof(*mysql_system_tables);
for(unsigned i=0, n= 1; i< s && errno != EPIPE && n != 0 &&
mysql_system_tables[i] != NULL; ++i)
{
n= write(fh, mysql_system_tables[i],
strlen(mysql_system_tables[i]));
}
if (errno != 0)
{
info << "failed." << endl;
return false;
}
else
info << "done." << endl;
info << "Filling system tables with data...";
s= sizeof(mysql_system_data)/sizeof(*mysql_system_data);
for(unsigned i=0, n= 1; i< s && errno != EPIPE && n != 0 &&
mysql_system_data[i] != NULL; ++i)
{
n= write(fh, mysql_system_data[i],
strlen(mysql_system_data[i]));
}
if (errno != 0)
{
info << "failed." << endl;
return false;
}
else
info << "done." << endl;
info << "Filling help table with data...";
s= sizeof(fill_help_tables)/sizeof(*fill_help_tables);
for(unsigned i=0, n= 1; i< s && errno != EPIPE && n != 0 &&
fill_help_tables[i] != NULL; ++i)
{
n= write(fh, fill_help_tables[i],
strlen(fill_help_tables[i]));
}
if (errno != 0)
{
info << "failed." << endl;
return false;
}
else
info << "done." << endl;
info << "Creating user for internal session service...";
string create_session_serv_user(
"INSERT IGNORE INTO mysql.user VALUES ('localhost','mysql.session',"
"'N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','Y','N',"
"'N','N','N','N','N','N','N','N','N','N','N','N','','','','',0,0,0,0,"
"'mysql_native_password','*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE',"
"'N',CURRENT_TIMESTAMP,NULL,'Y');\n");
string select_table_priv(
"INSERT IGNORE INTO mysql.tables_priv VALUES ('localhost', 'mysql',"
" 'mysql.session', 'user', 'root@localhost', CURRENT_TIMESTAMP,"
" 'Select', '');\n"
);
string select_db_priv(
"INSERT IGNORE INTO mysql.db VALUES ('localhost', 'performance_schema',"
" 'mysql.session','Y','N','N','N','N','N','N','N','N','N','N','N',"
"'N','N','N','N','N','N','N');\n"
);
w1= write(fh, create_session_serv_user.c_str(),
create_session_serv_user.length());
w2= write(fh, select_table_priv.c_str(), select_table_priv.length());
size_t w3= write(fh, select_db_priv.c_str(), select_db_priv.length());
if (w1 != create_session_serv_user.length() ||
w2 != select_table_priv.length() ||
w3 != select_db_priv.length())
{
info << "failed." << endl;
return false;
}
else
info << "done." << endl;
info << "Creating default user " << m_user->user << "@"
<< m_user->host
<< endl;
string create_user_cmd;
m_user->to_sql(&create_user_cmd);
w1= write(fh, create_user_cmd.c_str(), create_user_cmd.length());
if (w1 !=create_user_cmd.length() || errno != 0)
return false;
info << "Creating default proxy " << m_user->user << "@"
<< m_user->host
<< endl;
Proxy_user proxy_user(m_user->host, m_user->user);
string create_proxy_cmd;
proxy_user.to_str(&create_proxy_cmd);
w1= write(fh, create_proxy_cmd.c_str(), create_proxy_cmd.length());
if (w1 != create_proxy_cmd.length() || errno != 0)
return false;
if (!opt_skipsys)
{
info << "Creating sys schema" << endl;
s= sizeof(mysql_sys_schema)/sizeof(*mysql_sys_schema);
for(unsigned i=0, n= 1; i< s && errno != EPIPE && n != 0 &&
mysql_sys_schema[i] != NULL; ++i)
{
n= write(fh, mysql_sys_schema[i],
strlen(mysql_sys_schema[i]));
}
if (errno != 0)
{
info << "failed." << endl;
return false;
}
else
info << "done." << endl;
}
/* Execute optional SQL from a file */
if (m_opt_sqlfile.length() > 0)
{
Path extra_sql;
extra_sql.qpath(m_opt_sqlfile);
if (!extra_sql.exists())
{
warning << "No such file '" << extra_sql.to_str() << "' "
<< "(skipping)"
<< endl;
} else
{
info << "Executing extra SQL commands from " << extra_sql.to_str()
<< endl;
ifstream fin(extra_sql.to_str().c_str());
string sql_command;
string default_se_command("SET default_storage_engine=INNODB;\n");
int n= write(fh, default_se_command.c_str(), default_se_command.length());
Comment_extractor strip_comments;
Delimiter_parser check_delimiters;
while (!getline(fin, sql_command).eof() && errno != EPIPE &&
n != 0)
{
bool is_comment= strip_comments(sql_command);
if (!is_comment)
{
bool has_delimiter= check_delimiters(sql_command);
if (!has_delimiter)
continue;
n= write(fh, sql_command.c_str(), sql_command.length());
}
}
fin.close();
}
}
return true;
}
private:
Sql_user *m_user;
string m_opt_sqlfile;
};
struct Reader_thd_command_st
{
Process_reader *reader_functor;
int read_hndl;
};
static void *reader_func_adaptor(void *f)
{
Reader_thd_command_st *cmd= static_cast<Reader_thd_command_st*>(f);
(*cmd->reader_functor)(cmd->read_hndl);
return NULL;
}
template <typename Reader_func_t, typename Writer_func_t,
typename Fwd_iterator >
bool process_execute(const string &exec, Fwd_iterator begin,
Fwd_iterator end, Reader_func_t reader,
Writer_func_t writer)
{
pid_t child;
bool retval= true;
int read_pipe[2];
int write_pipe[2];
posix_spawn_file_actions_t spawn_action;
char *execve_args[MAX_MYSQLD_ARGUMENTS];
/*
Disable any signal handler for broken pipes and check for EPIPE during
IO instead.
*/
signal(SIGPIPE, SIG_IGN);
if (pipe(read_pipe) < 0)
{
return false;
}
if (pipe(write_pipe) < 0)
{
::close(read_pipe[0]);
::close(read_pipe[1]);
return false;
}
posix_spawn_file_actions_init(&spawn_action);
/* target process std input (0) reads from our write_pipe */
posix_spawn_file_actions_adddup2(&spawn_action, write_pipe[0], 0);
/* target process shouldn't attempt to write to this pipe */
posix_spawn_file_actions_addclose(&spawn_action, write_pipe[1]);
/* target process output (1) is mapped to our read_pipe */
posix_spawn_file_actions_adddup2(&spawn_action, read_pipe[1], 2);
/* target process shouldn't attempt to read from this pipe */
posix_spawn_file_actions_addclose(&spawn_action, read_pipe[0]);
/*
We need to copy the strings or spawn will fail
*/
char *local_filename= strdup(exec.c_str());
execve_args[0]= local_filename;
int i= 1;
for(Fwd_iterator it= begin;
it!= end && i < MAX_MYSQLD_ARGUMENTS-1;)
{
execve_args[i]= strdup(const_cast<char *>((*it).c_str()));
++it;
++i;
}
execve_args[i]= 0;
int ret= posix_spawnp(&child, (const char *)execve_args[0], &spawn_action,
NULL, execve_args, NULL);
/* This end is for the target process to read from */
::close(write_pipe[0]);
/* This end is for the target process to write to */
::close(read_pipe[1]);
if (ret != 0)
{
/* always failure if we get here! */
error << "Child process: " << exec <<
" exited with return value " << ret << endl;
exit(1);
}
else
{
pthread_t thd_id;
Reader_thd_command_st cmd;
cmd.read_hndl= read_pipe[0];
cmd.reader_functor= &reader;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &set, NULL);
pthread_create(&thd_id, NULL, reader_func_adaptor, &cmd);
if (!writer(write_pipe[1]) || errno != 0)
{
error << "Child process: " << exec <<
"terminated prematurely with errno= "
<< errno
<< endl;
retval= false;
}
// join with read thread
void *ret= NULL;
pthread_cancel(thd_id); // break select()
pthread_join(thd_id, &ret);
}
while(i > 0)
{
free(execve_args[i]);
--i;
}
::close(write_pipe[1]);
::close(read_pipe[0]);
/* Wait for the child to die */
int signal= 0;
waitpid(child, &signal, 0);
posix_spawn_file_actions_destroy(&spawn_action);
free(local_filename);
return retval;
}
int generate_password_file(Path &pwdfile, const string &adminuser,
const string &adminhost,
const string &password)
{
/*
The format of the password file is
['#'][bytes]['\n']['password bytes']['\n']|[EOF])
*/
ofstream fout;
mode_t old_mask= umask(~(S_IRWXU));
fout.open(pwdfile.to_str().c_str());
if (!fout.is_open())
{
umask(old_mask);
return ERR_FILE;
}
fout << "# Password set for user '"
<< adminuser << "@" << adminhost << "' at "
<< Datetime() << "\n"
<< password << "\n";
fout.close();
info << "done." << endl;
umask(old_mask);
return ALL_OK;
}
int connection_options_sorter(const void *a, const void *b)
{
return strcmp(static_cast<const my_option*>(a)->name,
static_cast<const my_option *>(b)->name);
}
static int is_prefix(const char *s, const char *t)
{
while (*t)
if (*s++ != *t++) return 0;
return 1;
}
static int real_get_defaults_options(int argc, char **argv,
my_bool *no_defaults,
char **defaults,
char **extra_defaults,
char **group_suffix,
char **login_path)
{
char **argv_it= argv;
int org_argc= argc, prev_argc= 0, default_option_count= 0;
while (argc >= 2 && argc != prev_argc)
{
/* Skip program name or previously handled argument */
argv_it++;
prev_argc= argc; /* To check if we found */
/* --no-defaults is always the first option. */
if (is_prefix(*argv_it,"--no-defaults") && ! default_option_count)
{
argc--;
default_option_count ++;
*no_defaults= TRUE;
continue;
}
if (!*defaults && is_prefix(*argv_it, "--defaults-file="))
{
*defaults= *argv_it + sizeof("--defaults-file=")-1;
argc--;
default_option_count ++;
continue;
}
if (!*extra_defaults && is_prefix(*argv_it, "--defaults-extra-file="))
{
*extra_defaults= *argv_it + sizeof("--defaults-extra-file=")-1;
argc--;
default_option_count ++;
continue;
}
if (!*group_suffix && is_prefix(*argv_it, "--defaults-group-suffix="))
{
*group_suffix= *argv_it + sizeof("--defaults-group-suffix=")-1;
argc--;
default_option_count ++;
continue;
}
if (!*login_path && is_prefix(*argv_it, "--login-path="))
{
*login_path= *argv_it + sizeof("--login-path=")-1;
argc--;
default_option_count ++;
continue;
}
}
return org_argc - argc;
}
class Resource_releaser
{
char **m_argv;
public:
explicit Resource_releaser(char **argv)
: m_argv(argv) { }
~Resource_releaser()
{
free_defaults(m_argv);
my_cleanup_options(my_connection_options);
}
};
int main(int argc,char *argv[])
{
/*
In order to use the mysys library and the program option library
we need to call the MY_INIT() macro.
*/
MY_INIT(argv[0]);
char *dummy= 0; // ignore group suffix when transferring to mysqld
/* Remember the defaults argument so we later can pass these to mysqld */
int default_opt_used= real_get_defaults_options(argc, argv,
&opt_no_defaults,
&opt_defaults_file,
&opt_def_extra_file,
&dummy,
&opt_loginpath);
#ifdef __WIN__
/* Convert command line parameters from UTF16LE to UTF8MB4. */
my_win_translate_command_line_args(&my_charset_utf8mb4_bin, &argc, &argv);
#endif
my_getopt_use_args_separator= TRUE;
if (load_defaults("my", load_default_groups, &argc, &argv))
return 1;
// Remember to call free_defaults() and my_cleanup_options()
Resource_releaser resource_releaser(argv);
// Assert that the help messages are in sorted order
// except that --help must be the first element and 0 must indicate the end.
my_qsort(my_connection_options + 1,
sizeof(my_connection_options)/sizeof(my_option) - 2,
sizeof(my_option),
connection_options_sorter);
int rc= 0;
if ((rc= handle_options(&argc, &argv, my_connection_options,
my_arguments_get_one_option)))
{
error << "Unrecognized options" << endl;
return 1;
}
warning << "mysql_install_db is deprecated. ";
warning << "Please consider switching to mysqld --initialize" << endl;
bool expire_password= !opt_insecure;
string adminuser(create_string(opt_adminuser));
string adminhost(create_string(opt_adminhost));
string authplugin(create_string(opt_authplugin));
string password;
string basedir(create_string(opt_basedir));
string srcdir(create_string(opt_srcdir));
string builddir(create_string(opt_builddir));
if (opt_verbose != 1)
{
info.enabled(false);
}
if (default_opt_used > 0)
{
if (opt_defaults_file != 0)
{
info << "Using default values from " << opt_defaults_file << endl;
}
else
if (!opt_no_defaults)
{
info << "Using default values from my.cnf" << endl;
}
if (opt_def_extra_file != 0)
{
info << "Using additional default values from " << endl;
}
}
/*
1. Verify all option parameters
2. Create missing directories
3. Compose mysqld start string
4. Execute mysqld
5. Exit
*/
if (opt_adminlogin)
{
info << "Reading the login config file "
<< opt_adminlogin
<< " for default account credentials using login-path = "
<< opt_loginpath
<< endl;
int ret= get_admin_credentials(create_string(opt_adminlogin),
create_string(opt_loginpath),
&adminuser,
&adminhost,
&password);
switch(ret)
{
case ALL_OK: expire_password= false;
if (password.length() == 0 && !opt_insecure)
{
error << "Password is specified as empty! You need to use the "
"--insecure option" << endl;
return 1;
}
break;
case ERR_FILE:
error << "Can't read the login config file: "
<< opt_adminlogin << endl;
return 1;
case ERR_ENCRYPTION:
error << "Failed to decrypt the login config file: "
<< opt_adminlogin << endl;
return 1;
case ERR_NO_SUCH_CATEGORY:
error << "Failed to locate login-path '"
<< opt_loginpath << "' "
<< "in the login config file '"
<< opt_adminlogin << "' " << endl;
return 1;
case ERR_SYNTAX:
default:
error << "Failed to parse the login config file: "
<< opt_adminlogin << endl;
return 1;
}
}
if (!assert_valid_root_account(adminuser,
adminhost,
create_string(opt_authplugin),
opt_ssl))
{
/* Subroutine reported error */
return 1;
}
Path data_directory;
if (!assert_valid_datadir(create_string(opt_datadir), &data_directory))
{
/* Subroutine reported error */
return 1;
}
Path language_directory;
if (!assert_valid_language_directory(create_string(opt_langpath),
basedir,
builddir,
srcdir,
&language_directory))
{
/* Subroutine reported error */
return 1;
}
Path mysqld_exec;
if( !assert_mysqld_exists(create_string(opt_mysqldfile),
basedir,
builddir,
srcdir,
&mysqld_exec))
{
/* Subroutine reported error */
return 1;
}
#if defined(HAVE_YASSL)
Path mysql_cert_setup;
if( !opt_insecure &&
!assert_cert_generator_exists(create_string(opt_mysql_cert_setup_file),
basedir,
builddir,
srcdir,
&mysql_cert_setup))
{
/* Subroutine reported error */
return 1;
}
#endif /* HAVE_YASSL */
if (opt_def_extra_file)
{
Path def_extra_file;
def_extra_file.qpath(opt_def_extra_file);
if (!def_extra_file.exists())
{
warning << "Can't open extra defaults file '"
<< opt_def_extra_file
<< "' (skipping)" << endl;
opt_def_extra_file= NULL;
}
}
if (opt_defaults_file)
{
opt_no_defaults= FALSE;
Path defaults_file;
defaults_file.qpath(opt_defaults_file);
if (!defaults_file.exists())
{
error << "Can't open defaults file '"
<< defaults_file
<< "'" << endl;
opt_defaults_file= NULL;
return 1;
}
}
if (data_directory.exists())
{
info << "Using existing directory "
<< data_directory
<< endl;
}
else
{
info << "Creating data directory "
<< data_directory << endl;
mode_t old_mask= umask(0);
if (my_mkdir(data_directory.to_str().c_str(),
S_IRWXU | S_IRGRP | S_IXGRP, MYF(MY_WME)))
{
error << "Failed to create the data directory '"
<< data_directory << "'" << endl;
umask(old_mask);
return 1;
}
umask(old_mask);
}
/* Generate a random password is no password was found previously */
if (password.length() == 0 && !opt_insecure)
{
Path randpwdfile;
if (opt_randpwdfile != 0)
{
randpwdfile.qpath(opt_randpwdfile);
}
else
{
randpwdfile.get_homedir();
randpwdfile.filename(default_randpwfile);
}
info << "Generating random password to "
<< randpwdfile << "...";
generate_password(&password,12);
if (generate_password_file(randpwdfile, adminuser, adminhost,
password) != ALL_OK)
{
error << "Can't create password file "
<< randpwdfile
<< endl;
return 1;
}
}
if (opt_euid && geteuid() == 0)
{
struct passwd *pwd;
info << "Setting file ownership to " << opt_euid
<< endl;
pwd= getpwnam(opt_euid); /* Try getting UID for username */
if (pwd == NULL)
{
error << "Failed to verify user id '" << opt_euid
<< "'. Does it exist?" << endl;
return 1;
}
if (chown(data_directory.to_str().c_str(), pwd->pw_uid, pwd->pw_gid) != 0)
{
error << "Failed to set file ownership for "
<< data_directory.to_str()
<< " to (" << pwd->pw_uid << ", " << pwd->pw_gid << ")"
<< endl;
}
if (setegid(pwd->pw_gid) != 0)
{
warning << "Failed to set effective group id to " << pwd->pw_gid
<< endl;
}
if (seteuid(pwd->pw_uid) != 0)
{
warning << "Failed to set effective user id to " << pwd->pw_uid
<< endl;
}
}
else
opt_euid= 0;
vector<string> command_line;
if (opt_no_defaults == TRUE && opt_defaults_file == NULL &&
opt_def_extra_file == NULL)
command_line.push_back(string("--no-defaults"));
if (opt_defaults_file != NULL)
command_line.push_back(string("--defaults-file=")
.append(opt_defaults_file));
if (opt_def_extra_file != NULL)
command_line.push_back(string("--defaults-extra-file=")
.append(opt_def_extra_file));
command_line.push_back(string("--bootstrap"));
command_line.push_back(string("--datadir=")
.append(data_directory.to_str()));
command_line.push_back(string("--lc-messages-dir=")
.append(language_directory.to_str()));
command_line.push_back(string("--lc-messages=")
.append(create_string(opt_lang)));
if (basedir.length() > 0)
command_line.push_back(string("--basedir=")
.append(basedir));
#if defined(HAVE_YASSL)
vector<string> cert_setup_command_line;
if (!opt_insecure)
{
if (opt_no_defaults == TRUE && opt_defaults_file == NULL &&
opt_def_extra_file == NULL)
cert_setup_command_line.push_back(string("--no-defaults"));
cert_setup_command_line.push_back(string("--datadir=")
.append(data_directory.to_str()));
cert_setup_command_line.push_back(string("--suffix=")
.append(MYSQL_SERVER_VERSION));
}
#endif /* HAVE_YASSL */
// DEBUG
//mysqld_exec.append("\"").insert(0, "gnome-terminal -e \"gdb --args ");
string ssl_type;
string ssl_cipher;
string x509_issuer;
string x509_subject;
if (opt_ssl == true)
create_ssl_policy(&ssl_type, &ssl_cipher, &x509_issuer, &x509_subject);
info << "Executing " << mysqld_exec.to_str() << " ";
copy(command_line.begin(), command_line.end(),
infix_ostream_iterator<Path>(info, " "));
info << endl;
Sql_user user(adminhost,
adminuser,
password,
Access_privilege(Access_privilege::acl_all()),
ssl_type, // ssl_type
ssl_cipher, // ssl_cipher
x509_issuer, // x509_issuer
x509_subject, // x509_subject
0, // max_questions
0, // max updates
0, // max connections
0, // max user connections
create_string(opt_authplugin),
string(""),
expire_password,
0);
string output;
bool success= process_execute(mysqld_exec.to_str(),
command_line.begin(),
command_line.end(),
Process_reader(&output),
Process_writer(&user,create_string(opt_sqlfile)));
if (!success)
{
error << "Failed to execute " << mysqld_exec.to_str() << " ";
copy(command_line.begin(), command_line.end(),
infix_ostream_iterator<Path>(error, " "));
error << endl;
cerr << "-- server log begin --" << endl;
cerr << output << endl;
cerr << "-- server log end --" << endl;
return 1;
}
else if (output.find("ERROR") != string::npos)
{
error << "The bootstrap log isn't empty:"
<< endl
<< output
<< endl;
}
else if (output.size() > 0 &&
output.find_first_not_of(" \t\n\r") != string::npos)
{
warning << "The bootstrap log isn't empty:"
<< endl
<< output
<< endl;
}
else
{
info << "Success!"
<< endl;
}
#if defined(HAVE_YASSL)
if (!opt_insecure)
{
string ssl_output;
info << "Generating SSL Certificates" << endl;
success= process_execute(mysql_cert_setup.to_str(),
cert_setup_command_line.begin(),
cert_setup_command_line.end(),
Process_reader(&ssl_output),
SSL_generator_writer());
if (!success)
{
warning << "failed to execute " << mysql_cert_setup.to_str() << " ";
copy(cert_setup_command_line.begin(), cert_setup_command_line.end(),
infix_ostream_iterator<Path>(error, " "));
warning << endl;
warning << "SSL functionality may not work";
warning << endl;
}
else if ((ssl_output.size() > 0))
{
info << "SSL certificate generation :"
<< endl
<< ssl_output
<< endl;
}
}
#endif /* HAVE_YASSL */
return 0;
}