|
- /*
- Copyright (c) 2012, 2021, Oracle and/or its affiliates.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 2.0,
- as published by the Free Software Foundation.
-
- This program is also distributed with certain software (including
- but not limited to OpenSSL) that is licensed under separate terms,
- as designated in a particular file or component or in included license
- documentation. The authors of MySQL hereby grant you an additional
- permission to link the program and your derivative works with the
- separately licensed software that they have included with MySQL.
-
- 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, version 2.0, 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"
- #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;
- 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},
- {"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(COPYRIGHT_NOTICE_STONEDB_BEGIN_YEAR) << 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;
- }
-
-
- 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= "";
- }
-
- #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 (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));
-
- 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;
- }
-
- return 0;
- }
|