diff options
Diffstat (limited to 'server-tools')
55 files changed, 0 insertions, 13103 deletions
diff --git a/server-tools/CMakeLists.txt b/server-tools/CMakeLists.txt deleted file mode 100644 index 3f02ba88f1d..00000000000 --- a/server-tools/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2006 MySQL AB -# -# 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 - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc imservice.cpp windowsservice.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager dbug mysys strings taocrypt vio yassl zlib wsock32) diff --git a/server-tools/Makefile.am b/server-tools/Makefile.am deleted file mode 100644 index 96e9d5a946e..00000000000 --- a/server-tools/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2003, 2006 MySQL AB -# -# 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 - -SUBDIRS = . instance-manager -DIST_SUBDIRS = . instance-manager - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt deleted file mode 100755 index 2b9bce56ff7..00000000000 --- a/server-tools/instance-manager/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2006 MySQL AB -# -# 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 -INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -ADD_DEFINITIONS(-DMYSQL_SERVER -DMYSQL_INSTANCE_MANAGER) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/sql - ${PROJECT_SOURCE_DIR}/extra/yassl/include) - -ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instance.cc instance_map.cc - instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc - mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc - thread_registry.cc user_map.cc IMService.cpp WindowsService.cpp - user_management_commands.cc - ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c - ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c - ../../libmysql/errmsg.c) - -ADD_DEPENDENCIES(mysqlmanager GenError) -TARGET_LINK_LIBRARIES(mysqlmanager debug dbug mysys strings taocrypt vio yassl zlib wsock32) - -IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqlmanager" "asInvoker") -ENDIF(EMBED_MANIFESTS) diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp deleted file mode 100644 index feccaadbecc..00000000000 --- a/server-tools/instance-manager/IMService.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#include <winsock2.h> -#include <signal.h> - -#include "IMService.h" - -#include "log.h" -#include "manager.h" -#include "options.h" - -static const char * const IM_SVC_USERNAME= NULL; -static const char * const IM_SVC_PASSWORD= NULL; - -IMService::IMService(void) - :WindowsService("MySqlManager", "MySQL Manager") -{ -} - -IMService::~IMService(void) -{ -} - -void IMService::Stop() -{ - ReportStatus(SERVICE_STOP_PENDING); - - /* stop the IM work */ - raise(SIGTERM); -} - -void IMService::Run(DWORD argc, LPTSTR *argv) -{ - /* report to the SCM that we're about to start */ - ReportStatus((DWORD)SERVICE_START_PENDING); - - Options::load(argc, argv); - - /* init goes here */ - ReportStatus((DWORD)SERVICE_RUNNING); - - /* wait for main loop to terminate */ - (void) Manager::main(); - Options::cleanup(); -} - -void IMService::Log(const char *msg) -{ - log_info(msg); -} - -int IMService::main() -{ - IMService winService; - - if (Options::Service::install_as_service) - { - if (winService.IsInstalled()) - { - log_info("Service is already installed."); - return 1; - } - - if (winService.Install(IM_SVC_USERNAME, IM_SVC_PASSWORD)) - { - log_info("Service installed successfully."); - return 0; - } - else - { - log_error("Service failed to install."); - return 1; - } - } - - if (Options::Service::remove_service) - { - if (!winService.IsInstalled()) - { - log_info("Service is not installed."); - return 1; - } - - if (winService.Remove()) - { - log_info("Service removed successfully."); - return 0; - } - else - { - log_error("Service failed to remove."); - return 1; - } - } - - log_info("Initializing Instance Manager service..."); - - if (!winService.Init()) - { - log_error("Service failed to initialize."); - - fprintf(stderr, - "The service should be started by Windows Service Manager.\n" - "The MySQL Manager should be started with '--standalone'\n" - "to run from command line."); - - return 1; - } - - return 0; -} diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h deleted file mode 100644 index aceafb2fca6..00000000000 --- a/server-tools/instance-manager/IMService.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#pragma once -#include "WindowsService.h" - -class IMService: public WindowsService -{ -public: - static int main(); - -private: - IMService(void); - ~IMService(void); - -protected: - void Log(const char *msg); - void Stop(); - void Run(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am deleted file mode 100644 index 19c4ac8de19..00000000000 --- a/server-tools/instance-manager/Makefile.am +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2004 MySQL AB -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -INCLUDES= @ZLIB_INCLUDES@ -I$(top_srcdir)/include \ - @openssl_includes@ -I$(top_builddir)/include - -DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER - -# As all autoconf variables depend from ${prefix} and being resolved only when -# make is run, we can not put these defines to a header file (e.g. to -# default_options.h, generated from default_options.h.in) -# See automake/autoconf docs for details - -noinst_LTLIBRARIES= liboptions.la -noinst_LIBRARIES= libnet.a - -liboptions_la_CXXFLAGS= $(CXXFLAGS) \ - -DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \ - -DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \ - -DDEFAULT_SOCKET_FILE_NAME="/tmp/mysqlmanager.sock" \ - -DDEFAULT_PASSWORD_FILE_NAME="/etc/mysqlmanager.passwd" \ - -DDEFAULT_MYSQLD_PATH="$(libexecdir)/mysqld$(EXEEXT)" \ - -DDEFAULT_CONFIG_FILE="my.cnf" \ - -DPROTOCOL_VERSION=@PROTOCOL_VERSION@ - -liboptions_la_SOURCES= options.h options.cc priv.h priv.cc -liboptions_la_LIBADD= $(top_builddir)/libmysql/get_password.lo - -# MySQL sometimes uses symlinks to reuse code -# All symlinked files are grouped in libnet.a - -nodist_libnet_a_SOURCES= net_serv.cc client_settings.h -libnet_a_LIBADD= $(top_builddir)/sql/password.$(OBJEXT) \ - $(top_builddir)/sql/pack.$(OBJEXT) \ - $(top_builddir)/sql/sql_state.$(OBJEXT) \ - $(top_builddir)/sql/mini_client_errors.$(OBJEXT)\ - $(top_builddir)/sql/client.$(OBJEXT) - -CLEANFILES= net_serv.cc client_settings.h - -net_serv.cc: - rm -f net_serv.cc - @LN_CP_F@ $(top_srcdir)/sql/net_serv.cc net_serv.cc - -client_settings.h: - rm -f client_settings.h - @LN_CP_F@ $(top_srcdir)/sql/client_settings.h client_settings.h - -libexec_PROGRAMS= mysqlmanager - -mysqlmanager_CXXFLAGS= - -mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \ - manager.h manager.cc log.h log.cc \ - thread_registry.h thread_registry.cc \ - listener.h listener.cc protocol.h protocol.cc \ - mysql_connection.h mysql_connection.cc \ - user_map.h user_map.cc \ - messages.h messages.cc \ - commands.h commands.cc \ - instance.h instance.cc \ - instance_map.h instance_map.cc\ - instance_options.h instance_options.cc \ - buffer.h buffer.cc parse.cc parse.h \ - guardian.cc guardian.h \ - parse_output.cc parse_output.h \ - mysql_manager_error.h \ - portability.h \ - exit_codes.h \ - user_management_commands.h \ - user_management_commands.cc \ - angel.h \ - angel.cc - -mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \ - liboptions.la \ - libnet.a \ - $(top_builddir)/vio/libvio.a \ - $(top_builddir)/mysys/libmysys.a \ - $(top_builddir)/strings/libmystrings.a \ - $(top_builddir)/dbug/libdbug.a \ - @openssl_libs@ @yassl_libs@ @ZLIB_LIBS@ - -EXTRA_DIST = WindowsService.cpp WindowsService.h IMService.cpp \ - IMService.h CMakeLists.txt - -tags: - ctags -R *.h *.cc - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/server-tools/instance-manager/README b/server-tools/instance-manager/README deleted file mode 100644 index ac799775003..00000000000 --- a/server-tools/instance-manager/README +++ /dev/null @@ -1,11 +0,0 @@ -Instance Manager - manage MySQL instances locally and remotely. - -File description: - mysqlmanager.cc - entry point to the manager, main, - options.{h,cc} - handle startup options - manager.{h,cc} - manager process - mysql_connection.{h,cc} - handle one connection with mysql client. - -See also instance manager architecture description in mysqlmanager.cc. - - diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp deleted file mode 100644 index 14795e2225a..00000000000 --- a/server-tools/instance-manager/WindowsService.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#include "my_global.h" -#include <windows.h> -#include "WindowsService.h" - -static WindowsService *gService; - -WindowsService::WindowsService(const char *p_serviceName, - const char *p_displayName) : - statusCheckpoint(0), - serviceName(p_serviceName), - displayName(p_displayName), - inited(FALSE), - dwAcceptedControls(SERVICE_ACCEPT_STOP), - debugging(FALSE) -{ - DBUG_ASSERT(serviceName != NULL); - - /* TODO: shouldn't we check displayName too (can it really be NULL)? */ - - /* WindowsService is assumed to be singleton. Let's assure this. */ - DBUG_ASSERT(gService == NULL); - - gService= this; - - status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; - status.dwServiceSpecificExitCode= 0; -} - -WindowsService::~WindowsService(void) -{ -} - -BOOL WindowsService::Install(const char *username, const char *password) -{ - bool ret_val= FALSE; - SC_HANDLE newService; - SC_HANDLE scm; - - if (IsInstalled()) - return TRUE; - - // determine the name of the currently executing file - char szFilePath[_MAX_PATH]; - GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); - - // open a connection to the SCM - if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) - return FALSE; - - newService= CreateService(scm, serviceName, displayName, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - szFilePath, NULL, NULL, NULL, username, - password); - - if (newService) - { - CloseServiceHandle(newService); - ret_val= TRUE; - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::Init() -{ - DBUG_ASSERT(serviceName != NULL); - - if (inited) - return TRUE; - - SERVICE_TABLE_ENTRY stb[] = - { - { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, - { NULL, NULL } - }; - inited= TRUE; - return StartServiceCtrlDispatcher(stb); //register with the Service Manager -} - -BOOL WindowsService::Remove() -{ - bool ret_val= FALSE; - - if (!IsInstalled()) - return TRUE; - - // open a connection to the SCM - SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); - if (!scm) - return FALSE; - - SC_HANDLE service= OpenService(scm, serviceName, DELETE); - if (service) - { - if (DeleteService(service)) - ret_val= TRUE; - DWORD dw= ::GetLastError(); - CloseServiceHandle(service); - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::IsInstalled() -{ - BOOL ret_val= FALSE; - - SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); - - ret_val= serv_handle != NULL; - - ::CloseServiceHandle(serv_handle); - ::CloseServiceHandle(scm); - - return ret_val; -} - -void WindowsService::SetAcceptedControls(DWORD acceptedControls) -{ - dwAcceptedControls= acceptedControls; -} - - -BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, - DWORD dwError) -{ - if (debugging) - return TRUE; - - if(currentState == SERVICE_START_PENDING) - status.dwControlsAccepted= 0; - else - status.dwControlsAccepted= dwAcceptedControls; - - status.dwCurrentState= currentState; - status.dwWin32ExitCode= dwError != 0 ? - ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; - status.dwWaitHint= waitHint; - status.dwServiceSpecificExitCode= dwError; - - if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) - { - status.dwCheckPoint= 0; - statusCheckpoint= 0; - } - else - status.dwCheckPoint= ++statusCheckpoint; - - // Report the status of the service to the service control manager. - BOOL result= SetServiceStatus(statusHandle, &status); - if (!result) - Log("ReportStatus failed"); - - return result; -} - -void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) -{ - statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); - if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(argc, argv); - ReportStatus(SERVICE_STOPPED); -} - -void WindowsService::HandleControlCode(DWORD opcode) -{ - // Handle the requested control code. - switch(opcode) { - case SERVICE_CONTROL_STOP: - // Stop the service. - status.dwCurrentState= SERVICE_STOP_PENDING; - Stop(); - break; - - case SERVICE_CONTROL_PAUSE: - status.dwCurrentState= SERVICE_PAUSE_PENDING; - Pause(); - break; - - case SERVICE_CONTROL_CONTINUE: - status.dwCurrentState= SERVICE_CONTINUE_PENDING; - Continue(); - break; - - case SERVICE_CONTROL_SHUTDOWN: - Shutdown(); - break; - - case SERVICE_CONTROL_INTERROGATE: - ReportStatus(status.dwCurrentState); - break; - - default: - // invalid control code - break; - } -} - -void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) -{ - DBUG_ASSERT(gService != NULL); - - // register our service control handler: - gService->RegisterAndRun(argc, argv); -} - -void WINAPI WindowsService::ControlHandler(DWORD opcode) -{ - DBUG_ASSERT(gService != NULL); - - return gService->HandleControlCode(opcode); -} diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h deleted file mode 100644 index 02a499e5f0c..00000000000 --- a/server-tools/instance-manager/WindowsService.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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 */ - -#pragma once - -class WindowsService -{ -protected: - bool inited; - const char *serviceName; - const char *displayName; - SERVICE_STATUS_HANDLE statusHandle; - DWORD statusCheckpoint; - SERVICE_STATUS status; - DWORD dwAcceptedControls; - bool debugging; - -public: - WindowsService(const char *p_serviceName, const char *p_displayName); - ~WindowsService(void); - - BOOL Install(const char *username, const char *password); - BOOL Remove(); - BOOL Init(); - BOOL IsInstalled(); - void SetAcceptedControls(DWORD acceptedControls); - void Debug(bool debugFlag) { debugging= debugFlag; } - -public: - static void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); - static void WINAPI ControlHandler(DWORD CtrlType); - -protected: - virtual void Run(DWORD argc, LPTSTR *argv)= 0; - virtual void Stop() {} - virtual void Shutdown() {} - virtual void Pause() {} - virtual void Continue() {} - virtual void Log(const char *msg) {} - - BOOL ReportStatus(DWORD currentStatus, DWORD waitHint= 3000, DWORD dwError=0); - void HandleControlCode(DWORD opcode); - void RegisterAndRun(DWORD argc, LPTSTR *argv); -}; diff --git a/server-tools/instance-manager/angel.cc b/server-tools/instance-manager/angel.cc deleted file mode 100644 index 64515c8498c..00000000000 --- a/server-tools/instance-manager/angel.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef __WIN__ - -#include "angel.h" - -#include <sys/wait.h> -/* - sys/wait.h is needed for waitpid(). Unfortunately, there is no MySQL - include file, that can serve for this. Include it before MySQL system - headers so that we can change system defines if needed. -*/ - -#include "my_global.h" -#include "my_alarm.h" -#include "my_dir.h" -#include "my_sys.h" - -/* Include other IM files. */ - -#include "log.h" -#include "manager.h" -#include "options.h" -#include "priv.h" - -/************************************************************************/ - -enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL }; - -static int log_fd; - -static volatile sig_atomic_t child_status= CHILD_OK; -static volatile sig_atomic_t child_exit_code= 0; -static volatile sig_atomic_t shutdown_request_signo= 0; - - -/************************************************************************/ -/** - Open log file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool open_log_file() -{ - log_info("Angel: opening log file '%s'...", - (const char *) Options::Daemon::log_file_name); - - log_fd= open(Options::Daemon::log_file_name, - O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - - if (log_fd < 0) - { - log_error("Can not open log file '%s': %s.", - (const char *) Options::Daemon::log_file_name, - (const char *) strerror(errno)); - - return TRUE; - } - - return FALSE; -} - - -/************************************************************************/ -/** - Detach the process from controlling tty. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool detach_process() -{ - /* - Become a session leader (the goal is not to have a controlling tty). - - setsid() must succeed because child is guaranteed not to be a process - group leader (it belongs to the process group of the parent). - - NOTE: if we now don't have a controlling tty we will not receive - tty-related signals - no need to ignore them. - */ - - if (setsid() < 0) - { - log_error("setsid() failed: %s.", (const char *) strerror(errno)); - return -1; - } - - /* Close STDIN. */ - - log_info("Angel: preparing standard streams."); - - if (close(STDIN_FILENO) < 0) - { - log_error("Warning: can not close stdin (%s)." - "Trying to continue...", - (const char *) strerror(errno)); - } - - /* Dup STDOUT and STDERR to the log file. */ - - if (dup2(log_fd, STDOUT_FILENO) < 0 || - dup2(log_fd, STDERR_FILENO) < 0) - { - log_error("Can not redirect stdout and stderr to the log file: %s.", - (const char *) strerror(errno)); - - return TRUE; - } - - if (log_fd != STDOUT_FILENO && log_fd != STDERR_FILENO) - { - if (close(log_fd) < 0) - { - log_error("Can not close original log file handler (%d): %s. " - "Trying to continue...", - (int) log_fd, - (const char *) strerror(errno)); - } - } - - return FALSE; -} - - -/************************************************************************/ -/** - Create PID file. - - @return - TRUE on error; - FALSE on success. -*************************************************************************/ - -static bool create_pid_file() -{ - if (create_pid_file(Options::Daemon::angel_pid_file_name, getpid())) - { - log_error("Angel: can not create pid file (%s).", - (const char *) Options::Daemon::angel_pid_file_name); - - return TRUE; - } - - log_info("Angel: pid file (%s) created.", - (const char *) Options::Daemon::angel_pid_file_name); - - return FALSE; -} - - -/************************************************************************/ -/** - SIGCHLD handler. - - Reap child, analyze child exit code, and set child_status - appropriately. -*************************************************************************/ - -extern "C" void reap_child(int); - -void reap_child(int __attribute__((unused)) signo) -{ - /* NOTE: As we have only one child, no need to cycle waitpid(). */ - - int exit_code; - - if (waitpid(0, &exit_code, WNOHANG) > 0) - { - child_exit_code= exit_code; - child_status= exit_code ? CHILD_NEED_RESPAWN : CHILD_EXIT_ANGEL; - } -} - - -/************************************************************************/ -/** - SIGTERM, SIGHUP, SIGINT handler. - - Set termination status and return. -*************************************************************************/ - -extern "C" void terminate(int signo); -void terminate(int signo) -{ - shutdown_request_signo= signo; -} - - -/************************************************************************/ -/** - Angel main loop. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -static int angel_main_loop() -{ - /* - Install signal handlers. - - NOTE: Although signal handlers are needed only for parent process - (IM-angel), we should install them before fork() in order to avoid race - condition (i.e. to be sure, that IM-angel will receive SIGCHLD in any - case). - */ - - sigset_t wait_for_signals_mask; - - struct sigaction sa_chld; - struct sigaction sa_term; - struct sigaction sa_chld_orig; - struct sigaction sa_term_orig; - struct sigaction sa_int_orig; - struct sigaction sa_hup_orig; - - log_info("Angel: setting necessary signal actions..."); - - sigemptyset(&wait_for_signals_mask); - - sigemptyset(&sa_chld.sa_mask); - sa_chld.sa_handler= reap_child; - sa_chld.sa_flags= SA_NOCLDSTOP; - - sigemptyset(&sa_term.sa_mask); - sa_term.sa_handler= terminate; - sa_term.sa_flags= 0; - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld, &sa_chld_orig); - sigaction(SIGTERM, &sa_term, &sa_term_orig); - sigaction(SIGINT, &sa_term, &sa_int_orig); - sigaction(SIGHUP, &sa_term, &sa_hup_orig); - - /* The main Angel loop. */ - - while (true) - { - /* Spawn a new Manager. */ - - log_info("Angel: forking Manager process..."); - - switch (fork()) { - case -1: - log_error("Angel: can not fork IM-main: %s.", - (const char *) strerror(errno)); - - return -1; - - case 0: - /* - We are in child process, which will be IM-main: - - Restore default signal actions to let the IM-main work with - signals as he wishes; - - Call Manager::main(); - */ - - log_info("Angel: Manager process created successfully."); - - /* NOTE: sigaction() fails only if arguments are wrong. */ - - sigaction(SIGCHLD, &sa_chld_orig, NULL); - sigaction(SIGTERM, &sa_term_orig, NULL); - sigaction(SIGINT, &sa_int_orig, NULL); - sigaction(SIGHUP, &sa_hup_orig, NULL); - - log_info("Angel: executing Manager..."); - - return Manager::main(); - } - - /* Wait for signals. */ - - log_info("Angel: waiting for signals..."); - - while (child_status == CHILD_OK && shutdown_request_signo == 0) - sigsuspend(&wait_for_signals_mask); - - /* Exit if one of shutdown signals has been caught. */ - - if (shutdown_request_signo) - { - log_info("Angel: received shutdown signal (%d). Exiting...", - (int) shutdown_request_signo); - - return 0; - } - - /* Manager process died. Respawn it if it was a failure. */ - - if (child_status == CHILD_NEED_RESPAWN) - { - child_status= CHILD_OK; - - log_error("Angel: Manager exited abnormally (exit code: %d).", - (int) child_exit_code); - - log_info("Angel: sleeping 1 second..."); - - sleep(1); /* don't respawn too fast */ - - log_info("Angel: respawning Manager..."); - - continue; - } - - /* Delete IM-angel PID file. */ - - my_delete(Options::Daemon::angel_pid_file_name, MYF(0)); - - /* IM-angel finished. */ - - log_info("Angel: Manager exited normally. Exiting..."); - - return 0; - } -} - - -/************************************************************************/ -/** - Angel main function. - - @return - The function returns exit status for global main(): - 0 -- program completed successfully; - !0 -- error occurred. -*************************************************************************/ - -int Angel::main() -{ - log_info("Angel: started."); - - /* Open log file. */ - - if (open_log_file()) - return -1; - - /* Fork a new process. */ - - log_info("Angel: daemonizing..."); - - switch (fork()) { - case -1: - /* - This is the main Instance Manager process, fork() failed. - Log an error and bail out with error code. - */ - - log_error("fork() failed: %s.", (const char *) strerror(errno)); - return -1; - - case 0: - /* We are in child process. Continue Angel::main() execution. */ - - break; - - default: - /* - We are in the parent process. Return 0 so that parent exits - successfully. - */ - - log_info("Angel: exiting from the original process..."); - - return 0; - } - - /* Detach child from controlling tty. */ - - if (detach_process()) - return -1; - - /* Create PID file. */ - - if (create_pid_file()) - return -1; - - /* Start Angel main loop. */ - - return angel_main_loop(); -} - -#endif // __WIN__ diff --git a/server-tools/instance-manager/angel.h b/server-tools/instance-manager/angel.h deleted file mode 100644 index db21c250972..00000000000 --- a/server-tools/instance-manager/angel.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_ANGEL_H -#define INCLUDES_MYSQL_ANGEL_H - -#ifndef __WIN__ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include <my_global.h> - -class Angel -{ -public: - static int main(); -}; - -#endif // INCLUDES_MYSQL_ANGEL_H -#endif // __WIN__ diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc deleted file mode 100644 index f197f42d009..00000000000 --- a/server-tools/instance-manager/buffer.cc +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "buffer.h" -#include <m_string.h> - -const uint Buffer::BUFFER_INITIAL_SIZE= 4096; -const uint Buffer::MAX_BUFFER_SIZE= 16777216; - -/* - Puts the given string to the buffer. - - SYNOPSIS - append() - position start position in the buffer - string string to be put in the buffer - len_arg the length of the string. This way we can avoid some - strlens. - - DESCRIPTION - - The method puts a string into the buffer, starting from position . - In the case when the buffer is too small it reallocs the buffer. The - total size of the buffer is restricted with 16. - - RETURN - 0 - ok - 1 - got an error in reserve() -*/ - -int Buffer::append(size_t position, const char *string, size_t len_arg) -{ - if (reserve(position, len_arg)) - return 1; - - strnmov((char*) buffer + position, string, len_arg); - return 0; -} - - -/* - Checks whether the current buffer size is ok to put a string of the length - "len_arg" starting from "position" and reallocs it if no. - - SYNOPSIS - reserve() - position the number starting byte on the buffer to store a buffer - len_arg the length of the string. - - DESCRIPTION - - The method checks whether it is possible to put a string of the "len_arg" - length into the buffer, starting from "position" byte. In the case when the - buffer is too small it reallocs the buffer. The total size of the buffer is - restricted with 16 Mb. - - RETURN - 0 - ok - 1 - realloc error or we have come to the 16Mb barrier -*/ - -int Buffer::reserve(size_t position, size_t len_arg) -{ - if (position + len_arg >= MAX_BUFFER_SIZE) - goto err; - - if (position + len_arg >= buffer_size) - { - buffer= (uchar*) my_realloc(buffer, - min(MAX_BUFFER_SIZE, - max((uint) (buffer_size*1.5), - position + len_arg)), MYF(0)); - if (!(buffer)) - goto err; - buffer_size= (size_t) (buffer_size*1.5); - } - return 0; - -err: - error= 1; - return 1; -} - - -int Buffer::get_size() -{ - return (uint) buffer_size; -} - - -int Buffer::is_error() -{ - return error; -} diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h deleted file mode 100644 index 3bd7a714437..00000000000 --- a/server-tools/instance-manager/buffer.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_sys.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* - This class is a simple implementation of the buffer of varying size. - It is used to store MySQL client-server protocol packets. This is why - the maximum buffer size if 16Mb. (See internals manual section - 7. MySQL Client/Server Protocol) -*/ - -class Buffer -{ -private: - static const uint BUFFER_INITIAL_SIZE; - /* maximum buffer size is 16Mb */ - static const uint MAX_BUFFER_SIZE; - size_t buffer_size; - /* Error flag. Triggered if we get an error of some kind */ - int error; -public: - Buffer(size_t buffer_size_arg= BUFFER_INITIAL_SIZE) - :buffer_size(buffer_size_arg), error(0) - { - /* - As append() will invokes realloc() anyway, it's ok if malloc returns 0 - */ - if (!(buffer= (uchar*) my_malloc(buffer_size, MYF(0)))) - buffer_size= 0; - } - - ~Buffer() - { - my_free(buffer, MYF(0)); - } - -public: - uchar *buffer; - int get_size(); - int is_error(); - int append(size_t position, const char *string, size_t len_arg); - int reserve(size_t position, size_t len_arg); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */ diff --git a/server-tools/instance-manager/command.cc b/server-tools/instance-manager/command.cc deleted file mode 100644 index ba84285ead2..00000000000 --- a/server-tools/instance-manager/command.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "manager.h" -#include "command.h" - -Command::Command() - :guardian(Manager::get_guardian()), - instance_map(Manager::get_instance_map()) -{} - -Command::~Command() -{} - diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h deleted file mode 100644 index 25d8c9849e8..00000000000 --- a/server-tools/instance-manager/command.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/* Class responsible for allocation of IM commands. */ - -class Guardian; -class Instance_map; - -struct st_net; - -/* - Command - entry point for any command. - GangOf4: 'Command' design pattern -*/ - -class Command -{ -public: - Command(); - virtual ~Command(); - - /* - This operation incapsulates behaviour of the command. - - SYNOPSIS - net The network connection to the client. - connection_id Client connection ID - - RETURN - 0 On success - non 0 On error. Client error code is returned. - */ - virtual int execute(st_net *net, ulong connection_id) = 0; - -protected: - Guardian *guardian; - Instance_map *instance_map; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */ diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc deleted file mode 100644 index 56bd720b3e9..00000000000 --- a/server-tools/instance-manager/commands.cc +++ /dev/null @@ -1,1752 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "commands.h" - -#include <my_global.h> -#include <m_ctype.h> -#include <mysql.h> -#include <my_dir.h> - -#include "buffer.h" -#include "guardian.h" -#include "instance_map.h" -#include "log.h" -#include "manager.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" -#include "protocol.h" - -/************************************************************************** - {{{ Static functions. -**************************************************************************/ - -/** - modify_defaults_to_im_error -- a map of error codes of - mysys::modify_defaults_file() into Instance Manager error codes. -*/ - -static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES, - ER_ACCESS_OPTION_FILE }; - - -/** - Parse version number from the version string. - - SYNOPSIS - parse_version_number() - version_str - version - version_size - - DESCRIPTION - TODO - - TODO: Move this function to Instance_options and parse version number - only once. - - NOTE: This function is used only in SHOW INSTANCE STATUS statement at the - moment. -*/ - -static int parse_version_number(const char *version_str, char *version, - uint version_size) -{ - const char *start= version_str; - const char *end; - - // skip garbage - while (!my_isdigit(default_charset_info, *start)) - start++; - - end= start; - // skip digits and dots - while (my_isdigit(default_charset_info, *end) || *end == '.') - end++; - - if ((uint)(end - start) >= version_size) - return -1; - - strncpy(version, start, end-start); - version[end-start]= '\0'; - - return 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - -/************************************************************************** - Implementation of Instance_name. -**************************************************************************/ - -Instance_name::Instance_name(const LEX_STRING *name) -{ - str.str= str_buffer; - str.length= name->length; - - if (str.length > MAX_INSTANCE_NAME_SIZE - 1) - str.length= MAX_INSTANCE_NAME_SIZE - 1; - - strmake(str.str, name->str, str.length); -} - -/************************************************************************** - Implementation of Show_instances. -**************************************************************************/ - -/** - Implementation of SHOW INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instances::execute(st_net *net, ulong /* connection_id */) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net))) - return err_code; - - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instances::write_header(st_net *net) -{ - LIST name, state; - LEX_STRING name_field, state_field; - LIST *field_list; - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - field_list= list_add(NULL, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instances::write_data(st_net *net) -{ - my_bool err_status= FALSE; - - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - instance_map->lock(); - - while ((instance= iterator.next())) - { - Buffer send_buf; /* buffer for packets */ - size_t pos= 0; - - instance->lock(); - - const char *instance_name= instance->options.instance_name.str; - const char *state_name= instance->get_state_name(); - - if (store_to_protocol_packet(&send_buf, instance_name, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - err_status= TRUE; - } - - instance->unlock(); - - if (err_status) - break; - } - - instance_map->unlock(); - - return err_status ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Flush_instances. -**************************************************************************/ - -/** - Implementation of FLUSH INSTANCES statement. - - Possible error codes: - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Flush_instances::execute(st_net *net, ulong connection_id) -{ - int err_status= Manager::flush_instances(); - - if (err_status) - return err_status; - - return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0; -} - - -/************************************************************************** - Implementation of Instance_cmd. -**************************************************************************/ - -Instance_cmd::Instance_cmd(const LEX_STRING *instance_name_arg): - instance_name(instance_name_arg) -{ - /* - MT-NOTE: we can not make a search for Instance object here, - because it can dissappear after releasing the lock. - */ -} - - -/************************************************************************** - Implementation of Abstract_instance_cmd. -**************************************************************************/ - -Abstract_instance_cmd::Abstract_instance_cmd( - const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -int Abstract_instance_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - instance_map->lock(); - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - instance_map->unlock(); - - err_code= execute_impl(net, instance); - - instance->unlock(); - - if (!err_code) - err_code= send_ok_response(net, connection_id); - - return err_code; -} - - -/************************************************************************** - Implementation of Show_instance_status. -**************************************************************************/ - -Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE STATUS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_status::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_status::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_status::write_header(st_net *net) -{ - LIST name, state, version, version_number, mysqld_compatible; - LIST *field_list; - LEX_STRING name_field, state_field, version_field, - version_number_field, mysqld_compatible_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "instance_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - state_field.str= (char *) "state"; - state_field.length= DEFAULT_FIELD_LENGTH; - state.data= &state_field; - - version_field.str= (char *) "version"; - version_field.length= MAX_VERSION_LENGTH; - version.data= &version_field; - - version_number_field.str= (char *) "version_number"; - version_number_field.length= MAX_VERSION_LENGTH; - version_number.data= &version_number_field; - - mysqld_compatible_field.str= (char *) "mysqld_compatible"; - mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH; - mysqld_compatible.data= &mysqld_compatible_field; - - field_list= list_add(NULL, &mysqld_compatible); - field_list= list_add(field_list, &version); - field_list= list_add(field_list, &version_number); - field_list= list_add(field_list, &state); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_status::write_data(st_net *net, Instance *instance) -{ - Buffer send_buf; /* buffer for packets */ - char version_num_buf[MAX_VERSION_LENGTH]; - size_t pos= 0; - - const char *state_name= instance->get_state_name(); - const char *version_tag= "unknown"; - const char *version_num= "unknown"; - const char *mysqld_compatible_status= - instance->is_mysqld_compatible() ? "yes" : "no"; - - if (instance->options.mysqld_version) - { - if (parse_version_number(instance->options.mysqld_version, version_num_buf, - sizeof(version_num_buf))) - return ER_OUT_OF_RESOURCES; - - version_num= version_num_buf; - version_tag= instance->options.mysqld_version; - } - - if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) || - store_to_protocol_packet(&send_buf, state_name, &pos) || - store_to_protocol_packet(&send_buf, version_num, &pos) || - store_to_protocol_packet(&send_buf, version_tag, &pos) || - store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) || - my_net_write(net, send_buf.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_options. -**************************************************************************/ - -Show_instance_options::Show_instance_options( - const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE OPTIONS statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_options::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_options::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_options::write_header(st_net *net) -{ - LIST name, option; - LIST *field_list; - LEX_STRING name_field, option_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "option_name"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - option_field.str= (char *) "value"; - option_field.length= DEFAULT_FIELD_LENGTH; - option.data= &option_field; - - field_list= list_add(NULL, &option); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_options::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - if (store_to_protocol_packet(&send_buff, "instance_name", &pos) || - store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - /* Loop through the options. */ - - for (int i= 0; i < instance->options.get_num_options(); i++) - { - Named_value option= instance->options.get_option(i); - const char *option_value= option.get_value()[0] ? option.get_value() : ""; - - pos= 0; - - if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) || - store_to_protocol_packet(&send_buff, option_value, &pos) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - } - - return 0; -} - - -/************************************************************************** - Implementation of Start_instance. -**************************************************************************/ - -Start_instance::Start_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of START INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INSTANCE_MISCONFIGURED The instance configuration is invalid - ER_INSTANCE_ALREADY_STARTED The instance is already started - ER_CANNOT_START_INSTANCE The instance could not have been started - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Start_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_configured()) - return ER_INSTANCE_MISCONFIGURED; - - if (instance->is_active()) - return ER_INSTANCE_ALREADY_STARTED; - - if (instance->start_mysqld()) - return ER_CANNOT_START_INSTANCE; - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - return 0; -} - - -int Start_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, "Instance started")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Stop_instance. -**************************************************************************/ - -Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of STOP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - - TODO: as soon as this method operates only with Instance, we probably - should introduce a new method (execute_stop_instance()) in Instance and - just call it from here. -*/ - -int Stop_instance::execute_impl(st_net * /* net */, Instance *instance) -{ - if (!instance->is_active()) - return ER_INSTANCE_IS_NOT_STARTED; - - instance->set_state(Instance::STOPPED); - - return instance->stop_mysqld() ? ER_STOP_INSTANCE : 0; -} - - -int Stop_instance::send_ok_response(st_net *net, ulong connection_id) -{ - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Create_instance. -**************************************************************************/ - -Create_instance::Create_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - This operation initializes Create_instance object. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On error. -*/ - -bool Create_instance::init(const char **text) -{ - return options.init() || parse_args(text); -} - - -/** - This operation parses CREATE INSTANCE options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing instance options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Create_instance::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return FALSE; /* OK: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_value_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (options.add_element(&option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); - } -} - - -/** - Implementation of CREATE INSTANCE statement. - - Possible error codes: - ER_MALFORMED_INSTANCE_NAME Instance name is malformed - ER_CREATE_EXISTING_INSTANCE There is an instance with the given name - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Create_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Check that the name is valid and there is no instance with such name. */ - - if (!Instance::is_name_valid(get_instance_name())) - return ER_MALFORMED_INSTANCE_NAME; - - /* - NOTE: In order to prevent race condition, we should perform all operations - on under acquired lock. - */ - - instance_map->lock(); - - if (instance_map->find(get_instance_name())) - { - instance_map->unlock(); - return ER_CREATE_EXISTING_INSTANCE; - } - - if ((err_code= instance_map->create_instance(get_instance_name(), &options))) - { - instance_map->unlock(); - return err_code; - } - - instance= instance_map->find(get_instance_name()); - DBUG_ASSERT(instance); - - if ((err_code= create_instance_in_file(get_instance_name(), &options))) - { - instance_map->remove_instance(instance); /* instance is deleted here. */ - - instance_map->unlock(); - return err_code; - } - - /* - CREATE INSTANCE must not lead to start instance, even if it guarded. - - TODO: The problem however is that if Instance Manager restarts after - creating instance, the instance will be restarted (see also BUG#19718). - */ - - instance->set_state(Instance::STOPPED); - - /* That's all. */ - - instance_map->unlock(); - - /* Send the result. */ - - if (net_send_ok(net, connection_id, NULL)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Drop_instance. -**************************************************************************/ - -Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg) - :Instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of DROP INSTANCE statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_DROP_ACTIVE_INSTANCE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Drop_instance::execute(st_net *net, ulong connection_id) -{ - int err_code; - Instance *instance; - - /* Lock Guardian, then Instance_map. */ - - instance_map->lock(); - - /* Find an instance. */ - - instance= instance_map->find(get_instance_name()); - - if (!instance) - { - instance_map->unlock(); - return ER_BAD_INSTANCE_NAME; - } - - instance->lock(); - - /* Check that the instance is offline. */ - - if (instance->is_active()) - { - instance->unlock(); - instance_map->unlock(); - - return ER_DROP_ACTIVE_INSTANCE; - } - - /* Try to remove instance from the file. */ - - err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL, - get_instance_name()->str, MY_REMOVE_SECTION); - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not remove instance '%s' from defaults file (%s). " - "Original error code: %d.", - (const char *) get_instance_name()->str, - (const char *) Options::Main::config_file, - (int) err_code); - - instance->unlock(); - instance_map->unlock(); - - return modify_defaults_to_im_error[err_code]; - } - - /* Unlock the instance before destroy. */ - - instance->unlock(); - - /* - Remove instance from the instance map - (the instance will be also destroyed here). - */ - - instance_map->remove_instance(instance); - - /* Unlock the instance map. */ - - instance_map->unlock(); - - /* That's all: send ok. */ - - if (net_send_ok(net, connection_id, "Instance dropped")) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation for Show_instance_log. -**************************************************************************/ - -Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, - uint size_arg, uint offset_arg) - :Abstract_instance_cmd(instance_name_arg), - log_type(log_type_arg), - size(size_arg), - offset(offset_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OFFSET_ERROR We were requested to read negative number of - bytes from the log - ER_NO_SUCH_LOG The specified type of log is not available for - the given instance - ER_GUESS_LOGFILE IM wasn't able to figure out the log - placement, while it is enabled. Probably user - should specify the path to the logfile - explicitly. - ER_OPEN_LOGFILE Cannot open the logfile - ER_READ_FILE Cannot read the logfile - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= check_params(instance))) - return err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log::check_params(Instance *instance) -{ - const char *logpath= instance->options.logs[log_type]; - - /* Cannot read negative number of bytes. */ - - if (offset > size) - return ER_OFFSET_ERROR; - - /* Instance has no such log. */ - - if (logpath == NULL) - return ER_NO_SUCH_LOG; - - if (*logpath == '\0') - return ER_GUESS_LOGFILE; - - return 0; -} - - -int Show_instance_log::write_header(st_net *net) -{ - LIST name; - LIST *field_list; - LEX_STRING name_field; - - /* Create list of the fields to be passed to send_fields(). */ - - name_field.str= (char *) "Log"; - name_field.length= DEFAULT_FIELD_LENGTH; - - name.data= &name_field; - - field_list= list_add(NULL, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - size_t pos= 0; - - const char *logpath= instance->options.logs[log_type]; - File fd; - - size_t buff_size; - size_t read_len; - - MY_STAT file_stat; - Buffer read_buff; - - if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) <= 0) - return ER_OPEN_LOGFILE; - - /* my_fstat doesn't use the flag parameter */ - if (my_fstat(fd, &file_stat, MYF(0))) - { - close(fd); - return ER_OUT_OF_RESOURCES; - } - - /* calculate buffer size */ - buff_size= (size - offset); - - read_buff.reserve(0, buff_size); - - /* read in one chunk */ - read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); - - if ((read_len= my_read(fd, read_buff.buffer, buff_size, MYF(0))) == - MY_FILE_ERROR) - { - close(fd); - return ER_READ_FILE; - } - - close(fd); - - if (store_to_protocol_packet(&send_buff, (char*) read_buff.buffer, &pos, - read_len) || - my_net_write(net, send_buff.buffer, pos)) - { - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Show_instance_log_files. -**************************************************************************/ - -Show_instance_log_files::Show_instance_log_files - (const LEX_STRING *instance_name_arg) - :Abstract_instance_cmd(instance_name_arg) -{ -} - - -/** - Implementation of SHOW INSTANCE LOG FILES statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Show_instance_log_files::execute_impl(st_net *net, Instance *instance) -{ - int err_code; - - if ((err_code= write_header(net)) || - (err_code= write_data(net, instance))) - return err_code; - - return 0; -} - - -int Show_instance_log_files::send_ok_response(st_net *net, - ulong /* connection_id */) -{ - if (send_eof(net) || net_flush(net)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -int Show_instance_log_files::write_header(st_net *net) -{ - LIST name, path, size; - LIST *field_list; - LEX_STRING name_field, path_field, size_field; - - /* Create list of the fileds to be passed to send_fields(). */ - - name_field.str= (char *) "Logfile"; - name_field.length= DEFAULT_FIELD_LENGTH; - name.data= &name_field; - - path_field.str= (char *) "Path"; - path_field.length= DEFAULT_FIELD_LENGTH; - path.data= &path_field; - - size_field.str= (char *) "File size"; - size_field.length= DEFAULT_FIELD_LENGTH; - size.data= &size_field; - - field_list= list_add(NULL, &size); - field_list= list_add(field_list, &path); - field_list= list_add(field_list, &name); - - return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0; -} - - -int Show_instance_log_files::write_data(st_net *net, Instance *instance) -{ - Buffer send_buff; /* buffer for packets */ - - /* - We have alike structure in instance_options.cc. We use such to be able - to loop through the options, which we need to handle in some common way. - */ - struct log_files_st - { - const char *name; - const char *value; - } logs[]= - { - {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]}, - {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]}, - {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]}, - {NULL, NULL} - }; - struct log_files_st *log_files; - - for (log_files= logs; log_files->name; log_files++) - { - if (!log_files->value) - continue; - - struct stat file_stat; - /* - Save some more space for the log file names. In fact all - we need is strlen("GENERAL_LOG") + 1 - */ - enum { LOG_NAME_BUFFER_SIZE= 20 }; - char buff[LOG_NAME_BUFFER_SIZE]; - - size_t pos= 0; - - const char *log_path= ""; - const char *log_size= "0"; - - if (!stat(log_files->value, &file_stat) && - MY_S_ISREG(file_stat.st_mode)) - { - int10_to_str(file_stat.st_size, buff, 10); - - log_path= log_files->value; - log_size= buff; - } - - if (store_to_protocol_packet(&send_buff, log_files->name, &pos) || - store_to_protocol_packet(&send_buff, log_path, &pos) || - store_to_protocol_packet(&send_buff, log_size, &pos) || - my_net_write(net, send_buff.buffer, pos)) - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/************************************************************************** - Implementation of Abstract_option_cmd. -**************************************************************************/ - -/** - Instance_options_list -- a data class representing a list of options for - some instance. -*/ - -class Instance_options_list -{ -public: - Instance_options_list(const LEX_STRING *instance_name_arg); - -public: - bool init(); - - const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -public: - /* - This member is set and used only in Abstract_option_cmd::execute_impl(). - Normally it is not used (and should not). - - The problem is that construction and execution of commands are made not - in one transaction (not under one lock session). So, we can not initialize - instance in constructor and use it in execution. - */ - Instance *instance; - - Named_value_arr options; - -private: - Instance_name instance_name; -}; - - -/**************************************************************************/ - -Instance_options_list::Instance_options_list( - const LEX_STRING *instance_name_arg) - :instance(NULL), - instance_name(instance_name_arg) -{ -} - - -bool Instance_options_list::init() -{ - return options.init(); -} - - -/**************************************************************************/ - -C_MODE_START - -static uchar* get_item_key(const uchar* item, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance_options_list *lst= (const Instance_options_list *) item; - *len= lst->get_instance_name()->length; - return (uchar *) lst->get_instance_name()->str; -} - -static void delete_item(void *item) -{ - delete (Instance_options_list *) item; -} - -C_MODE_END - - -/**************************************************************************/ - -Abstract_option_cmd::Abstract_option_cmd() - :initialized(FALSE) -{ -} - - -Abstract_option_cmd::~Abstract_option_cmd() -{ - if (initialized) - hash_free(&instance_options_map); -} - - -bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name, - Named_value *option) -{ - Instance_options_list *lst= get_instance_options_list(instance_name); - - if (!lst) - return TRUE; - - lst->options.add_element(option); - - return FALSE; -} - - -bool Abstract_option_cmd::init(const char **text) -{ - static const int INITIAL_HASH_SIZE= 16; - - if (hash_init(&instance_options_map, default_charset_info, - INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0)) - return TRUE; - - if (parse_args(text)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -/** - Correct the option file. The "skip" option is used to remove the found - option. - - SYNOPSIS - Abstract_option_cmd::correct_file() - skip Skip the option, being searched while writing the result file. - That is, to delete it. - - RETURN - 0 Success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_ACCESS_OPTION_FILE Cannot access the option file -*/ - -int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option, - bool skip) -{ - int err_code= modify_defaults_file(Options::Main::config_file, - option->get_name(), - option->get_value(), - instance->get_name()->str, - skip); - - DBUG_ASSERT(err_code >= 0 && err_code <= 2); - - if (err_code) - { - log_error("Can not modify option (%s) in defaults file (%s). " - "Original error code: %d.", - (const char *) option->get_name(), - (const char *) Options::Main::config_file, - (int) err_code); - } - - return modify_defaults_to_im_error[err_code]; -} - - -/** - Lock Instance Map and call execute_impl(). - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance with the given name does not exist - ER_INCOMPATIBLE_OPTION The specified option can not be set for - mysqld-compatible instance - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Abstract_option_cmd::execute(st_net *net, ulong connection_id) -{ - int err_code; - - instance_map->lock(); - - err_code= execute_impl(net, connection_id); - - instance_map->unlock(); - - return err_code; -} - - -Instance_options_list * -Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name) -{ - Instance_options_list *lst= - (Instance_options_list *) hash_search(&instance_options_map, - (uchar *) instance_name->str, - instance_name->length); - - if (!lst) - { - lst= new Instance_options_list(instance_name); - - if (!lst) - return NULL; - - if (lst->init() || my_hash_insert(&instance_options_map, (uchar *) lst)) - { - delete lst; - return NULL; - } - } - - return lst; -} - - -/** - Skeleton implementation of option-management command. - - MT-NOTE: Instance Map is locked before calling this operation. -*/ -int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id) -{ - int err_code= 0; - - /* Check that all the specified instances exist and are offline. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - bool instance_is_active; - - lst->instance= instance_map->find(lst->get_instance_name()); - - if (!lst->instance) - return ER_BAD_INSTANCE_NAME; - - lst->instance->lock(); - instance_is_active= lst->instance->is_active(); - lst->instance->unlock(); - - if (instance_is_active) - return ER_INSTANCE_IS_ACTIVE; - } - - /* Perform command-specific (SET/UNSET) actions. */ - - for (uint i= 0; i < instance_options_map.records; ++i) - { - Instance_options_list *lst= - (Instance_options_list *) hash_element(&instance_options_map, i); - - lst->instance->lock(); - - for (int j= 0; j < lst->options.get_size(); ++j) - { - Named_value option= lst->options.get_element(j); - err_code= process_option(lst->instance, &option); - - if (err_code) - break; - } - - lst->instance->unlock(); - - if (err_code) - break; - } - - if (err_code == 0) - net_send_ok(net, connection_id, NULL); - - return err_code; -} - - -/************************************************************************** - Implementation of Set_option. -**************************************************************************/ - -/** - This operation parses SET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Set_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str= NULL; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - /* Looking for equal sign. */ - - skip_spaces(text); - - if (**text == '=') - { - ++(*text); /* Skip an equal sign. */ - - /* Looking for option value. */ - - skip_spaces(text); - - if (!**text) - return TRUE; /* Syntax error: EOS when option value expected. */ - - if (**text != '\'' && **text != '"') - { - /* Option value is a simple token. */ - - LEX_STRING option_value; - - get_word(text, &option_value.length, ALPHANUM); - - if (option_value.length == 0) - return TRUE; /* internal parser error. */ - - option_value.str= (char *) *text; - *text+= option_value.length; - - if (!(option_value_str= Named_value::alloc_str(&option_value))) - return TRUE; /* out of memory during parsing. */ - } - else - { - /* Option value is a string. */ - - if (parse_option_value(*text, &len, &option_value_str)) - return TRUE; /* Syntax error: invalid string specification. */ - - *text+= len; - } - } - - if (!option_value_str) - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - return TRUE; /* out of memory during parsing. */ - } - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - { - Named_value::free_str(&option_name_str); - return TRUE; /* out of memory during parsing. */ - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -int Set_option::process_option(Instance *instance, Named_value *option) -{ - /* Check that the option is valid. */ - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option->get_name())) - { - log_error("IM-option (%s) can not be used " - "in the configuration of mysqld-compatible instance (%s).", - (const char *) option->get_name(), - (const char *) instance->get_name()->str); - return ER_INCOMPATIBLE_OPTION; - } - - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, FALSE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - if (instance->options.set_option(option)) - return ER_OUT_OF_RESOURCES; - - return 0; -} - - -/************************************************************************** - Implementation of Unset_option. -**************************************************************************/ - -/** - This operation parses UNSET options. - - SYNOPSIS - text [IN/OUT] a pointer to the text containing options. - - RETURN - FALSE On success. - TRUE On syntax error. -*/ - -bool Unset_option::parse_args(const char **text) -{ - size_t len; - - /* Check if we have something (and trim leading spaces). */ - - get_word(text, &len, NONSPACE); - - if (len == 0) - return TRUE; /* Syntax error: no option. */ - - /* Main parsing loop. */ - - while (TRUE) - { - LEX_STRING instance_name; - LEX_STRING option_name; - char *option_name_str; - char *option_value_str; - - /* Looking for instance name. */ - - get_word(text, &instance_name.length, ALPHANUM); - - if (instance_name.length == 0) - return TRUE; /* Syntax error: instance name expected. */ - - instance_name.str= (char *) *text; - *text+= instance_name.length; - - skip_spaces(text); - - /* Check the the delimiter is a dot. */ - - if (**text != '.') - return TRUE; /* Syntax error: dot expected. */ - - ++(*text); /* Skip a dot. */ - - /* Looking for option name. */ - - get_word(text, &option_name.length, OPTION_NAME); - - if (option_name.length == 0) - return TRUE; /* Syntax error: option name expected. */ - - option_name.str= (char *) *text; - *text+= option_name.length; - - if (!(option_name_str= Named_value::alloc_str(&option_name))) - return TRUE; /* out of memory during parsing. */ - - { - LEX_STRING empty_str= { C_STRING_WITH_LEN("") }; - - if (!(option_value_str= Named_value::alloc_str(&empty_str))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - } - - { - Named_value option(option_name_str, option_value_str); - - if (add_option(&instance_name, &option)) - { - option.free(); - return TRUE; /* out of memory during parsing. */ - } - } - - skip_spaces(text); - - if (!**text) - return FALSE; /* OK: end of options. */ - - if (**text != ',') - return TRUE; /* Syntax error: comma expected. */ - - ++(*text); /* Skip a comma. */ - } -} - - -/** - Implementation of UNSET statement. - - Possible error codes: - ER_BAD_INSTANCE_NAME The instance name specified is not valid - ER_INSTANCE_IS_ACTIVE The specified instance is active - ER_OUT_OF_RESOURCES Not enough resources to complete the operation -*/ - -int Unset_option::process_option(Instance *instance, Named_value *option) -{ - /* Update the configuration file. */ - - int err_code= correct_file(instance, option, TRUE); - - if (err_code) - return err_code; - - /* Update the internal cache. */ - - instance->options.unset_option(option->get_name()); - - return 0; -} - - -/************************************************************************** - Implementation of Syntax_error. -**************************************************************************/ - -int Syntax_error::execute(st_net * /* net */, ulong /* connection_id */) -{ - return ER_SYNTAX_ERROR; -} diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h deleted file mode 100644 index 5c2b2f9bbb7..00000000000 --- a/server-tools/instance-manager/commands.h +++ /dev/null @@ -1,393 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> -#include <hash.h> - -#include "command.h" -#include "instance.h" -#include "parse.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/** - Print all instances of this instance manager. - Grammar: SHOW INSTANCES -*/ - -class Show_instances: public Command -{ -public: - Show_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net); -}; - - -/** - Reread configuration file and refresh internal cache. - Grammar: FLUSH INSTANCES -*/ - -class Flush_instances: public Command -{ -public: - Flush_instances() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - - -/** - Base class for Instance-specific commands - (commands that operate on one instance). - - Instance_cmd extends Command class by: - - an attribute for storing instance name; - - code to initialize instance name in constructor; - - an accessor to get instance name. -*/ - -class Instance_cmd : public Command -{ -public: - Instance_cmd(const LEX_STRING *instance_name_arg); - -protected: - inline const LEX_STRING *get_instance_name() const - { - return instance_name.get_str(); - } - -private: - Instance_name instance_name; -}; - - -/** - Abstract class for Instance-specific commands. - - Abstract_instance_cmd extends Instance_cmd by providing a common - framework for writing command-implementations. Basically, the class - implements Command::execute() pure virtual function in the following - way: - - Lock Instance_map; - - Get an instance by name. Return an error, if there is no such - instance; - - Lock the instance; - - Unlock Instance_map; - - Call execute_impl(), which should be implemented in derived class; - - Unlock the instance; - - Send response to the client and return error status. -*/ - -class Abstract_instance_cmd: public Instance_cmd -{ -public: - Abstract_instance_cmd(const LEX_STRING *instance_name_arg); - -public: - virtual int execute(st_net *net, ulong connection_id); - -protected: - /** - This operation is intended to contain command-specific implementation. - - MT-NOTE: this operation is called under acquired Instance's lock. - */ - virtual int execute_impl(st_net *net, Instance *instance) = 0; - - /** - This operation is invoked on successful return of execute_impl() and is - intended to send closing data. - - MT-NOTE: this operation is called under released Instance's lock. - */ - virtual int send_ok_response(st_net *net, ulong connection_id) = 0; -}; - - -/** - Print status of an instance. - Grammar: SHOW INSTANCE STATUS <instance_name> -*/ - -class Show_instance_status: public Abstract_instance_cmd -{ -public: - Show_instance_status(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Print options of chosen instance. - Grammar: SHOW INSTANCE OPTIONS <instance_name> -*/ - -class Show_instance_options: public Abstract_instance_cmd -{ -public: - Show_instance_options(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Start an instance. - Grammar: START INSTANCE <instance_name> -*/ - -class Start_instance: public Abstract_instance_cmd -{ -public: - Start_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Stop an instance. - Grammar: STOP INSTANCE <instance_name> -*/ - -class Stop_instance: public Abstract_instance_cmd -{ -public: - Stop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); -}; - - -/** - Create an instance. - Grammar: CREATE INSTANCE <instance_name> [<options>] -*/ - -class Create_instance: public Instance_cmd -{ -public: - Create_instance(const LEX_STRING *instance_name_arg); - -public: - bool init(const char **text); - -protected: - virtual int execute(st_net *net, ulong connection_id); - -private: - bool parse_args(const char **text); - -private: - Named_value_arr options; -}; - - -/** - Drop an instance. - Grammar: DROP INSTANCE <instance_name> - - Operation is permitted only if the instance is stopped. On successful - completion the instance section is removed from config file and the instance - is removed from the instance map. -*/ - -class Drop_instance: public Instance_cmd -{ -public: - Drop_instance(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute(st_net *net, ulong connection_id); -}; - - -/** - Print requested part of the log. - Grammar: - SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[, offset_from_end] -*/ - -class Show_instance_log: public Abstract_instance_cmd -{ -public: - Show_instance_log(const LEX_STRING *instance_name_arg, - Log_type log_type_arg, uint size_arg, uint offset_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int check_params(Instance *instance); - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); - -private: - Log_type log_type; - uint size; - uint offset; -}; - - -/** - Shows the list of the log files, used by an instance. - Grammar: SHOW <instance_name> LOG FILES -*/ - -class Show_instance_log_files: public Abstract_instance_cmd -{ -public: - Show_instance_log_files(const LEX_STRING *instance_name_arg); - -protected: - virtual int execute_impl(st_net *net, Instance *instance); - virtual int send_ok_response(st_net *net, ulong connection_id); - -private: - int write_header(st_net *net); - int write_data(st_net *net, Instance *instance); -}; - - -/** - Abstract class for option-management commands. -*/ - -class Instance_options_list; - -class Abstract_option_cmd: public Command -{ -public: - ~Abstract_option_cmd(); - -public: - bool add_option(const LEX_STRING *instance_name, Named_value *option); - -public: - bool init(const char **text); - - virtual int execute(st_net *net, ulong connection_id); - -protected: - Abstract_option_cmd(); - - int correct_file(Instance *instance, Named_value *option, bool skip); - -protected: - virtual bool parse_args(const char **text) = 0; - virtual int process_option(Instance *instance, Named_value *option) = 0; - -private: - Instance_options_list * - get_instance_options_list(const LEX_STRING *instance_name); - - int execute_impl(st_net *net, ulong connection_id); - -private: - HASH instance_options_map; - bool initialized; -}; - - -/** - Set an option for the instance. - Grammar: SET instance_name.option[=option_value][, ...] -*/ - -class Set_option: public Abstract_option_cmd -{ -public: - Set_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Remove option of the instance. - Grammar: UNSET instance_name.option[, ...] -*/ - -class Unset_option: public Abstract_option_cmd -{ -public: - Unset_option() - { } - -protected: - virtual bool parse_args(const char **text); - virtual int process_option(Instance *instance, Named_value *option); -}; - - -/** - Syntax error command. - - This command is issued if parser reported a syntax error. We need it to - distinguish between syntax error and internal parser error. E.g. parsing - failed because we hadn't had enought memory. In the latter case the parser - just returns NULL. -*/ - -class Syntax_error: public Command -{ -public: - Syntax_error() - { } - -public: - int execute(st_net *net, ulong connection_id); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */ diff --git a/server-tools/instance-manager/exit_codes.h b/server-tools/instance-manager/exit_codes.h deleted file mode 100644 index 1609debd8f9..00000000000 --- a/server-tools/instance-manager/exit_codes.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H - -/* - Copyright (C) 2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - This file contains a list of exit codes, which are used when Instance - Manager is working in user-management mode. -*/ - -const int ERR_OK = 0; - -const int ERR_OUT_OF_MEMORY = 1; -const int ERR_INVALID_USAGE = 2; -const int ERR_INTERNAL_ERROR = 3; -const int ERR_IO_ERROR = 4; -const int ERR_PASSWORD_FILE_CORRUPTED = 5; -const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6; - -const int ERR_CAN_NOT_READ_USER_NAME = 10; -const int ERR_CAN_NOT_READ_PASSWORD = 11; -const int ERR_USER_ALREADY_EXISTS = 12; -const int ERR_USER_NOT_FOUND = 13; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc deleted file mode 100644 index b49b0ec0a00..00000000000 --- a/server-tools/instance-manager/guardian.cc +++ /dev/null @@ -1,496 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "guardian.h" -#include <string.h> -#include <sys/types.h> -#include <signal.h> - -#include "instance.h" -#include "instance_map.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "options.h" - - -/************************************************************************* - {{{ Constructor & destructor. -*************************************************************************/ - -/** - Guardian constructor. - - SYNOPSIS - Guardian() - thread_registry_arg - instance_map_arg - - DESCRIPTION - Nominal contructor intended for assigning references and initialize - trivial objects. Real initialization is made by init() method. -*/ - -Guardian::Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg) - :shutdown_requested(FALSE), - stopped(FALSE), - thread_registry(thread_registry_arg), - instance_map(instance_map_arg) -{ - pthread_mutex_init(&LOCK_guardian, 0); - pthread_cond_init(&COND_guardian, 0); -} - - -Guardian::~Guardian() -{ - /* - NOTE: it's necessary to synchronize here, because Guiardian thread can be - still alive an hold the mutex (because it is detached and we have no - control over it). - */ - - lock(); - unlock(); - - pthread_mutex_destroy(&LOCK_guardian); - pthread_cond_destroy(&COND_guardian); -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Send request to stop Guardian. - - SYNOPSIS - request_shutdown() -*/ - -void Guardian::request_shutdown() -{ - stop_instances(); - - lock(); - shutdown_requested= TRUE; - unlock(); - - ping(); -} - - -/** - Process an instance. - - SYNOPSIS - process_instance() - instance a pointer to the instance for processing - - MT-NOTE: - - the given instance must be locked before calling this operation; - - Guardian must be locked before calling this operation. -*/ - -void Guardian::process_instance(Instance *instance) -{ - int restart_retry= 100; - time_t current_time= time(NULL); - - if (instance->get_state() == Instance::STOPPING) - { - /* This brach is executed during shutdown. */ - - /* This returns TRUE if and only if an instance was stopped for sure. */ - if (instance->is_crashed()) - { - log_info("Guardian: '%s' stopped.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else if ((uint) (current_time - instance->last_checked) >= - instance->options.get_shutdown_delay()) - { - log_info("Guardian: '%s' hasn't stopped within %d secs.", - (const char *) instance->get_name()->str, - (int) instance->options.get_shutdown_delay()); - - instance->kill_mysqld(SIGKILL); - - log_info("Guardian: pretend that '%s' is killed.", - (const char *) instance->get_name()->str); - - instance->set_state(Instance::STOPPED); - } - else - { - log_info("Guardian: waiting for '%s' to stop (%d secs left).", - (const char *) instance->get_name()->str, - (int) (instance->options.get_shutdown_delay() - - current_time + instance->last_checked)); - } - - return; - } - - if (instance->is_mysqld_running()) - { - /* The instance can be contacted on it's port */ - - /* If STARTING also check that pidfile has been created */ - if (instance->get_state() == Instance::STARTING && - instance->options.load_pid() == 0) - { - /* Pid file not created yet, don't go to STARTED state yet */ - } - else if (instance->get_state() != Instance::STARTED) - { - /* clear status fields */ - log_info("Guardian: '%s' is running, set state to STARTED.", - (const char *) instance->options.instance_name.str); - instance->reset_stat(); - instance->set_state(Instance::STARTED); - } - } - else - { - switch (instance->get_state()) { - case Instance::NOT_STARTED: - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - - /* NOTE: set state to STARTING _before_ start() is called. */ - instance->set_state(Instance::STARTING); - instance->last_checked= current_time; - - instance->start_mysqld(); - - return; - - case Instance::STARTED: /* fallthrough */ - case Instance::STARTING: /* let the instance start or crash */ - if (!instance->is_crashed()) - return; - - instance->crash_moment= current_time; - instance->last_checked= current_time; - instance->set_state(Instance::JUST_CRASHED); - /* fallthrough -- restart an instance immediately */ - - case Instance::JUST_CRASHED: - if (current_time - instance->crash_moment <= 2) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - log_info("Guardian: starting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - instance->set_state(Instance::CRASHED); - - return; - - case Instance::CRASHED: /* just regular restarts */ - if ((ulong) (current_time - instance->last_checked) <= - (ulong) Options::Main::monitoring_interval) - return; - - if (instance->restart_counter < restart_retry) - { - if (instance->is_crashed()) - { - instance->start_mysqld(); - instance->last_checked= current_time; - - log_info("Guardian: restarting '%s'...", - (const char *) instance->options.instance_name.str); - } - } - else - { - log_info("Guardian: can not start '%s'. " - "Abandoning attempts to (re)start it", - (const char *) instance->options.instance_name.str); - - instance->set_state(Instance::CRASHED_AND_ABANDONED); - } - - return; - - case Instance::CRASHED_AND_ABANDONED: - return; /* do nothing */ - - default: - DBUG_ASSERT(0); - } - } -} - - -/** - Main function of Guardian thread. - - SYNOPSIS - run() - - DESCRIPTION - Check for all guarded instances and restart them if needed. -*/ - -void Guardian::run() -{ - struct timespec timeout; - - log_info("Guardian: started."); - - thread_registry->register_thread(&thread_info); - - /* Loop, until all instances were shut down at the end. */ - - while (true) - { - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - bool all_instances_stopped= TRUE; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - process_instance(instance); - - if (instance->get_state() != Instance::STOPPED) - all_instances_stopped= FALSE; - - instance->unlock(); - } - - instance_map->unlock(); - - lock(); - - if (shutdown_requested && all_instances_stopped) - { - log_info("Guardian: all guarded mysqlds stopped."); - - stopped= TRUE; - unlock(); - break; - } - - set_timespec(timeout, Options::Main::monitoring_interval); - - thread_registry->cond_timedwait(&thread_info, &COND_guardian, - &LOCK_guardian, &timeout); - unlock(); - } - - log_info("Guardian: stopped."); - - /* Now, when the Guardian is stopped we can stop the IM. */ - - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - - log_info("Guardian: finished."); -} - - -/** - Return the value of stopped flag. -*/ - -bool Guardian::is_stopped() -{ - int var; - - lock(); - var= stopped; - unlock(); - - return var; -} - - -/** - Wake up Guardian thread. - - MT-NOTE: though usually the mutex associated with condition variable should - be acquired before signalling the variable, here this is not needed. - Signalling under locked mutex is used to avoid lost signals. In the current - logic however locking mutex does not guarantee that the signal will not be - lost. -*/ - -void Guardian::ping() -{ - pthread_cond_signal(&COND_guardian); -} - - -/** - Prepare list of instances. - - SYNOPSIS - init() - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -void Guardian::init() -{ - Instance *instance; - Instance_map::Iterator iterator(instance_map); - - while ((instance= iterator.next())) - { - instance->lock(); - - instance->reset_stat(); - instance->set_state(Instance::NOT_STARTED); - - instance->unlock(); - } -} - - -/** - An internal method which is called at shutdown to unregister instances and - attempt to stop them if requested. - - SYNOPSIS - stop_instances() - - DESCRIPTION - Loops through the guarded_instances list and prepares them for shutdown. - For each instance we issue a stop command and change the state - accordingly. - - NOTE - Guardian object should be locked by the caller. - -*/ - -void Guardian::stop_instances() -{ - static const int NUM_STOP_ATTEMPTS = 100; - - Instance_map::Iterator instances_it(instance_map); - Instance *instance; - - instance_map->lock(); - - while ((instance= instances_it.next())) - { - instance->lock(); - - if (!instance->is_guarded() || - instance->get_state() == Instance::STOPPED) - { - instance->unlock(); - continue; - } - - /* - If instance is running or was running (and now probably hanging), - request stop. - */ - - if (instance->is_mysqld_running() || - instance->get_state() == Instance::STARTED) - { - instance->set_state(Instance::STOPPING); - instance->last_checked= time(NULL); - } - else - { - /* Otherwise mark it as STOPPED. */ - instance->set_state(Instance::STOPPED); - } - - /* Request mysqld to stop. */ - - bool instance_stopped= FALSE; - - for (int cur_attempt= 0; cur_attempt < NUM_STOP_ATTEMPTS; ++cur_attempt) - { - if (!instance->kill_mysqld(SIGTERM)) - { - instance_stopped= TRUE; - break; - } - - if (!instance->is_active()) - { - instance_stopped= TRUE; - break; - } - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } - - /* - Abort if we failed to stop mysqld instance. That should not happen, - but if it happened, we don't know what to do and prefer to have clear - failure with coredump. - */ - - DBUG_ASSERT(instance_stopped); - - instance->unlock(); - } - - instance_map->unlock(); -} - - -/** - Lock Guardian. -*/ - -void Guardian::lock() -{ - pthread_mutex_lock(&LOCK_guardian); -} - - -/** - Unlock Guardian. -*/ - -void Guardian::unlock() -{ - pthread_mutex_unlock(&LOCK_guardian); -} diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h deleted file mode 100644 index d78058a6fc5..00000000000 --- a/server-tools/instance-manager/guardian.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#include <my_global.h> -#include <my_sys.h> -#include <my_list.h> - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance; -class Instance_map; -class Thread_registry; - -/** - The guardian thread is responsible for monitoring and restarting of guarded - instances. -*/ - -class Guardian: public Thread -{ -public: - Guardian(Thread_registry *thread_registry_arg, - Instance_map *instance_map_arg); - ~Guardian(); - - void init(); - -public: - void request_shutdown(); - - bool is_stopped(); - - void lock(); - void unlock(); - - void ping(); - -protected: - virtual void run(); - -private: - void stop_instances(); - - void process_instance(Instance *instance); - -private: - /* - LOCK_guardian protectes the members in this section: - - shutdown_requested; - - stopped; - - Also, it is used for COND_guardian. - */ - pthread_mutex_t LOCK_guardian; - - /* - Guardian's main loop waits on this condition. So, it should be signalled - each time, when instance state has been changed and we want Guardian to - wake up. - - TODO: Change this to having data-scoped conditions, i.e. conditions, - which indicate that some data has been changed. - */ - pthread_cond_t COND_guardian; - - /* - This variable is set to TRUE, when Manager thread is shutting down. - The flag is used by Guardian thread to understand that it's time to - finish. - */ - bool shutdown_requested; - - /* - This flag is set to TRUE on shutdown by Guardian thread, when all guarded - mysqlds are stopped. - - The flag is used in the Manager thread to wait for Guardian to stop all - mysqlds. - */ - bool stopped; - - Thread_info thread_info; - Thread_registry *thread_registry; - Instance_map *instance_map; - -private: - Guardian(const Guardian &); - Guardian&operator =(const Guardian &); -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */ diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc deleted file mode 100644 index 1ad728d40eb..00000000000 --- a/server-tools/instance-manager/instance.cc +++ /dev/null @@ -1,944 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include <my_global.h> -#include <mysql.h> - -#include <signal.h> -#ifndef __WIN__ -#include <sys/wait.h> -#endif - -#include "manager.h" -#include "guardian.h" -#include "instance.h" -#include "log.h" -#include "mysql_manager_error.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" -#include "instance_map.h" - - -/************************************************************************* - {{{ Platform-specific functions. -*************************************************************************/ - -#ifndef __WIN__ -typedef pid_t My_process_info; -#else -typedef PROCESS_INFORMATION My_process_info; -#endif - -/* - Wait for an instance - - SYNOPSIS - wait_process() - pi Pointer to the process information structure - (platform-dependent). - - RETURN - 0 - Success - 1 - Error -*/ - -#ifndef __WIN__ -static int wait_process(My_process_info *pi) -{ - /* - Here we wait for the child created. This process differs for systems - running LinuxThreads and POSIX Threads compliant systems. This is because - according to POSIX we could wait() for a child in any thread of the - process. While LinuxThreads require that wait() is called by the thread, - which created the child. - On the other hand we could not expect mysqld to return the pid, we - got in from fork(), to wait4() fucntion when running on LinuxThreads. - This is because MySQL shutdown thread is not the one, which was created - by our fork() call. - So basically we have two options: whether the wait() call returns only in - the creator thread, but we cannot use waitpid() since we have no idea - which pid we should wait for (in fact it should be the pid of shutdown - thread, but we don't know this one). Or we could use waitpid(), but - couldn't use wait(), because it could return in any wait() in the program. - */ - - if (Manager::is_linux_threads()) - wait(NULL); /* LinuxThreads were detected */ - else - waitpid(*pi, NULL, 0); - - return 0; -} -#else -static int wait_process(My_process_info *pi) -{ - /* Wait until child process exits. */ - WaitForSingleObject(pi->hProcess, INFINITE); - - DWORD exitcode; - ::GetExitCodeProcess(pi->hProcess, &exitcode); - - /* Close process and thread handles. */ - CloseHandle(pi->hProcess); - CloseHandle(pi->hThread); - - /* - GetExitCodeProces returns zero on failure. We should revert this value - to report an error. - */ - return (!exitcode); -} -#endif - -/* - Launch an instance - - SYNOPSIS - start_process() - instance_options Pointer to the options of the instance to be - launched. - pi Pointer to the process information structure - (platform-dependent). - - RETURN - FALSE - Success - TRUE - Cannot create an instance -*/ - -#ifndef __WIN__ -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ -#ifndef __QNX__ - *pi= fork(); -#else - /* - On QNX one cannot use fork() in multithreaded environment and we - should use spawn() or one of it's siblings instead. - Here we use spawnv(), which is a combination of fork() and execv() - in one call. It returns the pid of newly created process (>0) or -1 - */ - *pi= spawnv(P_NOWAIT, instance_options->mysqld_path, instance_options->argv); -#endif - - switch (*pi) { - case 0: /* never happens on QNX */ - execv(instance_options->mysqld_path.str, instance_options->argv); - /* exec never returns */ - exit(1); - case -1: - log_error("Instance '%s': can not start mysqld: fork() failed.", - (const char *) instance_options->instance_name.str); - return TRUE; - } - - return FALSE; -} -#else -static bool start_process(Instance_options *instance_options, - My_process_info *pi) -{ - STARTUPINFO si; - - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb= sizeof(STARTUPINFO); - ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); - - int cmdlen= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - cmdlen+= (uint) strlen(instance_options->argv[i]) + 3; - cmdlen++; /* make room for the null */ - - char *cmdline= new char[cmdlen]; - if (cmdline == NULL) - return TRUE; - - cmdline[0]= 0; - for (int i= 0; instance_options->argv[i] != 0; i++) - { - strcat(cmdline, "\""); - strcat(cmdline, instance_options->argv[i]); - strcat(cmdline, "\" "); - } - - /* Start the child process */ - BOOL result= - CreateProcess(NULL, /* Put it all in cmdline */ - cmdline, /* Command line */ - NULL, /* Process handle not inheritable */ - NULL, /* Thread handle not inheritable */ - FALSE, /* Set handle inheritance to FALSE */ - 0, /* No creation flags */ - NULL, /* Use parent's environment block */ - NULL, /* Use parent's starting directory */ - &si, /* Pointer to STARTUPINFO structure */ - pi); /* Pointer to PROCESS_INFORMATION structure */ - delete cmdline; - - return !result; -} -#endif - -#ifdef __WIN__ - -BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) -{ - DWORD dwTID, dwCode, dwErr= 0; - HANDLE hProcessDup= INVALID_HANDLE_VALUE; - HANDLE hRT= NULL; - HINSTANCE hKernel= GetModuleHandle("Kernel32"); - BOOL bSuccess= FALSE; - - BOOL bDup= DuplicateHandle(GetCurrentProcess(), - hProcess, GetCurrentProcess(), &hProcessDup, - PROCESS_ALL_ACCESS, FALSE, 0); - - // Detect the special case where the process is - // already dead... - if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) && - (dwCode == STILL_ACTIVE)) - { - FARPROC pfnExitProc; - - pfnExitProc= GetProcAddress(hKernel, "ExitProcess"); - - hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0, - (LPTHREAD_START_ROUTINE)pfnExitProc, - (PVOID)uExitCode, 0, &dwTID); - - if (hRT == NULL) - dwErr= GetLastError(); - } - else - dwErr= ERROR_PROCESS_ABORTED; - - if (hRT) - { - // Must wait process to terminate to - // guarantee that it has exited... - WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE); - - CloseHandle(hRT); - bSuccess= TRUE; - } - - if (bDup) - CloseHandle(hProcessDup); - - if (!bSuccess) - SetLastError(dwErr); - - return bSuccess; -} - -int kill(pid_t pid, int signum) -{ - HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (signum == SIGTERM) - ::SafeTerminateProcess(processhandle, 0); - else - ::TerminateProcess(processhandle, -1); - return 0; -} -#endif - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Static constants. -*************************************************************************/ - -const LEX_STRING -Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") }; - -/************************************************************************* - }}} -*************************************************************************/ - - -/************************************************************************* - {{{ Instance Monitor thread. -*************************************************************************/ - -/** - Proxy thread is a simple way to avoid all pitfalls of the threads - implementation in the OS (e.g. LinuxThreads). With such a thread we - don't have to process SIGCHLD, which is a tricky business if we want - to do it in a portable way. - - Instance Monitor Thread forks a child process, execs mysqld and waits for - the child to die. - - Instance Monitor assumes that the monitoring instance will not be dropped. - This is guaranteed by having flag monitoring_thread_active and - Instance::is_active() operation. -*/ - -class Instance_monitor: public Thread -{ -public: - Instance_monitor(Instance *instance_arg) :instance(instance_arg) {} -protected: - virtual void run(); - void start_and_monitor_instance(); -private: - Instance *instance; -}; - - -void Instance_monitor::run() -{ - start_and_monitor_instance(); - delete this; -} - - -void Instance_monitor::start_and_monitor_instance() -{ - Thread_registry *thread_registry= Manager::get_thread_registry(); - Guardian *guardian= Manager::get_guardian(); - - My_process_info mysqld_process_info; - Thread_info monitor_thread_info; - - log_info("Instance '%s': Monitor: started.", - (const char *) instance->get_name()->str); - - /* - For guarded instance register the thread in Thread_registry to wait for - the thread to stop on shutdown (nonguarded instances are not stopped on - shutdown, so the thread will no finish). - */ - - if (instance->is_guarded()) - { - thread_registry->register_thread(&monitor_thread_info, FALSE); - } - - /* Starting mysqld. */ - - log_info("Instance '%s': Monitor: starting mysqld...", - (const char *) instance->get_name()->str); - - if (start_process(&instance->options, &mysqld_process_info)) - { - instance->lock(); - instance->monitoring_thread_active= FALSE; - instance->unlock(); - - return; - } - - /* Waiting for mysqld to die. */ - - log_info("Instance '%s': Monitor: waiting for mysqld to stop...", - (const char *) instance->get_name()->str); - - wait_process(&mysqld_process_info); /* Don't check for return value. */ - - log_info("Instance '%s': Monitor: mysqld stopped.", - (const char *) instance->get_name()->str); - - /* Update instance status. */ - - instance->lock(); - - if (instance->is_guarded()) - thread_registry->unregister_thread(&monitor_thread_info); - - instance->crashed= TRUE; - instance->monitoring_thread_active= FALSE; - - log_info("Instance '%s': Monitor: finished.", - (const char *) instance->get_name()->str); - - instance->unlock(); - - /* Wake up guardian. */ - - guardian->ping(); -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Static operations. -**************************************************************************/ - -/** - The operation is intended to check whether string is a well-formed - instance name or not. - - SYNOPSIS - is_name_valid() - name string to check - - RETURN - TRUE string is a valid instance name - FALSE string is not a valid instance name - - TODO: Move to Instance_name class: Instance_name::is_valid(). -*/ - -bool Instance::is_name_valid(const LEX_STRING *name) -{ - const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length; - - if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str, - Instance::DFLT_INSTANCE_NAME.length) != 0) - return FALSE; - - return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix); -} - - -/** - The operation is intended to check if the given instance name is - mysqld-compatible or not. - - SYNOPSIS - is_mysqld_compatible_name() - name name to check - - RETURN - TRUE name is mysqld-compatible - FALSE otherwise - - TODO: Move to Instance_name class: Instance_name::is_mysqld_compatible(). -*/ - -bool Instance::is_mysqld_compatible_name(const LEX_STRING *name) -{ - return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0; -} - - -/** - Return client state name. Must not be used outside the class. - Use Instance::get_state_name() instead. -*/ - -const char * Instance::get_instance_state_name(enum_instance_state state) -{ - switch (state) { - case STOPPED: - return "offline"; - - case NOT_STARTED: - return "not started"; - - case STARTING: - return "starting"; - - case STARTED: - return "online"; - - case JUST_CRASHED: - return "failed"; - - case CRASHED: - return "crashed"; - - case CRASHED_AND_ABANDONED: - return "abandoned"; - - case STOPPING: - return "stopping"; - } - - return NULL; /* just to ignore compiler warning. */ -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Initialization & deinitialization. -**************************************************************************/ - -Instance::Instance() - :monitoring_thread_active(FALSE), - crashed(FALSE), - configured(FALSE), - /* mysqld_compatible is initialized in init() */ - state(NOT_STARTED), - restart_counter(0), - crash_moment(0), - last_checked(0) -{ - pthread_mutex_init(&LOCK_instance, 0); -} - - -Instance::~Instance() -{ - log_info("Instance '%s': destroying...", (const char *) get_name()->str); - - pthread_mutex_destroy(&LOCK_instance); -} - - -/** - Initialize instance options. - - SYNOPSIS - init() - name_arg name of the instance - - RETURN: - FALSE - ok - TRUE - error -*/ - -bool Instance::init(const LEX_STRING *name_arg) -{ - mysqld_compatible= is_mysqld_compatible_name(name_arg); - - return options.init(name_arg); -} - - -/** - @brief Complete instance options initialization. - - @return Error status. - @retval FALSE ok - @retval TRUE error -*/ - -bool Instance::complete_initialization() -{ - configured= ! options.complete_initialization(); - return !configured; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: public interface implementation. -**************************************************************************/ - -/** - Determine if there is some activity with the instance. - - SYNOPSIS - is_active() - - DESCRIPTION - An instance is active if one of the following conditions is true: - - Instance-monitoring thread is running; - - Instance is guarded and its state is other than STOPPED; - - Corresponding mysqld-server accepts connections. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - instance is active - FALSE - otherwise. -*/ - -bool Instance::is_active() -{ - if (monitoring_thread_active) - return TRUE; - - if (is_guarded() && get_state() != STOPPED) - return TRUE; - - return is_mysqld_running(); -} - - -/** - Determine if mysqld is accepting connections. - - SYNOPSIS - is_mysqld_running() - - DESCRIPTION - Try to connect to mysqld with fake login/password to check whether it is - accepting connections or not. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - TRUE - mysqld is alive and accept connections - FALSE - otherwise. -*/ - -bool Instance::is_mysqld_running() -{ - MYSQL mysql; - uint port= options.get_mysqld_port(); /* 0 if not specified. */ - const char *socket= NULL; - static const char *password= "check_connection"; - static const char *username= "MySQL_Instance_Manager"; - static const char *access_denied_message= "Access denied for user"; - bool return_val; - - if (options.mysqld_socket) - socket= options.mysqld_socket; - - /* no port was specified => instance falled back to default value */ - if (!port && !options.mysqld_socket) - port= SERVER_DEFAULT_PORT; - - mysql_init(&mysql); - /* try to connect to a server with a fake username/password pair */ - if (mysql_real_connect(&mysql, LOCAL_HOST, username, - password, - NullS, port, - socket, 0)) - { - /* - We have successfully connected to the server using fake - username/password. Write a warning to the logfile. - */ - log_error("Instance '%s': was able to log into mysqld.", - (const char *) get_name()->str); - return_val= TRUE; /* server is alive */ - } - else - return_val= test(!strncmp(access_denied_message, mysql_error(&mysql), - sizeof(access_denied_message) - 1)); - - mysql_close(&mysql); - - return return_val; -} - - -/** - @brief Start mysqld. - - Reset flags and start Instance Monitor thread, which will start mysqld. - - @note Instance must be locked before calling the operation. - - @return Error status code - @retval FALSE Ok - @retval TRUE Could not start instance -*/ - -bool Instance::start_mysqld() -{ - Instance_monitor *instance_monitor; - - if (!configured) - return TRUE; - - /* - Prepare instance to start Instance Monitor thread. - - NOTE: It's important to set these actions here in order to avoid - race conditions -- these actions must be done under acquired lock on - Instance. - */ - - crashed= FALSE; - monitoring_thread_active= TRUE; - - remove_pid(); - - /* Create and start the Instance Monitor thread. */ - - instance_monitor= new Instance_monitor(this); - - if (instance_monitor == NULL || instance_monitor->start(Thread::DETACHED)) - { - delete instance_monitor; - monitoring_thread_active= FALSE; - - log_error("Instance '%s': can not create instance monitor thread.", - (const char *) get_name()->str); - - return TRUE; - } - - ++restart_counter; - - /* The Instance Monitor thread will delete itself when it's finished. */ - - return FALSE; -} - - -/** - Stop mysqld. - - SYNOPSIS - stop_mysqld() - - DESCRIPTION - Try to stop mysqld gracefully. Otherwise kill it with SIGKILL. - - MT-NOTE: instance must be locked before calling the operation. - - RETURN - FALSE - ok - TRUE - could not stop the instance -*/ - -bool Instance::stop_mysqld() -{ - log_info("Instance '%s': stopping mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGTERM); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld stopped gracefully.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': mysqld failed to stop gracefully within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - log_info("Instance'%s': killing mysqld...", - (const char *) get_name()->str); - - kill_mysqld(SIGKILL); - - if (!wait_for_stop()) - { - log_info("Instance '%s': mysqld has been killed.", - (const char *) get_name()->str); - return FALSE; - } - - log_info("Instance '%s': can not kill mysqld within %d seconds.", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - return TRUE; -} - - -/** - Send signal to mysqld. - - SYNOPSIS - kill_mysqld() - - DESCRIPTION - Load pid from the pid file and send the given signal to that process. - If the signal is SIGKILL, remove the pid file after sending the signal. - - MT-NOTE: instance must be locked before calling the operation. - - TODO - This too low-level and OS-specific operation for public interface. - Also, it has some implicit behaviour for SIGKILL signal. Probably, we - should have the following public operations instead: - - start_mysqld() -- as is; - - stop_mysqld -- request mysqld to shutdown gracefully (send SIGTERM); - don't wait for complete shutdown; - - wait_for_stop() (or join_mysqld()) -- wait for mysqld to stop within - time interval; - - kill_mysqld() -- request to terminate mysqld; don't wait for - completion. - These operations should also be used in Guardian to manage instances. -*/ - -bool Instance::kill_mysqld(int signum) -{ - pid_t mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - { - log_info("Instance '%s': no pid file to send a signal (%d).", - (const char *) get_name()->str, - (int) signum); - return TRUE; - } - - log_info("Instance '%s': sending %d to %d...", - (const char *) get_name()->str, - (int) signum, - (int) mysqld_pid); - - if (kill(mysqld_pid, signum)) - { - log_info("Instance '%s': kill() failed.", - (const char *) get_name()->str); - return TRUE; - } - - /* Kill suceeded */ - if (signum == SIGKILL) /* really killed instance with SIGKILL */ - { - log_error("Instance '%s': killed.", - (const char *) options.instance_name.str); - - /* After sucessful hard kill the pidfile need to be removed */ - options.unlink_pidfile(); - } - - return FALSE; -} - - -/** - Lock instance. -*/ - -void Instance::lock() -{ - pthread_mutex_lock(&LOCK_instance); -} - - -/** - Unlock instance. -*/ - -void Instance::unlock() -{ - pthread_mutex_unlock(&LOCK_instance); -} - - -/** - Return instance state name. - - SYNOPSIS - get_state_name() - - DESCRIPTION - The operation returns user-friendly state name. The operation can be - used both for guarded and non-guarded instances. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Replace with the static get_state_name(state_code) function. -*/ - -const char *Instance::get_state_name() -{ - if (!is_configured()) - return "misconfigured"; - - if (is_guarded()) - { - /* The instance is managed by Guardian: we can report precise state. */ - - return get_instance_state_name(get_state()); - } - - /* The instance is not managed by Guardian: we can report status only. */ - - return is_active() ? "online" : "offline"; -} - - -/** - Reset statistics. - - SYNOPSIS - reset_stat() - - DESCRIPTION - The operation resets statistics used for guarding the instance. - - MT-NOTE: instance must be locked before calling the operation. - - TODO: Make private. -*/ - -void Instance::reset_stat() -{ - restart_counter= 0; - crash_moment= 0; - last_checked= 0; -} - -/************************************************************************** - }}} -**************************************************************************/ - - -/************************************************************************** - {{{ Instance: implementation of private operations. -**************************************************************************/ - -/** - Remove pid file. -*/ - -void Instance::remove_pid() -{ - int mysqld_pid= options.load_pid(); - - if (mysqld_pid == 0) - return; - - if (options.unlink_pidfile()) - { - log_error("Instance '%s': can not unlink pid file.", - (const char *) options.instance_name.str); - } -} - - -/** - Wait for mysqld to stop within shutdown interval. -*/ - -bool Instance::wait_for_stop() -{ - int start_time= (int) time(NULL); - int finish_time= start_time + options.get_shutdown_delay(); - - log_info("Instance '%s': waiting for mysqld to stop " - "(timeout: %d seconds)...", - (const char *) get_name()->str, - (int) options.get_shutdown_delay()); - - while (true) - { - if (options.load_pid() == 0 && !is_mysqld_running()) - return FALSE; - - if (time(NULL) >= finish_time) - return TRUE; - - /* Sleep for 0.3 sec and check again. */ - - my_sleep(300000); - } -} - -/************************************************************************** - }}} -**************************************************************************/ diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h deleted file mode 100644 index aa9c923cba1..00000000000 --- a/server-tools/instance-manager/instance.h +++ /dev/null @@ -1,273 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <m_string.h> - -#include "instance_options.h" -#include "priv.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Instance_map; -class Thread_registry; - - -/** - Instance_name -- the class represents instance name -- a string of length - less than MAX_INSTANCE_NAME_SIZE. - - Generally, this is just a string with self-memory-management and should be - eliminated in the future. -*/ - -class Instance_name -{ -public: - Instance_name(const LEX_STRING *name); - -public: - inline const LEX_STRING *get_str() const - { - return &str; - } - - inline const char *get_c_str() const - { - return str.str; - } - - inline uint get_length() const - { - return str.length; - } - -private: - LEX_STRING str; - char str_buffer[MAX_INSTANCE_NAME_SIZE]; -}; - - -class Instance -{ -public: - /* States of an instance. */ - enum enum_instance_state - { - STOPPED, - NOT_STARTED, - STARTING, - STARTED, - JUST_CRASHED, - CRASHED, - CRASHED_AND_ABANDONED, - STOPPING - }; - -public: - /** - The constant defines name of the default mysqld-instance ("mysqld"). - */ - static const LEX_STRING DFLT_INSTANCE_NAME; - -public: - static bool is_name_valid(const LEX_STRING *name); - static bool is_mysqld_compatible_name(const LEX_STRING *name); - -public: - Instance(); - ~Instance(); - - bool init(const LEX_STRING *name_arg); - bool complete_initialization(); - -public: - bool is_active(); - - bool is_mysqld_running(); - - bool start_mysqld(); - bool stop_mysqld(); - bool kill_mysqld(int signo); - - void lock(); - void unlock(); - - const char *get_state_name(); - - void reset_stat(); - -public: - /** - The operation is intended to check if the instance is mysqld-compatible - or not. - */ - inline bool is_mysqld_compatible() const; - - /** - The operation is intended to check if the instance is configured properly - or not. Misconfigured instances are not managed. - */ - inline bool is_configured() const; - - /** - The operation returns TRUE if the instance is guarded and FALSE otherwise. - */ - inline bool is_guarded() const; - - /** - The operation returns name of the instance. - */ - inline const LEX_STRING *get_name() const; - - /** - The operation returns the current state of the instance. - - NOTE: At the moment should be used only for guarded instances. - */ - inline enum_instance_state get_state() const; - - /** - The operation changes the state of the instance. - - NOTE: At the moment should be used only for guarded instances. - TODO: Make private. - */ - inline void set_state(enum_instance_state new_state); - - /** - The operation returns crashed flag. - */ - inline bool is_crashed(); - -public: - /** - This attributes contains instance options. - - TODO: Make private. - */ - Instance_options options; - -private: - /** - monitoring_thread_active is TRUE if there is a thread that monitors the - corresponding mysqld-process. - */ - bool monitoring_thread_active; - - /** - crashed is TRUE when corresponding mysqld-process has been died after - start. - */ - bool crashed; - - /** - configured is TRUE when the instance is configured and FALSE otherwise. - Misconfigured instances are not managed. - */ - bool configured; - - /* - mysqld_compatible specifies whether the instance is mysqld-compatible - or not. Mysqld-compatible instances can contain only mysqld-specific - options. At the moment an instance is mysqld-compatible if its name is - "mysqld". - - The idea is that [mysqld] section should contain only mysqld-specific - options (no Instance Manager-specific options) to be readable by mysqld - program. - */ - bool mysqld_compatible; - - /* - Mutex protecting the instance. - */ - pthread_mutex_t LOCK_instance; - -private: - /* Guarded-instance attributes. */ - - /* state of an instance (i.e. STARTED, CRASHED, etc.) */ - enum_instance_state state; - -public: - /* the amount of attemts to restart instance (cleaned up at success) */ - int restart_counter; - - /* triggered at a crash */ - time_t crash_moment; - - /* General time field. Used to provide timeouts (at shutdown and restart) */ - time_t last_checked; - -private: - static const char *get_instance_state_name(enum_instance_state state); - -private: - void remove_pid(); - - bool wait_for_stop(); - -private: - friend class Instance_monitor; -}; - - -inline bool Instance::is_mysqld_compatible() const -{ - return mysqld_compatible; -} - - -inline bool Instance::is_configured() const -{ - return configured; -} - - -inline bool Instance::is_guarded() const -{ - return !options.nonguarded; -} - - -inline const LEX_STRING *Instance::get_name() const -{ - return &options.instance_name; -} - - -inline Instance::enum_instance_state Instance::get_state() const -{ - return state; -} - - -inline void Instance::set_state(enum_instance_state new_state) -{ - state= new_state; -} - - -inline bool Instance::is_crashed() -{ - return crashed; -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */ diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc deleted file mode 100644 index b137370b50a..00000000000 --- a/server-tools/instance-manager/instance_map.cc +++ /dev/null @@ -1,649 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_map.h" - -#include <my_global.h> -#include <m_ctype.h> -#include <mysql_com.h> - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "options.h" -#include "priv.h" - -C_MODE_START - -/** - HASH-routines: get key of instance for storing in hash. -*/ - -static uchar* get_instance_key(const uchar* u, size_t* len, - my_bool __attribute__((unused)) t) -{ - const Instance *instance= (const Instance *) u; - *len= instance->options.instance_name.length; - return (uchar *) instance->options.instance_name.str; -} - -/** - HASH-routines: cleanup handler. -*/ - -static void delete_instance(void *u) -{ - Instance *instance= (Instance *) u; - delete instance; -} - -/** - The option handler to pass to the process_default_option_files function. - - SYNOPSIS - process_option() - ctx Handler context. Here it is an instance_map structure. - group_name The name of the group the option belongs to. - option The very option to be processed. It is already - prepared to be used in argv (has -- prefix) - - DESCRIPTION - - This handler checks whether a group is an instance group and adds - an option to the appropriate instance class. If this is the first - occurence of an instance name, we'll also create the instance - with such name and add it to the instance map. - - RETURN - 0 - ok - 1 - error occured -*/ - -static int process_option(void *ctx, const char *group, const char *option) -{ - Instance_map *map= (Instance_map*) ctx; - LEX_STRING group_str; - - group_str.str= (char *) group; - group_str.length= strlen(group); - - return map->process_one_option(&group_str, option); -} - -C_MODE_END - - -/** - Parse option string. - - SYNOPSIS - parse_option() - option_str [IN] option string (e.g. "--name=value") - option_name_buf [OUT] parsed name of the option. - Must be of (MAX_OPTION_LEN + 1) size. - option_value_buf [OUT] parsed value of the option. - Must be of (MAX_OPTION_LEN + 1) size. - - DESCRIPTION - This is an auxiliary function and should not be used externally. It is - intended to parse whole option string into option name and option value. -*/ - -static void parse_option(const char *option_str, - char *option_name_buf, - char *option_value_buf) -{ - const char *eq_pos; - const char *ptr= option_str; - - while (*ptr == '-') - ++ptr; - - strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1); - - eq_pos= strchr(ptr, '='); - if (eq_pos) - { - option_name_buf[eq_pos - ptr]= 0; - strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1); - } - else - { - option_value_buf[0]= 0; - } -} - - -/** - Process one option from the configuration file. - - SYNOPSIS - Instance_map::process_one_option() - group group name - option option string (e.g. "--name=value") - - DESCRIPTION - This is an auxiliary function and should not be used externally. - It is used only by flush_instances(), which pass it to - process_option(). The caller ensures proper locking - of the instance map object. -*/ - /* - Process a given option and assign it to appropricate instance. This is - required for the option handler, passed to my_search_option_files(). - */ - -int Instance_map::process_one_option(const LEX_STRING *group, - const char *option) -{ - Instance *instance= NULL; - - if (!Instance::is_name_valid(group)) - { - /* - Current section name is not a valid instance name. - We should skip it w/o error. - */ - return 0; - } - - if (!(instance= (Instance *) hash_search(&hash, (uchar *) group->str, - group->length))) - { - if (!(instance= new Instance())) - return 1; - - if (instance->init(group) || add_instance(instance)) - { - delete instance; - return 1; - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) group->str); - - log_info("mysqld instance '%s' has been added successfully.", - (const char *) group->str); - } - - if (option) - { - char option_name[MAX_OPTION_LEN + 1]; - char option_value[MAX_OPTION_LEN + 1]; - - parse_option(option, option_name, option_value); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option_name)) - { - log_info("Warning: configuration of mysqld-compatible instance '%s' " - "contains IM-specific option '%s'. " - "This breaks backward compatibility for the configuration file.", - (const char *) group->str, - (const char *) option_name); - } - - Named_value option(option_name, option_value); - - if (instance->options.set_option(&option)) - return 1; /* the instance'll be deleted when we destroy the map */ - } - - return 0; -} - - -/** - Instance_map constructor. -*/ - -Instance_map::Instance_map() -{ - pthread_mutex_init(&LOCK_instance_map, 0); -} - - -/** - Initialize Instance_map internals. -*/ - -bool Instance_map::init() -{ - return hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, - get_instance_key, delete_instance, 0); -} - - -/** - Reset Instance_map data. -*/ - -bool Instance_map::reset() -{ - hash_free(&hash); - return init(); -} - - -/** - Instance_map destructor. -*/ - -Instance_map::~Instance_map() -{ - lock(); - - /* - NOTE: it's necessary to synchronize on each instance before removal, - because Instance-monitoring thread can be still alive an hold the mutex - (because it is detached and we have no control over it). - */ - - while (true) - { - Iterator it(this); - Instance *instance= it.next(); - - if (!instance) - break; - - instance->lock(); - instance->unlock(); - - remove_instance(instance); - } - - hash_free(&hash); - unlock(); - - pthread_mutex_destroy(&LOCK_instance_map); -} - - -/** - Lock Instance_map. -*/ - -void Instance_map::lock() -{ - pthread_mutex_lock(&LOCK_instance_map); -} - - -/** - Unlock Instance_map. -*/ - -void Instance_map::unlock() -{ - pthread_mutex_unlock(&LOCK_instance_map); -} - - -/** - Check if there is an active instance or not. -*/ - -bool Instance_map::is_there_active_instance() -{ - Instance *instance; - Iterator iterator(this); - - while ((instance= iterator.next())) - { - bool active_instance_found; - - instance->lock(); - active_instance_found= instance->is_active(); - instance->unlock(); - - if (active_instance_found) - return TRUE; - } - - return FALSE; -} - - -/** - Add an instance into the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::add_instance(Instance *instance) -{ - return my_hash_insert(&hash, (uchar *) instance); -} - - -/** - Remove instance from the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::remove_instance(Instance *instance) -{ - return hash_delete(&hash, (uchar *) instance); -} - - -/** - Create a new instance and register it in the internal hash. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -int Instance_map::create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - Instance *instance= new Instance(); - - if (!instance) - { - log_error("Can not allocate instance (name: '%s').", - (const char *) instance_name->str); - return ER_OUT_OF_RESOURCES; - } - - if (instance->init(instance_name)) - { - log_error("Can not initialize instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - Named_value option= options->get_element(i); - - if (instance->is_mysqld_compatible() && - Instance_options::is_option_im_specific(option.get_name())) - { - log_error("IM-option (%s) can not be used " - "in configuration of mysqld-compatible instance (%s).", - (const char *) option.get_name(), - (const char *) instance_name->str); - delete instance; - return ER_INCOMPATIBLE_OPTION; - } - - instance->options.set_option(&option); - } - - if (instance->is_mysqld_compatible()) - log_info("Warning: instance name '%s' is mysqld-compatible.", - (const char *) instance_name->str); - - if (instance->complete_initialization()) - { - log_error("Can not complete initialization of instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - /* TODO: return more appropriate error code in this case. */ - } - - if (add_instance(instance)) - { - log_error("Can not register instance (name: '%s').", - (const char *) instance_name->str); - delete instance; - return ER_OUT_OF_RESOURCES; - } - - return 0; -} - - -/** - Return a pointer to the instance or NULL, if there is no such instance. - - MT-NOTE: Instance Map must be locked before calling the operation. -*/ - -Instance * Instance_map::find(const LEX_STRING *name) -{ - return (Instance *) hash_search(&hash, (uchar *) name->str, name->length); -} - - -/** - Init instances command line arguments after all options have been loaded. -*/ - -bool Instance_map::complete_initialization() -{ - bool mysqld_found; - - /* Complete initialization of all registered instances. */ - - for (uint i= 0; i < hash.records; ++i) - { - Instance *instance= (Instance *) hash_element(&hash, i); - - if (instance->complete_initialization()) - return TRUE; - } - - /* That's all if we are runnning in an ordinary mode. */ - - if (!Options::Main::mysqld_safe_compatible) - return FALSE; - - /* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */ - - mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL; - - if (mysqld_found) - return FALSE; - - if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - log_error("Can not create default instance."); - return TRUE; - } - - switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL)) - { - case 0: - case ER_CONF_FILE_DOES_NOT_EXIST: - /* - Continue if the instance has been added to the config file - successfully, or the config file just does not exist. - */ - break; - - default: - log_error("Can not add default instance to the config file."); - - Instance *instance= find(&Instance::DFLT_INSTANCE_NAME); - - if (instance) - remove_instance(instance); /* instance is deleted here. */ - - return TRUE; - } - - return FALSE; -} - - -/** - Load options from config files and create appropriate instance - structures. -*/ - -int Instance_map::load() -{ - int argc= 1; - /* this is a dummy variable for search_option_files() */ - uint args_used= 0; - const char *argv_options[3]; - char **argv= (char **) &argv_options; - char defaults_file_arg[FN_REFLEN]; - - /* the name of the program may be orbitrary here in fact */ - argv_options[0]= "mysqlmanager"; - - /* - If the option file was forced by the user when starting - the IM with --defaults-file=xxxx, make sure it is also - passed as --defaults-file, not only as Options::config_file. - This is important for option files given with relative path: - e.g. --defaults-file=my.cnf. - Otherwise my_search_option_files will treat "my.cnf" as a group - name and start looking for files named "my.cnf.cnf" in all - default dirs. Which is not what we want. - */ - if (Options::Main::is_forced_default_file) - { - snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s", - Options::Main::config_file); - - argv_options[1]= defaults_file_arg; - argv_options[2]= '\0'; - - argc= 2; - } - else - argv_options[1]= '\0'; - - /* - If the routine failed, we'll simply fallback to defaults in - complete_initialization(). - */ - if (my_search_option_files(Options::Main::config_file, &argc, - (char ***) &argv, &args_used, - process_option, (void*) this, - Options::default_directories)) - log_info("Falling back to compiled-in defaults."); - - return complete_initialization(); -} - - -/************************************************************************* - {{{ Instance_map::Iterator implementation. -*************************************************************************/ - -void Instance_map::Iterator::go_to_first() -{ - current_instance=0; -} - - -Instance *Instance_map::Iterator::next() -{ - if (current_instance < instance_map->hash.records) - return (Instance *) hash_element(&instance_map->hash, current_instance++); - - return NULL; -} - -/************************************************************************* - }}} -*************************************************************************/ - - -/** - Create a new configuration section for mysqld-instance in the config file. - - SYNOPSIS - create_instance_in_file() - instance_name mysqld-instance name - options options for the new mysqld-instance - - RETURN - 0 On success - ER_CONF_FILE_DOES_NOT_EXIST If config file does not exist - ER_ACCESS_OPTION_FILE If config file is not writable or some I/O - error ocurred during writing configuration -*/ - -int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options) -{ - File cnf_file; - - if (my_access(Options::Main::config_file, W_OK)) - { - log_error("Configuration file (%s) does not exist.", - (const char *) Options::Main::config_file); - return ER_CONF_FILE_DOES_NOT_EXIST; - } - - cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0)); - - if (cnf_file <= 0) - { - log_error("Can not open configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - return ER_ACCESS_OPTION_FILE; - } - - if (my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"[", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)instance_name->str, instance_name->length, - MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)"]", 1, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - - for (int i= 0; options && i < options->get_size(); ++i) - { - char option_str[MAX_OPTION_STR_LEN]; - char *ptr; - int option_str_len; - Named_value option= options->get_element(i); - - ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS); - - if (option.get_value()[0]) - ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - option_str_len= ptr - option_str; - - if (my_write(cnf_file, (uchar*)option_str, option_str_len, MYF(MY_NABP)) || - my_write(cnf_file, (uchar*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP))) - { - log_error("Can not write to configuration file (%s): %s.", - (const char *) Options::Main::config_file, - (const char *) strerror(errno)); - my_close(cnf_file, MYF(0)); - return ER_ACCESS_OPTION_FILE; - } - } - - my_close(cnf_file, MYF(0)); - - return 0; -} diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h deleted file mode 100644 index af2f1868195..00000000000 --- a/server-tools/instance-manager/instance_map.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> -#include <hash.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Guardian; -class Instance; -class Named_value_arr; -class Thread_registry; - -extern int load_all_groups(char ***groups, const char *filename); -extern void free_groups(char **groups); - -extern int create_instance_in_file(const LEX_STRING *instance_name, - const Named_value_arr *options); - - -/** - Instance_map - stores all existing instances -*/ - -class Instance_map -{ -public: - /** - Instance_map iterator - */ - - class Iterator - { - private: - uint current_instance; - Instance_map *instance_map; - public: - Iterator(Instance_map *instance_map_arg) : - current_instance(0), instance_map(instance_map_arg) - {} - - void go_to_first(); - Instance *next(); - }; - -public: - Instance *find(const LEX_STRING *name); - - bool is_there_active_instance(); - - void lock(); - void unlock(); - - bool init(); - bool reset(); - - int load(); - - int process_one_option(const LEX_STRING *group, const char *option); - - int add_instance(Instance *instance); - - int remove_instance(Instance *instance); - - int create_instance(const LEX_STRING *instance_name, - const Named_value_arr *options); - -public: - Instance_map(); - ~Instance_map(); - -private: - bool complete_initialization(); - -private: - enum { START_HASH_SIZE = 16 }; - pthread_mutex_t LOCK_instance_map; - HASH hash; - -private: - friend class Iterator; -}; - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */ diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc deleted file mode 100644 index 8b96d6f0f96..00000000000 --- a/server-tools/instance-manager/instance_options.cc +++ /dev/null @@ -1,753 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "instance_options.h" - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> - -#include <signal.h> - -#include "buffer.h" -#include "instance.h" -#include "log.h" -#include "options.h" -#include "parse_output.h" -#include "priv.h" - - -/* Create "mysqld ..." command in the buffer */ - -static inline bool create_mysqld_command(Buffer *buf, - const LEX_STRING *mysqld_path, - const LEX_STRING *option) -{ - int position= 0; - - if (buf->get_size()) /* malloc succeeded */ - { -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - buf->append(position, mysqld_path->str, mysqld_path->length); - position+= mysqld_path->length; -#ifdef __WIN__ - buf->append(position++, "\"", 1); -#endif - /* here the '\0' character is copied from the option string */ - buf->append(position, option->str, option->length + 1); - - return buf->is_error() ? TRUE : FALSE; - } - return TRUE; -} - -static inline bool is_path_separator(char ch) -{ -#if defined(__WIN__) || defined(__NETWARE__) - /* On windows and netware more delimiters are possible */ - return ch == FN_LIBCHAR || ch == FN_DEVCHAR || ch == '/'; -#else - return ch == FN_LIBCHAR; /* Unixes */ -#endif -} - - -static char *find_last_path_separator(char *path, uint length) -{ - while (length) - { - if (is_path_separator(path[length])) - return path + length; - length--; - } - return NULL; /* No path separator found */ -} - - - -bool Instance_options::is_option_im_specific(const char *option_name) -{ - static const char *IM_SPECIFIC_OPTIONS[] = - { - "nonguarded", - "mysqld-path", - "shutdown-delay", - NULL - }; - - for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i) - { - if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i])) - return TRUE; - } - - return FALSE; -} - - -Instance_options::Instance_options() - :mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL), - mysqld_pid_file(NULL), - nonguarded(NULL), - mysqld_port(NULL), - mysqld_port_val(0), - shutdown_delay(NULL), - shutdown_delay_val(0), - filled_default_options(0) -{ - mysqld_path.str= NULL; - mysqld_path.length= 0; - - mysqld_real_path.str= NULL; - mysqld_real_path.length= 0; - - memset(logs, 0, sizeof(logs)); -} - - -/* - Get compiled-in value of default_option - - SYNOPSIS - get_default_option() - result buffer to put found value - result_len buffer size - option_name the name of the option, prefixed with "--" - - DESCRIPTION - - Get compile-in value of requested option from server - - RETURN - 0 - ok - 1 - error occured -*/ - - -int Instance_options::get_default_option(char *result, size_t result_len, - const char *option_name) -{ - int rc= 1; - LEX_STRING verbose_option= - { C_STRING_WITH_LEN(" --no-defaults --verbose --help") }; - - /* reserve space for the path + option + final '\0' */ - Buffer cmd(mysqld_path.length + verbose_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option)) - goto err; - - /* +2 eats first "--" from the option string (E.g. "--datadir") */ - rc= parse_output_and_get_value((char*) cmd.buffer, - option_name + 2, strlen(option_name + 2), - result, result_len, GET_VALUE); -err: - return rc; -} - - -/* - Fill mysqld_version option (used at initialization stage) - - SYNOPSIS - fill_instance_version() - - DESCRIPTION - - Get mysqld version string from "mysqld --version" output. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_instance_version() -{ - char result[MAX_VERSION_LENGTH]; - LEX_STRING version_option= - { C_STRING_WITH_LEN(" --no-defaults --version") }; - Buffer cmd(mysqld_path.length + version_option.length + 1); - - if (create_mysqld_command(&cmd, &mysqld_path, &version_option)) - { - log_error("Failed to get version of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, MAX_VERSION_LENGTH); - - if (parse_output_and_get_value((char*) cmd.buffer, STRING_WITH_LEN("Ver"), - result, MAX_VERSION_LENGTH, GET_LINE)) - { - log_error("Failed to get version of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char *start; - - /* trim leading whitespaces */ - start= result; - while (my_isspace(default_charset_info, *start)) - ++start; - - mysqld_version= strdup_root(&alloc, start); - } - - return FALSE; -} - - -/* - Fill mysqld_real_path - - SYNOPSIS - fill_mysqld_real_path() - - DESCRIPTION - - Get the real path to mysqld from "mysqld --help" output. - Will print the realpath of mysqld between "Usage: " and "[OPTIONS]" - - This is needed if the mysqld_path variable is pointing at a - script(for example libtool) or a symlink. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_mysqld_real_path() -{ - char result[FN_REFLEN]; - LEX_STRING help_option= - { C_STRING_WITH_LEN(" --no-defaults --help") }; - Buffer cmd(mysqld_path.length + help_option.length); - - if (create_mysqld_command(&cmd, &mysqld_path, &help_option)) - { - log_error("Failed to get real path of '%s': out of memory.", - (const char *) mysqld_path.str); - return TRUE; - } - - bzero(result, FN_REFLEN); - - if (parse_output_and_get_value((char*) cmd.buffer, - STRING_WITH_LEN("Usage: "), - result, FN_REFLEN, - GET_LINE)) - { - log_error("Failed to get real path of '%s': unexpected output.", - (const char *) mysqld_path.str); - return TRUE; - } - - DBUG_ASSERT(*result != '\0'); - - { - char* options_str; - /* chop the path of at [OPTIONS] */ - if ((options_str= strstr(result, "[OPTIONS]"))) - *options_str= '\0'; - mysqld_real_path.str= strdup_root(&alloc, result); - mysqld_real_path.length= strlen(mysqld_real_path.str); - } - - return FALSE; -} - - -/* - Fill various log options - - SYNOPSIS - fill_log_options() - - DESCRIPTION - - Compute paths to enabled log files. If the path is not specified in the - instance explicitly (I.e. log=/home/user/mysql.log), we try to guess the - file name and placement. - - RETURN - FALSE - ok - TRUE - error occured -*/ - -bool Instance_options::fill_log_options() -{ - Buffer buff; - enum { MAX_LOG_OPTION_LENGTH= 256 }; - char datadir[MAX_LOG_OPTION_LENGTH]; - char hostname[MAX_LOG_OPTION_LENGTH]; - uint hostname_length; - struct log_files_st - { - const char *name; - uint length; - char **value; - const char *default_suffix; - } logs_st[]= - { - {"--log-error", 11, &(logs[IM_LOG_ERROR]), ".err"}, - {"--log", 5, &(logs[IM_LOG_GENERAL]), ".log"}, - {"--log-slow-queries", 18, &(logs[IM_LOG_SLOW]), "-slow.log"}, - {NULL, 0, NULL, NULL} - }; - struct log_files_st *log_files; - - /* compute hostname and datadir for the instance */ - if (mysqld_datadir == NULL) - { - if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir")) - return TRUE; - } - else - { - /* below is safe, as --datadir always has a value */ - strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1); - } - - if (gethostname(hostname,sizeof(hostname)-1) < 0) - strmov(hostname, "mysql"); - - hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ - hostname_length= strlen(hostname); - - - for (log_files= logs_st; log_files->name; log_files++) - { - for (int i=0; (argv[i] != 0); i++) - { - if (!strncmp(argv[i], log_files->name, log_files->length)) - { - /* - This is really log_files->name option if and only if it is followed - by '=', '\0' or space character. This way we can distinguish such - options as '--log' and '--log-bin'. This is checked in the following - two statements. - */ - if (argv[i][log_files->length] == '\0' || - my_isspace(default_charset_info, argv[i][log_files->length])) - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, hostname, datadir, "", - MY_UNPACK_FILENAME | MY_SAFE_PATH); - - - if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) <= - strlen(log_files->default_suffix)) - return TRUE; - - strmov(full_name + strlen(full_name), log_files->default_suffix); - - /* - If there were specified two identical logfiles options, - we would loose some memory in MEM_ROOT here. However - this situation is not typical. - */ - *(log_files->value)= strdup_root(&alloc, full_name); - } - - if (argv[i][log_files->length] == '=') - { - char full_name[MAX_LOG_OPTION_LENGTH]; - - fn_format(full_name, argv[i] +log_files->length + 1, - datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); - - if (!(*(log_files->value)= strdup_root(&alloc, full_name))) - return TRUE; - } - } - } - } - - return FALSE; -} - - -/* - Get the full pid file name with path - - SYNOPSIS - get_pid_filaname() - result buffer to sotre the pidfile value - - IMPLEMENTATION - Get the data directory, then get the pid filename - (which is always set for an instance), then load the - full path with my_load_path(). It takes into account - whether it is already an absolute path or it should be - prefixed with the datadir and so on. - - RETURN - 0 - ok - 1 - error occured -*/ - -int Instance_options::get_pid_filename(char *result) -{ - char datadir[MAX_PATH_LEN]; - - if (mysqld_datadir == NULL) - { - /* we might get an error here if we have wrong path to the mysqld binary */ - if (get_default_option(datadir, sizeof(datadir), "--datadir")) - return 1; - } - else - strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS); - - /* get the full path to the pidfile */ - my_load_path(result, mysqld_pid_file, datadir); - return 0; -} - - -int Instance_options::unlink_pidfile() -{ - return unlink(pid_file_with_path); -} - - -pid_t Instance_options::load_pid() -{ - FILE *pid_file_stream; - - /* get the pid */ - if ((pid_file_stream= my_fopen(pid_file_with_path, - O_RDONLY | O_BINARY, MYF(0))) != NULL) - { - pid_t pid; - - if (fscanf(pid_file_stream, "%i", &pid) != 1) - pid= -1; - my_fclose(pid_file_stream, MYF(0)); - return pid; - } - return 0; -} - - -bool Instance_options::complete_initialization() -{ - int arg_idx; - const char *tmp; - char *end; - char bin_name_firstchar; - - if (!mysqld_path.str) - { - /* - Need to copy the path to allocated memory, as convert_dirname() might - need to change it - */ - mysqld_path.str= strdup_root(&alloc, Options::Main::default_mysqld_path); - if (!mysqld_path.str) - return TRUE; - } - - mysqld_path.length= strlen(mysqld_path.str); - - /* - If we found path with no slashes (end == NULL), we should not call - convert_dirname() at all. As we have got relative path to the binary. - That is, user supposes that mysqld resides in the same dir as - mysqlmanager. - */ - if ((end= find_last_path_separator(mysqld_path.str, mysqld_path.length))) - { - bin_name_firstchar= end[1]; - - /* - Below we will conver the path to mysqld in the case, it was given - in a format of another OS (e.g. uses '/' instead of '\' etc). - Here we strip the path to get rid of the binary name ("mysqld"), - we do it by removing first letter of the binary name (e.g. 'm' - in "mysqld"). Later we put it back. - */ - end[1]= 0; - - /* convert dirname to the format of current OS */ - convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS); - - /* put back the first character of the binary name*/ - end[1]= bin_name_firstchar; - } - - if (mysqld_port) - mysqld_port_val= atoi(mysqld_port); - - if (shutdown_delay) - shutdown_delay_val= atoi(shutdown_delay); - - if (!(tmp= strdup_root(&alloc, "--no-defaults"))) - return TRUE; - - if (!mysqld_pid_file) - { - char pidfilename[MAX_PATH_LEN]; - char hostname[MAX_PATH_LEN]; - - /* - If we created only one istance [mysqld], because no config. files were - found, we would like to model mysqld pid file values. - */ - - if (!gethostname(hostname, sizeof(hostname) - 1)) - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-", - hostname, ".pid", NullS); - } - else - { - if (Instance::is_mysqld_compatible_name(&instance_name)) - strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS); - else - strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid", - NullS); - } - - Named_value option((char *) "pid-file", pidfilename); - - set_option(&option); - } - - if (get_pid_filename(pid_file_with_path)) - return TRUE; - - /* we need to reserve space for the final zero + possible default options */ - if (!(argv= (char**) - alloc_root(&alloc, (get_num_options() + 1 - + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*)))) - return TRUE; - filled_default_options= 0; - - /* the path must be first in the argv */ - if (add_to_argv(mysqld_path.str)) - return TRUE; - - if (add_to_argv(tmp)) - return TRUE; - - arg_idx= filled_default_options; - for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx) - { - char option_str[MAX_OPTION_STR_LEN]; - Named_value option= get_option(opt_idx); - - if (is_option_im_specific(option.get_name())) - continue; - - char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(), - NullS); - - if (option.get_value()[0]) - strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS); - - argv[arg_idx++]= strdup_root(&alloc, option_str); - } - - argv[arg_idx]= 0; - - if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version()) - return TRUE; - - return FALSE; -} - - -bool Instance_options::set_option(Named_value *option) -{ - bool err_status; - int idx= find_option(option->get_name()); - char *option_name_str; - char *option_value_str; - - if (!(option_name_str= Named_value::alloc_str(option->get_name()))) - return TRUE; - - if (!(option_value_str= Named_value::alloc_str(option->get_value()))) - { - Named_value::free_str(&option_name_str); - return TRUE; - } - - Named_value option_copy(option_name_str, option_value_str); - - if (idx < 0) - err_status= options.add_element(&option_copy); - else - err_status= options.replace_element(idx, &option_copy); - - if (!err_status) - update_var(option_copy.get_name(), option_copy.get_value()); - else - option_copy.free(); - - return err_status; -} - - -void Instance_options::unset_option(const char *option_name) -{ - int idx= find_option(option_name); - - if (idx < 0) - return; /* the option has not been set. */ - - options.remove_element(idx); - - update_var(option_name, NULL); -} - - -void Instance_options::update_var(const char *option_name, - const char *option_value) -{ - struct options_st - { - const char *name; - uint name_len; - const char **var; - } options_def[]= - { - {"socket", 6, &mysqld_socket}, - {"port", 4, &mysqld_port}, - {"datadir", 7, &mysqld_datadir}, - {"pid-file", 8, &mysqld_pid_file}, - {"nonguarded", 10, &nonguarded}, - {"mysqld-path", 11, (const char **) &mysqld_path.str}, - {"shutdown-delay", 14, &shutdown_delay}, - {NULL, 0, NULL} - }; - - for (options_st *opt= options_def; opt->name; ++opt) - { - if (!strncmp(opt->name, option_name, opt->name_len)) - { - *(opt->var)= option_value; - break; - } - } -} - - -int Instance_options::find_option(const char *option_name) -{ - for (int i= 0; i < get_num_options(); i++) - { - if (!strcmp(get_option(i).get_name(), option_name)) - return i; - } - - return -1; -} - - -int Instance_options::add_to_argv(const char* option) -{ - DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS); - - if (option) - argv[filled_default_options++]= (char*) option; - return 0; -} - - -/* function for debug purposes */ -void Instance_options::print_argv() -{ - int i; - - printf("printing out an instance %s argv:\n", - (const char *) instance_name.str); - - for (i=0; argv[i] != NULL; i++) - printf("argv: %s\n", argv[i]); -} - - -/* - We execute this function to initialize some options. - - RETURN - FALSE - ok - TRUE - memory allocation error -*/ - -bool Instance_options::init(const LEX_STRING *instance_name_arg) -{ - instance_name.length= instance_name_arg->length; - - init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0); - - if (options.init()) - return TRUE; - - if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str, - instance_name_arg->length))) - return TRUE; - - return FALSE; -} - - -Instance_options::~Instance_options() -{ - free_root(&alloc, MYF(0)); -} - - -uint Instance_options::get_shutdown_delay() const -{ - static const uint DEFAULT_SHUTDOWN_DELAY= 35; - - /* - NOTE: it is important to check shutdown_delay here, but use - shutdown_delay_val. The idea is that if the option is unset, - shutdown_delay will be NULL, but shutdown_delay_val will not be reset. - */ - - return shutdown_delay ? shutdown_delay_val : DEFAULT_SHUTDOWN_DELAY; -} - -int Instance_options::get_mysqld_port() const -{ - /* - NOTE: it is important to check mysqld_port here, but use mysqld_port_val. - The idea is that if the option is unset, mysqld_port will be NULL, but - mysqld_port_val will not be reset. - */ - - return mysqld_port ? mysqld_port_val : 0; -} - diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h deleted file mode 100644 index b0503815036..00000000000 --- a/server-tools/instance-manager/instance_options.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_sys.h> - -#include "parse.h" -#include "portability.h" /* for pid_t on Win32 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - - -/* - This class contains options of an instance and methods to operate them. - - We do not provide this class with the means of synchronization as it is - supposed that options for instances are all loaded at once during the - instance_map initilization and we do not change them later. This way we - don't have to synchronize between threads. -*/ - -class Instance_options -{ -public: - /* The operation is used to check if the option is IM-specific or not. */ - static bool is_option_im_specific(const char *option_name); - -public: - Instance_options(); - ~Instance_options(); - - bool complete_initialization(); - - bool set_option(Named_value *option); - void unset_option(const char *option_name); - - inline int get_num_options() const; - inline Named_value get_option(int idx) const; - -public: - bool init(const LEX_STRING *instance_name_arg); - pid_t load_pid(); - int get_pid_filename(char *result); - int unlink_pidfile(); - void print_argv(); - - uint get_shutdown_delay() const; - int get_mysqld_port() const; - -public: - /* - We need this value to be greater or equal then FN_REFLEN found in - my_global.h to use my_load_path() - */ - enum { MAX_PATH_LEN= 512 }; - enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 }; - char pid_file_with_path[MAX_PATH_LEN]; - char **argv; - /* - Here we cache the version string, obtained from mysqld --version. - In the case when mysqld binary is not found we get NULL here. - */ - const char *mysqld_version; - /* We need the some options, so we store them as a separate pointers */ - const char *mysqld_socket; - const char *mysqld_datadir; - const char *mysqld_pid_file; - LEX_STRING instance_name; - LEX_STRING mysqld_path; - LEX_STRING mysqld_real_path; - const char *nonguarded; - /* log enums are defined in parse.h */ - char *logs[3]; - -private: - bool fill_log_options(); - bool fill_instance_version(); - bool fill_mysqld_real_path(); - int add_to_argv(const char *option); - int get_default_option(char *result, size_t result_len, - const char *option_name); - - void update_var(const char *option_name, const char *option_value); - int find_option(const char *option_name); - -private: - const char *mysqld_port; - uint mysqld_port_val; - const char *shutdown_delay; - uint shutdown_delay_val; - - uint filled_default_options; - MEM_ROOT alloc; - - Named_value_arr options; -}; - - -inline int Instance_options::get_num_options() const -{ - return options.get_size(); -} - - -inline Named_value Instance_options::get_option(int idx) const -{ - return options.get_element(idx); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */ diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc deleted file mode 100644 index 4d8a33e7db1..00000000000 --- a/server-tools/instance-manager/listener.cc +++ /dev/null @@ -1,337 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "listener.h" - -#include <my_global.h> -#include <mysql.h> -#include <violite.h> - -#include <sys/stat.h> -#ifndef __WIN__ -#include <sys/un.h> -#endif - -#include "log.h" -#include "mysql_connection.h" -#include "options.h" -#include "portability.h" -#include "priv.h" -#include "thread_registry.h" - - -static void set_non_blocking(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFL, 0); - fcntl(socket, F_SETFL, flags | O_NONBLOCK); -#else - u_long arg= 1; - ioctlsocket(socket, FIONBIO, &arg); -#endif -} - - -static void set_no_inherit(int socket) -{ -#ifndef __WIN__ - int flags= fcntl(socket, F_GETFD, 0); - fcntl(socket, F_SETFD, flags | FD_CLOEXEC); -#endif -} - -const int Listener::LISTEN_BACK_LOG_SIZE= 5; /* standard backlog size */ - -Listener::Listener(Thread_registry *thread_registry_arg, - User_map *user_map_arg) - :thread_registry(thread_registry_arg), - user_map(user_map_arg), - total_connection_count(0), - num_sockets(0) -{ -} - - -/* - Listener::run() - listen all supported sockets and spawn a thread - to handle incoming connection. - Using 'die' in case of syscall failure is OK now - we don't hold any - resources and 'die' kills the signal thread automatically. To be rewritten - one day. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. -*/ - -void Listener::run() -{ - int i, n= 0; - -#ifndef __WIN__ - struct sockaddr_un unix_socket_address; -#endif - - log_info("Listener: started."); - - thread_registry->register_thread(&thread_info); - - FD_ZERO(&read_fds); - - /* I. prepare 'listen' sockets */ - if (create_tcp_socket()) - goto err; - -#ifndef __WIN__ - if (create_unix_socket(unix_socket_address)) - goto err; -#endif - - /* II. Listen sockets and spawn childs */ - for (i= 0; i < num_sockets; i++) - n= max(n, sockets[i]); - n++; - - timeval tv; - while (!thread_registry->is_shutdown()) - { - fd_set read_fds_arg= read_fds; - /* - We should reintialize timer as on linux it is modified - to reflect amount of time not slept. - */ - tv.tv_sec= 0; - tv.tv_usec= 100000; - - /* - When using valgrind 2.0 this syscall doesn't get kicked off by a - signal during shutdown. This results in failing assert - (Thread_registry::~Thread_registry). Valgrind 2.2 works fine. - */ - int rc= select(n, &read_fds_arg, 0, 0, &tv); - - if (rc == 0 || rc == -1) - { - if (rc == -1 && errno != EINTR) - log_error("Listener: select() failed: %s.", - (const char *) strerror(errno)); - continue; - } - - - for (int socket_index= 0; socket_index < num_sockets; socket_index++) - { - /* Assuming that rc > 0 as we asked to wait forever */ - if (FD_ISSET(sockets[socket_index], &read_fds_arg)) - { - int client_fd= accept(sockets[socket_index], 0, 0); - /* accept may return -1 (failure or spurious wakeup) */ - if (client_fd >= 0) // connection established - { - set_no_inherit(client_fd); - - struct st_vio *vio= - vio_new(client_fd, - socket_index == 0 ? VIO_TYPE_SOCKET : VIO_TYPE_TCPIP, - socket_index == 0 ? 1 : 0); - - if (vio != NULL) - handle_new_mysql_connection(vio); - else - { - shutdown(client_fd, SHUT_RDWR); - closesocket(client_fd); - } - } - } - } - } - - /* III. Release all resources and exit */ - - log_info("Listener: shutdown requested, exiting..."); - - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - -#ifndef __WIN__ - unlink(unix_socket_address.sun_path); -#endif - - thread_registry->unregister_thread(&thread_info); - - log_info("Listener: finished."); - return; - -err: - log_error("Listener: failed to initialize. Initiate shutdown..."); - - // we have to close the ip sockets in case of error - for (i= 0; i < num_sockets; i++) - closesocket(sockets[i]); - - thread_registry->set_error_status(); - thread_registry->unregister_thread(&thread_info); - thread_registry->request_shutdown(); - return; -} - -int Listener::create_tcp_socket() -{ - /* value to be set by setsockopt */ - int arg= 1; - - int ip_socket= socket(AF_INET, SOCK_STREAM, 0); - if (ip_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_INET) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - struct sockaddr_in ip_socket_address; - bzero(&ip_socket_address, sizeof(ip_socket_address)); - - ulong im_bind_addr; - if (Options::Main::bind_address != 0) - { - im_bind_addr= (ulong) inet_addr(Options::Main::bind_address); - - if (im_bind_addr == (ulong) INADDR_NONE) - im_bind_addr= htonl(INADDR_ANY); - } - else - im_bind_addr= htonl(INADDR_ANY); - uint im_port= Options::Main::port_number; - - ip_socket_address.sin_family= AF_INET; - ip_socket_address.sin_addr.s_addr= im_bind_addr; - - - ip_socket_address.sin_port= (unsigned short) - htons((unsigned short) im_port); - - setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg)); - if (bind(ip_socket, (struct sockaddr *) &ip_socket_address, - sizeof(ip_socket_address))) - { - log_error("Listener: bind(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - if (listen(ip_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(ip socket) failed: %s.", - (const char *) strerror(errno)); - closesocket(ip_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(ip_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(ip_socket); - - FD_SET(ip_socket, &read_fds); - sockets[num_sockets++]= ip_socket; - log_info("Listener: accepting connections on ip socket (port: %d)...", - (int) im_port); - return 0; -} - -#ifndef __WIN__ -int Listener:: -create_unix_socket(struct sockaddr_un &unix_socket_address) -{ - int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0); - if (unix_socket == INVALID_SOCKET) - { - log_error("Listener: socket(AF_UNIX) failed: %s.", - (const char *) strerror(errno)); - return -1; - } - - bzero(&unix_socket_address, sizeof(unix_socket_address)); - - unix_socket_address.sun_family= AF_UNIX; - strmake(unix_socket_address.sun_path, Options::Main::socket_file_name, - sizeof(unix_socket_address.sun_path)); - unlink(unix_socket_address.sun_path); // in case we have stale socket file - - /* - POSIX specifies default permissions for a pathname created by bind - to be 0777. We need everybody to have access to the socket. - */ - mode_t old_mask= umask(0); - if (bind(unix_socket, (struct sockaddr *) &unix_socket_address, - sizeof(unix_socket_address))) - { - log_error("Listener: bind(unix socket) failed for '%s': %s.", - (const char *) unix_socket_address.sun_path, - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - umask(old_mask); - - if (listen(unix_socket, LISTEN_BACK_LOG_SIZE)) - { - log_error("Listener: listen(unix socket) failed: %s.", - (const char *) strerror(errno)); - close(unix_socket); - return -1; - } - - /* set the socket nonblocking */ - set_non_blocking(unix_socket); - - /* make sure that instances won't be listening our sockets */ - set_no_inherit(unix_socket); - - log_info("Listener: accepting connections on unix socket '%s'...", - (const char *) unix_socket_address.sun_path); - sockets[num_sockets++]= unix_socket; - FD_SET(unix_socket, &read_fds); - return 0; -} -#endif - - -/* - Create new mysql connection. Created thread is responsible for deletion of - the Mysql_connection and Vio instances passed to it. - SYNOPSIS - handle_new_mysql_connection() -*/ - -void Listener::handle_new_mysql_connection(struct st_vio *vio) -{ - Mysql_connection *mysql_connection= - new Mysql_connection(thread_registry, user_map, - vio, ++total_connection_count); - if (mysql_connection == NULL || mysql_connection->start(Thread::DETACHED)) - { - log_error("Listener: can not start connection handler."); - delete mysql_connection; - vio_delete(vio); - } - /* The connection will delete itself when the thread is finished */ -} diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h deleted file mode 100644 index 964fb361fb5..00000000000 --- a/server-tools/instance-manager/listener.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H - -#include "thread_registry.h" - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class Thread_registry; -class User_map; - -/** - Listener - a thread listening on sockets and spawning - connection threads. -*/ - -class Listener: public Thread -{ -public: - Listener(Thread_registry *thread_registry_arg, User_map *user_map_arg); - -protected: - virtual void run(); - -private: - static const int LISTEN_BACK_LOG_SIZE; - -private: - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - - ulong total_connection_count; - - int sockets[2]; - int num_sockets; - fd_set read_fds; - -private: - void handle_new_mysql_connection(struct st_vio *vio); - int create_tcp_socket(); - int create_unix_socket(struct sockaddr_un &unix_socket_address); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc deleted file mode 100644 index 9f276523e49..00000000000 --- a/server-tools/instance-manager/log.cc +++ /dev/null @@ -1,196 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "log.h" - -#include <my_global.h> -#include <m_string.h> -#include <my_sys.h> - -#include <stdarg.h> - -#include "portability.h" /* for vsnprintf() on Windows. */ - -/* - TODO: - - add flexible header support - - rewrite all fprintf with fwrite - - think about using 'write' instead of fwrite/fprintf on POSIX systems -*/ - -/* - Format log entry and write it to the given stream. - SYNOPSIS - log() -*/ - -static void log(FILE *file,const char *level_tag, const char *format, - va_list args) -{ - /* - log() should be thread-safe; it implies that we either call fprintf() - once per log(), or use flockfile()/funlockfile(). But flockfile() is - POSIX, not ANSI C, so we try to vsnprintf the whole message to the - stack, and if stack buffer is not enough, to malloced string. When - message is formatted, it is fprintf()'ed to the file. - */ - - /* Format time like MYSQL_LOG does. */ - time_t now= time(0); - struct tm bd_time; // broken-down time - localtime_r(&now, &bd_time); - - char buff_date[128]; - sprintf(buff_date, "[%d/%lu] [%02d/%02d/%02d %02d:%02d:%02d] [%s] ", - (int) getpid(), - (unsigned long) pthread_self(), - (int) bd_time.tm_year % 100, - (int) bd_time.tm_mon + 1, - (int) bd_time.tm_mday, - (int) bd_time.tm_hour, - (int) bd_time.tm_min, - (int) bd_time.tm_sec, - (const char *) level_tag); - /* Format the message */ - char buff_stack[256]; - - int n= vsnprintf(buff_stack, sizeof(buff_stack), format, args); - /* - return value of vsnprintf can vary, according to various standards; - try to check all cases. - */ - char *buff_msg= buff_stack; - if (n < 0 || n == sizeof(buff_stack)) - { - int size= sizeof(buff_stack) * 2; - buff_msg= (char*) my_malloc(size, MYF(0)); - while (TRUE) - { - if (buff_msg == 0) - { - strmake(buff_stack, "log(): message is too big, my_malloc() failed", - sizeof(buff_stack) - 1); - buff_msg= buff_stack; - break; - } - n = vsnprintf(buff_msg, size, format, args); - if (n >= 0 && n < size) - break; - size*= 2; - /* realloc() does unnecessary memcpy */ - my_free(buff_msg, 0); - buff_msg= (char*) my_malloc(size, MYF(0)); - } - } - else if ((size_t) n > sizeof(buff_stack)) - { - buff_msg= (char*) my_malloc(n + 1, MYF(0)); -#ifdef DBUG - DBUG_ASSERT(n == vsnprintf(buff_msg, n + 1, format, args)); -#else - vsnprintf(buff_msg, n + 1, format, args); -#endif - } - fprintf(file, "%s%s\n", buff_date, buff_msg); - if (buff_msg != buff_stack) - my_free(buff_msg, 0); - - /* don't fflush() the file: buffering strategy is set in log_init() */ -} - -/************************************************************************** - Logging: implementation of public interface. -**************************************************************************/ - -/* - The function initializes logging sub-system. - - SYNOPSIS - log_init() -*/ - -void log_init() -{ - /* - stderr is unbuffered by default; there is no good of line buffering, - as all logging is performed linewise - so remove buffering from stdout - also - */ - setbuf(stdout, 0); -} - - -/* - The function is intended to log error messages. It precedes a message - with date, time and [ERROR] tag and print it to the stderr and stdout. - - We want to print it on stdout to be able to know in which context we got the - error - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_error(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "ERROR", format, args); - fflush(stdout); - log(stderr, "ERROR", format, args); - fflush(stderr); - va_end(args); -} - - -/* - The function is intended to log information messages. It precedes - a message with date, time and [INFO] tag and print it to the stdout. - - SYNOPSIS - log_error() - format [IN] format string - ... [IN] arguments to format -*/ - -void log_info(const char *format, ...) -{ - va_list args; - va_start(args, format); - log(stdout, "INFO", format, args); - va_end(args); -} - -/* - The function prints information to the error log and eixt(1). - - SYNOPSIS - die() - format [IN] format string - ... [IN] arguments to format -*/ - -void die(const char *format, ...) -{ - va_list args; - fprintf(stderr,"%s: ", my_progname); - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\n"); - exit(1); -} diff --git a/server-tools/instance-manager/log.h b/server-tools/instance-manager/log.h deleted file mode 100644 index e6c3b55c54c..00000000000 --- a/server-tools/instance-manager/log.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H - -/* - Logging facilities. - - Two logging streams are supported: error log and info log. - Additionally libdbug may be used for debug information output. - - ANSI C buffered I/O is used to perform logging. - - Logging is performed via stdout/stder, so one can reopen them to point to - ordinary files. To initialize logging environment log_init() must be called. - - Rationale: - - no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h - - no constructors/desctructors to make logging available all the time -*/ - - -void log_init(); - - -void log_info(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format(printf, 1, 2))) -#endif - ; - - -void log_error(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - - -void die(const char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))) -#endif - ; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc deleted file mode 100644 index 792461e41a9..00000000000 --- a/server-tools/instance-manager/manager.cc +++ /dev/null @@ -1,526 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "manager.h" - -#include <my_global.h> -#include <m_string.h> -#include <my_sys.h> -#include <thr_alarm.h> - -#include <signal.h> -#ifndef __WIN__ -#include <sys/wait.h> -#endif - -#include "exit_codes.h" -#include "guardian.h" -#include "instance_map.h" -#include "listener.h" -#include "mysql_manager_error.h" -#include "mysqld_error.h" -#include "log.h" -#include "options.h" -#include "priv.h" -#include "thread_registry.h" -#include "user_map.h" - - -/********************************************************************** - {{{ Platform-specific implementation. -**********************************************************************/ - -#ifndef __WIN__ -void set_signals(sigset_t *mask) -{ - /* block signals */ - sigemptyset(mask); - sigaddset(mask, SIGINT); - sigaddset(mask, SIGTERM); - sigaddset(mask, SIGPIPE); - sigaddset(mask, SIGHUP); - signal(SIGPIPE, SIG_IGN); - - /* - We want this signal to be blocked in all theads but the signal - one. It is needed for the thr_alarm subsystem to work. - */ - sigaddset(mask,THR_SERVER_ALARM); - - /* all new threads will inherite this signal mask */ - pthread_sigmask(SIG_BLOCK, mask, NULL); - - /* - In our case the signal thread also implements functions of alarm thread. - Here we init alarm thread functionality. We suppose that we won't have - more then 10 alarms at the same time. - */ - init_thr_alarm(10); -} -#else - -bool have_signal; - -void onsignal(int signo) -{ - have_signal= TRUE; -} - -void set_signals(sigset_t *set) -{ - signal(SIGINT, onsignal); - signal(SIGTERM, onsignal); - have_signal= FALSE; -} - -int my_sigwait(const sigset_t *set, int *sig) -{ - while (!have_signal) - { - Sleep(100); - } - return 0; -} - -#endif - -/********************************************************************** - }}} -**********************************************************************/ - - -/********************************************************************** - {{{ Implementation of checking the actual thread model. -***********************************************************************/ - -namespace { /* no-indent */ - -class ThreadModelChecker: public Thread -{ -public: - ThreadModelChecker() - :main_pid(getpid()) - { } - -public: - inline bool is_linux_threads() const - { - return linux_threads; - } - -protected: - virtual void run() - { - linux_threads= main_pid != getpid(); - } - -private: - pid_t main_pid; - bool linux_threads; -}; - -bool check_if_linux_threads(bool *linux_threads) -{ - ThreadModelChecker checker; - - if (checker.start() || checker.join()) - return TRUE; - - *linux_threads= checker.is_linux_threads(); - - return FALSE; -} - -} - -/********************************************************************** - }}} -***********************************************************************/ - - -/********************************************************************** - Manager implementation -***********************************************************************/ - -Guardian *Manager::p_guardian; -Instance_map *Manager::p_instance_map; -Thread_registry *Manager::p_thread_registry; -User_map *Manager::p_user_map; - -#ifndef __WIN__ -bool Manager::linux_threads; -#endif // __WIN__ - - -/** - Request shutdown of guardian and threads registered in Thread_registry. - - SYNOPSIS - stop_all_threads() -*/ - -void Manager::stop_all_threads() -{ - /* - Let Guardian thread know that it should break it's processing cycle, - once it wakes up. - */ - p_guardian->request_shutdown(); - - /* Stop all threads. */ - p_thread_registry->deliver_shutdown(); - - /* Set error status in the thread registry. */ - p_thread_registry->set_error_status(); -} - - -/** - Initialize user map and load password file. - - SYNOPSIS - init_user_map() - - RETURN - FALSE on success - TRUE on failure -*/ - -bool Manager::init_user_map(User_map *user_map) -{ - int err_code; - const char *err_msg; - - if (user_map->init()) - { - log_error("Manager: can not initialize user list: out of memory."); - return TRUE; - } - - err_code= user_map->load(Options::Main::password_file_name, &err_msg); - - if (!err_code) - return FALSE; - - if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST && - Options::Main::mysqld_safe_compatible) - { - /* - The password file does not exist, but we are running in - mysqld_safe-compatible mode. Continue, but complain in log. - */ - - log_info("Warning: password file does not exist, " - "nobody will be able to connect to Instance Manager."); - - return FALSE; - } - - log_error("Manager: %s.", (const char *) err_msg); - - return TRUE; -} - - -/** - Main manager function. - - SYNOPSIS - main() - - DESCRIPTION - This is an entry point to the main instance manager process: - start listener thread, write pid file and enter into signal handling. - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - - RETURNS - main() returns exit status (exit code). -*/ - -int Manager::main() -{ - bool shutdown_complete= FALSE; - pid_t manager_pid= getpid(); - - log_info("Manager: initializing..."); - -#ifndef __WIN__ - if (check_if_linux_threads(&linux_threads)) - { - log_error("Manager: can not determine thread model."); - return 1; - } - - log_info("Manager: detected threads model: %s.", - (const char *) (linux_threads ? "LINUX threads" : "POSIX threads")); -#endif // __WIN__ - - /* - All objects created in the Manager object live as long as thread_registry - lives, and thread_registry is alive until there are working threads. - - There are two main purposes of the Thread Registry: - 1. Interrupt blocking I/O and signal condition variables in case of - shutdown; - 2. Wait for detached threads before shutting down the main thread. - - NOTE: - 1. Handling shutdown can be done in more elegant manner by introducing - Event (or Condition) object with support of logical operations. - 2. Using Thread Registry to wait for detached threads is definitely not - the best way, because when Thread Registry unregisters an thread, the - thread is still alive. Accurate way to wait for threads to stop is - not using detached threads and join all threads before shutdown. - */ - - Thread_registry thread_registry; - User_map user_map; - Instance_map instance_map; - Guardian guardian(&thread_registry, &instance_map); - - Listener listener(&thread_registry, &user_map); - - p_instance_map= &instance_map; - p_guardian= &guardian; - p_thread_registry= &thread_registry; - p_user_map= &user_map; - - /* Initialize instance map. */ - - if (instance_map.init()) - { - log_error("Manager: can not initialize instance list: out of memory."); - return 1; - } - - /* Initialize user db. */ - - if (init_user_map(&user_map)) - return 1; /* logging has been already done. */ - - /* Write Instance Manager pid file. */ - - if (create_pid_file(Options::Main::pid_file_name, manager_pid)) - return 1; /* necessary logging has been already done. */ - - log_info("Manager: pid file (%s) created.", - (const char *) Options::Main::pid_file_name); - - /* - Initialize signals and alarm-infrastructure. - - NOTE: To work nicely with LinuxThreads, the signal thread is the first - thread in the process. - - NOTE: After init_thr_alarm() call it's possible to call thr_alarm() - (from different threads), that results in sending ALARM signal to the - alarm thread (which can be the main thread). That signal can interrupt - blocking calls. In other words, a blocking call can be interrupted in - the main thread after init_thr_alarm(). - */ - - sigset_t mask; - set_signals(&mask); - - /* - Create the guardian thread. The newly started thread will block until - we actually load instances. - - NOTE: Guardian should be shutdown first. Only then all other threads - can be stopped. This should be done in this order because the guardian - is responsible for shutting down all the guarded instances, and this - is a long operation. - - NOTE: Guardian uses thr_alarm() when detects the current state of an - instance (is_running()), but this does not interfere with - flush_instances() call later in the code, because until - flush_instances() completes in the main thread, Guardian thread is not - permitted to process instances. And before flush_instances() has - completed, there are no instances to guard. - */ - - if (guardian.start(Thread::DETACHED)) - { - log_error("Manager: can not start Guardian thread."); - goto err; - } - - /* Load instances. */ - - if (Manager::flush_instances()) - { - log_error("Manager: can not init instances repository."); - stop_all_threads(); - goto err; - } - - /* Initialize the Listener. */ - - if (listener.start(Thread::DETACHED)) - { - log_error("Manager: can not start Listener thread."); - stop_all_threads(); - goto err; - } - - /* - After the list of guarded instances have been initialized, - Guardian should start them. - */ - - guardian.ping(); - - /* Main loop. */ - - log_info("Manager: started."); - - while (!shutdown_complete) - { - int signo; - int status= 0; - - if ((status= my_sigwait(&mask, &signo)) != 0) - { - log_error("Manager: sigwait() failed"); - stop_all_threads(); - goto err; - } - - /* - The general idea in this loop is the following: - - we are waiting for SIGINT, SIGTERM -- signals that mean we should - shutdown; - - as shutdown signal is caught, we stop Guardian thread (by calling - Guardian::request_shutdown()); - - as Guardian is stopped, it sends SIGTERM to this thread - (by calling Thread_registry::request_shutdown()), so that the - my_sigwait() above returns; - - as we catch the second SIGTERM, we send signals to all threads - registered in Thread_registry (by calling - Thread_registry::deliver_shutdown()) and waiting for threads to stop; - */ - -#ifndef __WIN__ -/* - On some Darwin kernels SIGHUP is delivered along with most - signals. This is why we skip it's processing on these - platforms. For more details and test program see - Bug #14164 IM tests fail on MacOS X (powermacg5) -*/ -#ifdef IGNORE_SIGHUP_SIGQUIT - if (SIGHUP == signo) - continue; -#endif - if (THR_SERVER_ALARM == signo) - process_alarm(signo); - else -#endif - { - log_info("Manager: got shutdown signal."); - - if (!guardian.is_stopped()) - { - guardian.request_shutdown(); - } - else - { - thread_registry.deliver_shutdown(); - shutdown_complete= TRUE; - } - } - } - - log_info("Manager: finished."); - -err: - /* delete the pid file */ - my_delete(Options::Main::pid_file_name, MYF(0)); - -#ifndef __WIN__ - /* free alarm structures */ - end_thr_alarm(1); -#endif - - return thread_registry.get_error_status() ? 1 : 0; -} - - -/** - Re-read instance configuration file. - - SYNOPSIS - flush_instances() - - DESCRIPTION - This function will: - - clear the current list of instances. This removes both - running and stopped instances. - - load a new instance configuration from the file. - - pass on the new map to the guardian thread: it will start - all instances that are marked `guarded' and not yet started. - - Note, as the check whether an instance is started is currently - very simple (returns TRUE if there is a MySQL server running - at the given port), this function has some peculiar - side-effects: - * if the port number of a running instance was changed, the - old instance is forgotten, even if it was running. The new - instance will be started at the new port. - * if the configuration was changed in a way that two - instances swapped their port numbers, the guardian thread - will not notice that and simply report that both instances - are configured successfully and running. - - In order to avoid such side effects one should never call - FLUSH INSTANCES without prior stop of all running instances. - - RETURN - 0 On success - ER_OUT_OF_RESOURCES Not enough resources to complete the operation - ER_THERE_IS_ACTIVE_INSTACE If there is an active instance -*/ - -int Manager::flush_instances() -{ - p_instance_map->lock(); - - if (p_instance_map->is_there_active_instance()) - { - p_instance_map->unlock(); - return ER_THERE_IS_ACTIVE_INSTACE; - } - - if (p_instance_map->reset()) - { - p_instance_map->unlock(); - return ER_OUT_OF_RESOURCES; - } - - if (p_instance_map->load()) - { - p_instance_map->unlock(); - - /* Don't init guardian if we failed to load instances. */ - return ER_OUT_OF_RESOURCES; - } - - get_guardian()->init(); - get_guardian()->ping(); - - p_instance_map->unlock(); - - return 0; -} diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h deleted file mode 100644 index e6956884603..00000000000 --- a/server-tools/instance-manager/manager.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -#include <my_global.h> - -class Guardian; -class Instance_map; -class Thread_registry; -class User_map; - -class Manager -{ -public: - static int main(); - - static int flush_instances(); - -public: - /** - These methods return a non-NULL value only for the duration - of main(). - */ - static Instance_map *get_instance_map() { return p_instance_map; } - static Guardian *get_guardian() { return p_guardian; } - static Thread_registry *get_thread_registry() { return p_thread_registry; } - static User_map *get_user_map() { return p_user_map; } - -public: -#ifndef __WIN__ - static bool is_linux_threads() { return linux_threads; } -#endif // __WIN__ - -private: - static void stop_all_threads(); - static bool init_user_map(User_map *user_map); - -private: - static Guardian *p_guardian; - static Instance_map *p_instance_map; - static Thread_registry *p_thread_registry; - static User_map *p_user_map; - -#ifndef __WIN__ - /* - This flag is set if Instance Manager is running on the system using - LinuxThreads. - */ - static bool linux_threads; -#endif // __WIN__ -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc deleted file mode 100644 index 201ebfd62fc..00000000000 --- a/server-tools/instance-manager/messages.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "messages.h" - -#include <my_global.h> -#include <mysql_com.h> - -#include "mysqld_error.h" -#include "mysql_manager_error.h" - - -static const char *mysqld_error_message(unsigned sql_errno) -{ - switch (sql_errno) { - case ER_HANDSHAKE_ERROR: - return "Bad handshake"; - case ER_OUT_OF_RESOURCES: - return "Out of memory; Check if mysqld or some other process" - " uses all available memory. If not you may have to use" - " 'ulimit' to allow mysqld to use more memory or you can" - " add more swap space"; - case ER_ACCESS_DENIED_ERROR: - return "Access denied. Bad username/password pair"; - case ER_NOT_SUPPORTED_AUTH_MODE: - return "Client does not support authentication protocol requested by" - " server; consider upgrading MySQL client"; - case ER_UNKNOWN_COM_ERROR: - return "Unknown command"; - case ER_SYNTAX_ERROR: - return "You have an error in your command syntax. Check the manual that" - " corresponds to your MySQL Instance Manager version for the right" - " syntax to use"; - case ER_BAD_INSTANCE_NAME: - return "Unknown instance name"; - case ER_INSTANCE_IS_NOT_STARTED: - return "Cannot stop instance. Perhaps the instance is not started, or was" - " started manually, so IM cannot find the pidfile."; - case ER_INSTANCE_ALREADY_STARTED: - return "The instance is already started"; - case ER_CANNOT_START_INSTANCE: - return "Cannot start instance. Possible reasons are wrong instance options" - " or resources shortage"; - case ER_OFFSET_ERROR: - return "Cannot read negative number of bytes"; - case ER_STOP_INSTANCE: - return "Cannot stop instance"; - case ER_READ_FILE: - return "Cannot read requested part of the logfile"; - case ER_NO_SUCH_LOG: - return "The instance has no such log enabled"; - case ER_OPEN_LOGFILE: - return "Cannot open log file"; - case ER_GUESS_LOGFILE: - return "Cannot guess the log filename. Try specifying full log name" - " in the instance options"; - case ER_ACCESS_OPTION_FILE: - return "Cannot open the option file to edit. Check permissions"; - case ER_DROP_ACTIVE_INSTANCE: - return "Cannot drop an active instance. You should stop it first"; - case ER_CREATE_EXISTING_INSTANCE: - return "Instance already exists"; - case ER_INSTANCE_MISCONFIGURED: - return "Instance is misconfigured. Cannot start it"; - case ER_MALFORMED_INSTANCE_NAME: - return "Malformed instance name."; - case ER_INSTANCE_IS_ACTIVE: - return "The instance is active. Stop the instance first"; - case ER_THERE_IS_ACTIVE_INSTACE: - return "At least one instance is active. Stop all instances first"; - case ER_INCOMPATIBLE_OPTION: - return "Instance Manager-specific options are prohibited from being used " - "in the configuration of mysqld-compatible instances"; - case ER_CONF_FILE_DOES_NOT_EXIST: - return "Configuration file does not exist"; - default: - DBUG_ASSERT(0); - return 0; - } -} - - -const char *message(unsigned sql_errno) -{ - return mysqld_error_message(sql_errno); -} - - -const char *errno_to_sqlstate(unsigned sql_errno) -{ - return mysql_errno_to_sqlstate(sql_errno); -} diff --git a/server-tools/instance-manager/messages.h b/server-tools/instance-manager/messages.h deleted file mode 100644 index 5d9383093bc..00000000000 --- a/server-tools/instance-manager/messages.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H - -const char *message(unsigned sql_errno); - -const char *errno_to_sqlstate(unsigned sql_errno); - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc deleted file mode 100644 index 12ea0a3ea5a..00000000000 --- a/server-tools/instance-manager/mysql_connection.cc +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "mysql_connection.h" - -#include <m_string.h> -#include <m_string.h> -#include <my_global.h> -#include <mysql.h> -#include <my_sys.h> -#include <violite.h> - -#include "command.h" -#include "log.h" -#include "messages.h" -#include "mysqld_error.h" -#include "mysql_manager_error.h" -#include "parse.h" -#include "priv.h" -#include "protocol.h" -#include "thread_registry.h" -#include "user_map.h" - - -Mysql_connection::Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, ulong - connection_id_arg) - :vio(vio_arg), - connection_id(connection_id_arg), - thread_registry(thread_registry_arg), - user_map(user_map_arg) -{ -} - - -/* - NET subsystem requieres its user to provide my_net_local_init extern - C function (exactly as declared below). my_net_local_init is called by - my_net_init and is supposed to set NET controlling variables. - See also priv.h for variables description. -*/ - -C_MODE_START - -void my_net_local_init(NET *net) -{ - net->max_packet= net_buffer_length; - my_net_set_read_timeout(net, (uint)net_read_timeout); - my_net_set_write_timeout(net, (uint)net_write_timeout); - net->retry_count= net_retry_count; - net->max_packet_size= max_allowed_packet; -} - -C_MODE_END - -/* - Unused stub hook required for linking the client API. -*/ - -C_MODE_START - -void slave_io_thread_detach_vio() -{ -} - -C_MODE_END - - -/* - Every resource, which we can fail to acquire, is allocated in init(). - This function is complementary to cleanup(). -*/ - -bool Mysql_connection::init() -{ - /* Allocate buffers for network I/O */ - if (my_net_init(&net, vio)) - return TRUE; - - net.return_status= &status; - - /* Initialize random number generator */ - { - ulong seed1= (ulong) &rand_st + rand(); - ulong seed2= (ulong) rand() + (ulong) time(0); - randominit(&rand_st, seed1, seed2); - } - - /* Fill scramble - server's random message used for handshake */ - create_random_string(scramble, SCRAMBLE_LENGTH, &rand_st); - - /* We don't support transactions, every query is atomic */ - status= SERVER_STATUS_AUTOCOMMIT; - - thread_registry->register_thread(&thread_info); - - return FALSE; -} - - -void Mysql_connection::cleanup() -{ - net_end(&net); - thread_registry->unregister_thread(&thread_info); -} - - -Mysql_connection::~Mysql_connection() -{ - /* vio_delete closes the socket if necessary */ - vio_delete(vio); -} - - -void Mysql_connection::main() -{ - log_info("Connection %lu: accepted.", (unsigned long) connection_id); - - if (check_connection()) - { - log_info("Connection %lu: failed to authorize the user.", - (unsigned long) connection_id); - - return; - } - - log_info("Connection %lu: the user was authorized successfully.", - (unsigned long) connection_id); - - vio_keepalive(vio, TRUE); - - while (!net.error && net.vio && !thread_registry->is_shutdown()) - { - if (do_command()) - break; - } -} - - -int Mysql_connection::check_connection() -{ - ulong pkt_len=0; // to hold client reply length - - /* buffer for the first packet */ /* packet contains: */ - uchar buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended - 4 + // connection id - SCRAMBLE_LENGTH + 2 + // scramble (in 2 pieces) - 18]; // server variables: flags, - // charset number, status, - uchar *pos= buff; - ulong server_flags; - - memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1); - pos+= mysqlmanager_version.length + 1; - - int4store((uchar*) pos, connection_id); - pos+= 4; - - /* - Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of the scramble is placed here, and second - part at the end of packet (even though we don't support old clients, - we must follow standard packet format.) - */ - memcpy(pos, scramble, SCRAMBLE_LENGTH_323); - pos+= SCRAMBLE_LENGTH_323; - *pos++= '\0'; - - server_flags= CLIENT_LONG_FLAG | CLIENT_PROTOCOL_41 | - CLIENT_SECURE_CONNECTION; - - /* - 18-bytes long section for various flags/variables - - Every flag occupies a bit in first half of ulong; int2store will - gracefully pick up all flags. - */ - int2store(pos, server_flags); - pos+= 2; - *pos++= (char) default_charset_info->number; // global mysys variable - int2store(pos, status); // connection status - pos+= 2; - bzero(pos, 13); // not used now - pos+= 13; - - /* second part of the scramble, null-terminated */ - memcpy(pos, scramble + SCRAMBLE_LENGTH_323, - SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1); - pos+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1; - - /* write connection message and read reply */ - enum { MIN_HANDSHAKE_SIZE= 2 }; - if (net_write_command(&net, protocol_version, (uchar*) "", 0, - buff, pos - buff) || - (pkt_len= my_net_read(&net)) == packet_error || - pkt_len < MIN_HANDSHAKE_SIZE) - { - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - client_capabilities= uint2korr(net.read_pos); - if (!(client_capabilities & CLIENT_PROTOCOL_41)) - { - net_send_error_323(&net, ER_NOT_SUPPORTED_AUTH_MODE); - return 1; - } - client_capabilities|= ((ulong) uint2korr(net.read_pos + 2)) << 16; - - pos= net.read_pos + 32; - - /* At least one byte for username and one byte for password */ - if (pos >= net.read_pos + pkt_len + 2) - { - /*TODO add user and password handling in error messages*/ - net_send_error(&net, ER_HANDSHAKE_ERROR); - return 1; - } - - const char *user= (char*) pos; - const char *password= strend(user)+1; - ulong password_len= *password++; - LEX_STRING user_name= { (char *) user, password - user - 2 }; - - if (password_len != SCRAMBLE_LENGTH) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - if (user_map->authenticate(&user_name, password, scramble)) - { - net_send_error(&net, ER_ACCESS_DENIED_ERROR); - return 1; - } - net_send_ok(&net, connection_id, NULL); - return 0; -} - - -int Mysql_connection::do_command() -{ - char *packet; - ulong packet_length; - - /* We start to count packets from 0 for each new command */ - net.pkt_nr= 0; - - if ((packet_length=my_net_read(&net)) == packet_error) - { - /* Check if we can continue without closing the connection */ - if (net.error != 3) // what is 3 - find out - return 1; - if (thread_registry->is_shutdown()) - return 1; - net_send_error(&net, net.last_errno); - net.error= 0; - return 0; - } - else - { - if (thread_registry->is_shutdown()) - return 1; - packet= (char*) net.read_pos; - enum enum_server_command command= (enum enum_server_command) - (uchar) *packet; - log_info("Connection %lu: received packet (length: %lu; command: %d).", - (unsigned long) connection_id, - (unsigned long) packet_length, - (int) command); - - return dispatch_command(command, packet + 1); - } -} - -int Mysql_connection::dispatch_command(enum enum_server_command command, - const char *packet) -{ - switch (command) { - case COM_QUIT: // client exit - log_info("Connection %lu: received QUIT command.", - (unsigned long) connection_id); - return 1; - - case COM_PING: - log_info("Connection %lu: received PING command.", - (unsigned long) connection_id); - net_send_ok(&net, connection_id, NULL); - return 0; - - case COM_QUERY: - { - log_info("Connection %lu: received QUERY command: '%s'.", - (unsigned long) connection_id, - (const char *) packet); - - if (Command *com= parse_command(packet)) - { - int res= 0; - - log_info("Connection %lu: query parsed successfully.", - (unsigned long) connection_id); - - res= com->execute(&net, connection_id); - delete com; - if (!res) - { - log_info("Connection %lu: query executed successfully", - (unsigned long) connection_id); - } - else - { - log_info("Connection %lu: can not execute query (error: %d).", - (unsigned long) connection_id, - (int) res); - - net_send_error(&net, res); - } - } - else - { - log_error("Connection %lu: can not parse query: out ot resources.", - (unsigned long) connection_id); - - net_send_error(&net,ER_OUT_OF_RESOURCES); - } - - return 0; - } - - default: - log_info("Connection %lu: received unsupported command (%d).", - (unsigned long) connection_id, - (int) command); - - net_send_error(&net, ER_UNKNOWN_COM_ERROR); - return 0; - } - - return 0; /* Just to make compiler happy. */ -} - - -void Mysql_connection::run() -{ - if (init()) - log_error("Connection %lu: can not init handler.", - (unsigned long) connection_id); - else - { - main(); - cleanup(); - } - - delete this; -} - -/* - vim: fdm=marker -*/ diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h deleted file mode 100644 index 56bbf76e146..00000000000 --- a/server-tools/instance-manager/mysql_connection.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H - -#include "thread_registry.h" -#include <mysql_com.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -struct st_vio; -class User_map; - -/* - MySQL connection - handle one connection with mysql command line client - See also comments in mysqlmanager.cc to picture general Instance Manager - architecture. - We use conventional technique to work with classes without exceptions: - class acquires all vital resource in init(); Thus if init() succeed, - a user must call cleanup(). All other methods are valid only between - init() and cleanup(). -*/ - -class Mysql_connection: public Thread -{ -public: - Mysql_connection(Thread_registry *thread_registry_arg, - User_map *user_map_arg, - struct st_vio *vio_arg, - ulong connection_id_arg); - virtual ~Mysql_connection(); - -protected: - virtual void run(); - -private: - struct st_vio *vio; - ulong connection_id; - Thread_info thread_info; - Thread_registry *thread_registry; - User_map *user_map; - NET net; - struct rand_struct rand_st; - char scramble[SCRAMBLE_LENGTH + 1]; - uint status; - ulong client_capabilities; -private: - /* The main loop implementation triad */ - bool init(); - void main(); - void cleanup(); - - /* Names are conventionally the same as in mysqld */ - int check_connection(); - int do_command(); - int dispatch_command(enum enum_server_command command, const char *text); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h deleted file mode 100644 index e50e5d24f6d..00000000000 --- a/server-tools/instance-manager/mysql_manager_error.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Definefile for instance manager error messagenumbers */ - -#define ER_BAD_INSTANCE_NAME 3000 -#define ER_INSTANCE_IS_NOT_STARTED 3001 -#define ER_INSTANCE_ALREADY_STARTED 3002 -#define ER_CANNOT_START_INSTANCE 3003 -#define ER_STOP_INSTANCE 3004 -#define ER_NO_SUCH_LOG 3005 -#define ER_OPEN_LOGFILE 3006 -#define ER_GUESS_LOGFILE 3007 -#define ER_ACCESS_OPTION_FILE 3008 -#define ER_OFFSET_ERROR 3009 -#define ER_READ_FILE 3010 -#define ER_DROP_ACTIVE_INSTANCE 3011 -#define ER_CREATE_EXISTING_INSTANCE 3012 -#define ER_INSTANCE_MISCONFIGURED 3013 -#define ER_MALFORMED_INSTANCE_NAME 3014 -#define ER_INSTANCE_IS_ACTIVE 3015 -#define ER_THERE_IS_ACTIVE_INSTACE 3016 -#define ER_INCOMPATIBLE_OPTION 3017 -#define ER_CONF_FILE_DOES_NOT_EXIST 3018 - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */ diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc deleted file mode 100644 index 276d1ca3b49..00000000000 --- a/server-tools/instance-manager/mysqlmanager.cc +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_dir.h> -#include <my_sys.h> - -#include <string.h> - -#ifndef __WIN__ -#include <pwd.h> -#include <grp.h> -#endif - -#include "angel.h" -#include "log.h" -#include "manager.h" -#include "options.h" -#include "user_management_commands.h" - -#ifdef __WIN__ -#include "IMService.h" -#endif - - -/* - Instance Manager consists of two processes: the angel process (IM-angel), - and the manager process (IM-main). Responsibilities of IM-angel is to - monitor IM-main, and restart it in case of failure/shutdown. IM-angel is - started only if startup option '--run-as-service' is provided. - - IM-main consists of several subsystems (thread sets): - - - the signal handling thread - - The signal thread handles user signals and propagates them to the - other threads. All other threads are accounted in the signal handler - thread Thread Registry. - - - the listener - - The listener listens to all sockets. There is a listening socket for - each subsystem (TCP/IP, UNIX socket). - - - mysql subsystem - - Instance Manager acts like an ordinary MySQL Server, but with very - restricted command set. Each MySQL client connection is handled in a - separate thread. All MySQL client connections threads constitute - mysql subsystem. -*/ - -static int main_impl(int argc, char *argv[]); - -#ifndef __WIN__ -static struct passwd *check_user(); -static bool switch_user(); -#endif - - -/************************************************************************/ -/** - The entry point. -*************************************************************************/ - -int main(int argc, char *argv[]) -{ - int return_value; - - puts("\n" - "WARNING: This program is deprecated and will be removed in 6.0.\n"); - - /* Initialize. */ - - MY_INIT(argv[0]); - log_init(); - umask(0117); - srand((uint) time(0)); - - /* Main function. */ - - log_info("IM: started."); - - return_value= main_impl(argc, argv); - - log_info("IM: finished."); - - /* Cleanup. */ - - Options::cleanup(); - my_end(0); - - return return_value; -} - - -/************************************************************************/ -/** - Instance Manager main functionality. -*************************************************************************/ - -int main_impl(int argc, char *argv[]) -{ - int rc; - - if ((rc= Options::load(argc, argv))) - return rc; - - if (Options::User_management::cmd) - return Options::User_management::cmd->execute(); - -#ifndef __WIN__ - - if (switch_user()) - return 1; - - return Options::Daemon::run_as_service ? - Angel::main() : - Manager::main(); - -#else - - return Options::Service::stand_alone ? - Manager::main() : - IMService::main(); - -#endif -} - -/************************************************************************** - OS-specific functions implementation. -**************************************************************************/ - -#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) - -/************************************************************************/ -/** - Change to run as another user if started with --user. -*************************************************************************/ - -static struct passwd *check_user() -{ - const char *user= Options::Daemon::user; - struct passwd *user_info; - uid_t user_id= geteuid(); - - /* Don't bother if we aren't superuser */ - if (user_id) - { - if (user) - { - /* Don't give a warning, if real user is same as given with --user */ - user_info= getpwnam(user); - if ((!user_info || user_id != user_info->pw_uid)) - log_info("One can only use the --user switch if running as root\n"); - } - return NULL; - } - if (!user) - { - log_info("You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.\n"); - return NULL; - } - if (!strcmp(user, "root")) - return NULL; /* Avoid problem with dynamic libraries */ - if (!(user_info= getpwnam(user))) - { - /* Allow a numeric uid to be used */ - const char *pos; - for (pos= user; my_isdigit(default_charset_info, *pos); pos++) - {} - if (*pos) /* Not numeric id */ - goto err; - if (!(user_info= getpwuid(atoi(user)))) - goto err; - else - return user_info; - } - else - return user_info; - -err: - log_error("Can not start under user '%s'.", - (const char *) user); - return NULL; -} - - -/************************************************************************/ -/** - Switch user. -*************************************************************************/ - -static bool switch_user() -{ - struct passwd *user_info= check_user(); - - if (!user_info) - return FALSE; - -#ifdef HAVE_INITGROUPS - initgroups(Options::Daemon::user, user_info->pw_gid); -#endif - - if (setgid(user_info->pw_gid) == -1) - { - log_error("setgid() failed"); - return TRUE; - } - - if (setuid(user_info->pw_uid) == -1) - { - log_error("setuid() failed"); - return TRUE; - } - - return FALSE; -} - -#endif diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc deleted file mode 100644 index ebca593bb03..00000000000 --- a/server-tools/instance-manager/options.cc +++ /dev/null @@ -1,558 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "options.h" - -#include <my_global.h> -#include <my_sys.h> -#include <my_getopt.h> -#include <mysql_com.h> - -#include "exit_codes.h" -#include "log.h" -#include "portability.h" -#include "priv.h" -#include "user_management_commands.h" - -#define QUOTE2(x) #x -#define QUOTE(x) QUOTE2(x) - -#ifdef __WIN__ - -/* Define holders for default values. */ - -static char win_dflt_config_file_name[FN_REFLEN]; -static char win_dflt_password_file_name[FN_REFLEN]; -static char win_dflt_pid_file_name[FN_REFLEN]; - -static char win_dflt_mysqld_path[FN_REFLEN]; - -/* Define and initialize Windows-specific options. */ - -my_bool Options::Service::install_as_service; -my_bool Options::Service::remove_service; -my_bool Options::Service::stand_alone; - -const char *Options::Main::config_file= win_dflt_config_file_name; -const char *Options::Main::password_file_name= win_dflt_password_file_name; -const char *Options::Main::pid_file_name= win_dflt_pid_file_name; - -const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path; - -static int setup_windows_defaults(); - -#else /* UNIX */ - -/* Define and initialize UNIX-specific options. */ - -my_bool Options::Daemon::run_as_service= FALSE; -const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); -const char *Options::Daemon::user= NULL; /* No default value */ -const char *Options::Daemon::angel_pid_file_name= NULL; - -const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE); -const char * -Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); -const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); -const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); - -const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH); - -#endif - -/* Remember if the config file was forced. */ - -bool Options::Main::is_forced_default_file= FALSE; - -/* Define and initialize common options. */ - -const char *Options::Main::bind_address= NULL; /* No default value */ -uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL; -uint Options::Main::port_number= DEFAULT_PORT; -my_bool Options::Main::mysqld_safe_compatible= FALSE; -const char **Options::default_directories= NULL; - -/* Options::User_management */ - -char *Options::User_management::user_name= NULL; -char *Options::User_management::password= NULL; - -User_management_cmd *Options::User_management::cmd= NULL; - -/* Private members. */ - -char **Options::saved_argv= NULL; - -#ifndef DBUG_OFF -const char *Options::Debug::config_str= "d:t:i:O,im.trace"; -#endif - -static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid"; -static const int ANGEL_PID_FILE_SUFFIX_LEN= (uint) strlen(ANGEL_PID_FILE_SUFFIX); - -/* - List of options, accepted by the instance manager. - List must be closed with empty option. -*/ - -enum options { - OPT_USERNAME= 'u', - OPT_PASSWORD= 'p', - OPT_LOG= 256, - OPT_PID_FILE, - OPT_SOCKET, - OPT_PASSWORD_FILE, - OPT_MYSQLD_PATH, -#ifdef __WIN__ - OPT_INSTALL_SERVICE, - OPT_REMOVE_SERVICE, - OPT_STAND_ALONE, -#else - OPT_RUN_AS_SERVICE, - OPT_USER, - OPT_ANGEL_PID_FILE, -#endif - OPT_MONITORING_INTERVAL, - OPT_PORT, - OPT_WAIT_TIMEOUT, - OPT_BIND_ADDRESS, - OPT_PRINT_PASSWORD_LINE, - OPT_ADD_USER, - OPT_DROP_USER, - OPT_EDIT_USER, - OPT_CLEAN_PASSWORD_FILE, - OPT_CHECK_PASSWORD_FILE, - OPT_LIST_USERS, - OPT_MYSQLD_SAFE_COMPATIBLE -}; - -static struct my_option my_long_options[] = -{ - { "help", '?', "Display this help and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "add-user", OPT_ADD_USER, - "Add a user to the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.", - (uchar* *) &Options::Daemon::angel_pid_file_name, - (uchar* *) &Options::Daemon::angel_pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.", - (uchar* *) &Options::Main::bind_address, - (uchar* *) &Options::Main::bind_address, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "check-password-file", OPT_CHECK_PASSWORD_FILE, - "Check the password file for consistency", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "clean-password-file", OPT_CLEAN_PASSWORD_FILE, - "Clean the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef DBUG_OFF - {"debug", '#', "Debug log.", - (uchar* *) &Options::Debug::config_str, - (uchar* *) &Options::Debug::config_str, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, -#endif - - { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL" - " Server binary.", - (uchar* *) &Options::Main::default_mysqld_path, - (uchar* *) &Options::Main::default_mysqld_path, - 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 }, - - { "drop-user", OPT_DROP_USER, - "Drop existing user from the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "edit-user", OPT_EDIT_USER, - "Edit existing user in the password file", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "install", OPT_INSTALL_SERVICE, "Install as system service.", - (uchar* *) &Options::Service::install_as_service, - (uchar* *) &Options::Service::install_as_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - - { "list-users", OPT_LIST_USERS, - "Print out a list of registered users", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - -#ifndef __WIN__ - { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.", - (uchar* *) &Options::Daemon::log_file_name, - (uchar* *) &Options::Daemon::log_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor" - " instances in seconds.", - (uchar* *) &Options::Main::monitoring_interval, - (uchar* *) &Options::Main::monitoring_interval, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL, - 0, 0, 0, 0, 0 }, - - { "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE, - "Start Instance Manager in mysqld_safe compatible manner", - (uchar* *) &Options::Main::mysqld_safe_compatible, - (uchar* *) &Options::Main::mysqld_safe_compatible, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, - - { "print-password-line", OPT_PRINT_PASSWORD_LINE, - "Print out a user entry as a line for the password file and exit.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password", OPT_PASSWORD, "Password to update the password file", - (uchar* *) &Options::User_management::password, - (uchar* *) &Options::User_management::password, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "password-file", OPT_PASSWORD_FILE, - "Look for Instance Manager users and passwords here.", - (uchar* *) &Options::Main::password_file_name, - (uchar* *) &Options::Main::password_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "pid-file", OPT_PID_FILE, "Pid file to use.", - (uchar* *) &Options::Main::pid_file_name, - (uchar* *) &Options::Main::pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "port", OPT_PORT, "Port number to use for connections", - (uchar* *) &Options::Main::port_number, - (uchar* *) &Options::Main::port_number, - 0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 }, - -#ifdef __WIN__ - { "remove", OPT_REMOVE_SERVICE, "Remove system service.", - (uchar* *) &Options::Service::remove_service, - (uchar* *) &Options::Service::remove_service, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "run-as-service", OPT_RUN_AS_SERVICE, - "Daemonize and start angel process.", - (uchar* *) &Options::Daemon::run_as_service, - 0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 }, -#endif - -#ifndef __WIN__ - { "socket", OPT_SOCKET, "Socket file to use for connection.", - (uchar* *) &Options::Main::socket_file_name, - (uchar* *) &Options::Main::socket_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - -#ifdef __WIN__ - { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.", - (uchar* *) &Options::Service::stand_alone, - (uchar* *) &Options::Service::stand_alone, - 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0}, -#else - { "user", OPT_USER, "Username to start mysqlmanager", - (uchar* *) &Options::Daemon::user, - (uchar* *) &Options::Daemon::user, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, -#endif - - { "username", OPT_USERNAME, - "Username to update the password file", - (uchar* *) &Options::User_management::user_name, - (uchar* *) &Options::User_management::user_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "version", 'V', "Output version information and exit.", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - - { "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits " - "for activity on a connection before closing it.", - (uchar* *) &net_read_timeout, - (uchar* *) &net_read_timeout, - 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 }, - - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 } -}; - -static void version() -{ - printf("%s Ver %s for %s on %s\n", my_progname, - (const char *) mysqlmanager_version.str, - SYSTEM_TYPE, MACHINE_TYPE); -} - - -static const char *default_groups[]= { "manager", 0 }; - - -static void usage() -{ - version(); - - printf("Copyright (C) 2003, 2004 MySQL AB\n" - "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to modify and redistribute it under the GPL license\n"); - printf("Usage: %s [OPTIONS] \n", my_progname); - - my_print_help(my_long_options); - printf("\nThe following options may be given as the first argument:\n" - "--print-defaults Print the program argument list and exit\n" - "--defaults-file=# Only read manager configuration and instance\n" - " setings from the given file #. The same file\n" - " will be used to modify configuration of instances\n" - " with SET commands.\n"); - my_print_variables(my_long_options); -} - - -C_MODE_START - -static my_bool -get_one_option(int optid, - const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch(optid) { - case 'V': - version(); - exit(0); - case OPT_PRINT_PASSWORD_LINE: - case OPT_ADD_USER: - case OPT_DROP_USER: - case OPT_EDIT_USER: - case OPT_CLEAN_PASSWORD_FILE: - case OPT_CHECK_PASSWORD_FILE: - case OPT_LIST_USERS: - if (Options::User_management::cmd) - { - fprintf(stderr, "Error: only one password-management command " - "can be specified at a time.\n"); - exit(ERR_INVALID_USAGE); - } - - switch (optid) { - case OPT_PRINT_PASSWORD_LINE: - Options::User_management::cmd= new Print_password_line_cmd(); - break; - case OPT_ADD_USER: - Options::User_management::cmd= new Add_user_cmd(); - break; - case OPT_DROP_USER: - Options::User_management::cmd= new Drop_user_cmd(); - break; - case OPT_EDIT_USER: - Options::User_management::cmd= new Edit_user_cmd(); - break; - case OPT_CLEAN_PASSWORD_FILE: - Options::User_management::cmd= new Clean_db_cmd(); - break; - case OPT_CHECK_PASSWORD_FILE: - Options::User_management::cmd= new Check_db_cmd(); - break; - case OPT_LIST_USERS: - Options::User_management::cmd= new List_users_cmd(); - break; - } - - break; - case '?': - usage(); - exit(0); - case '#': -#ifndef DBUG_OFF - DBUG_SET(argument ? argument : Options::Debug::config_str); - DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str); -#endif - break; - } - return 0; -} - -C_MODE_END - - -/* - - Process argv of original program: get tid of --defaults-extra-file - and print a message if met there. - - call load_defaults to load configuration file section and save the pointer - for free_defaults. - - call handle_options to assign defaults and command-line arguments - to the class members. - if either of these function fail, return the error code. -*/ - -int Options::load(int argc, char **argv) -{ - if (argc >= 2) - { - if (is_prefix(argv[1], "--defaults-file=")) - { - Main::config_file= strchr(argv[1], '=') + 1; - Main::is_forced_default_file= TRUE; - } - if (is_prefix(argv[1], "--defaults-extra-file=") || - is_prefix(argv[1], "--no-defaults")) - { - /* the log is not enabled yet */ - fprintf(stderr, "The --defaults-extra-file and --no-defaults options" - " are not supported by\n" - "Instance Manager. Program aborted.\n"); - return ERR_INVALID_USAGE; - } - } - -#ifdef __WIN__ - if (setup_windows_defaults()) - { - fprintf(stderr, "Internal error: could not setup default values.\n"); - return ERR_OUT_OF_MEMORY; - } -#endif - - /* load_defaults will reset saved_argv with a new allocated list */ - saved_argv= argv; - - /* config-file options are prepended to command-line ones */ - - log_info("Loading config file '%s'...", - (const char *) Main::config_file); - - my_load_defaults(Main::config_file, default_groups, &argc, - &saved_argv, &default_directories); - - if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option))) - return ERR_INVALID_USAGE; - - if (!User_management::cmd && - (User_management::user_name || User_management::password)) - { - fprintf(stderr, - "--username and/or --password options have been specified, " - "but no password-management command has been given.\n"); - return ERR_INVALID_USAGE; - } - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - { - if (Options::Daemon::angel_pid_file_name == NULL) - { - /* - Calculate angel pid file on the IM pid file basis: replace the - extension (everything after the last dot) of the pid file basename to - '.angel.pid'. - */ - - char *local_angel_pid_file_name; - char *base_name_ptr; - char *ext_ptr; - - local_angel_pid_file_name= - (char *) malloc(strlen(Options::Main::pid_file_name) + - ANGEL_PID_FILE_SUFFIX_LEN); - - strcpy(local_angel_pid_file_name, Options::Main::pid_file_name); - - base_name_ptr= strrchr(local_angel_pid_file_name, '/'); - - if (!base_name_ptr) - base_name_ptr= local_angel_pid_file_name + 1; - - ext_ptr= strrchr(base_name_ptr, '.'); - if (ext_ptr) - *ext_ptr= 0; - - strcat(local_angel_pid_file_name, ANGEL_PID_FILE_SUFFIX); - - Options::Daemon::angel_pid_file_name= local_angel_pid_file_name; - } - else - { - Options::Daemon::angel_pid_file_name= - strdup(Options::Daemon::angel_pid_file_name); - } - } -#endif - - return 0; -} - -void Options::cleanup() -{ - if (saved_argv) - free_defaults(saved_argv); - - delete User_management::cmd; - -#ifndef __WIN__ - if (Options::Daemon::run_as_service) - free((void *) Options::Daemon::angel_pid_file_name); -#endif -} - -#ifdef __WIN__ - -static int setup_windows_defaults() -{ - char module_full_name[FN_REFLEN]; - char dir_name[FN_REFLEN]; - char base_name[FN_REFLEN]; - char im_name[FN_REFLEN]; - char *base_name_ptr; - char *ptr; - - /* Determine dirname and basename. */ - - if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) || - !GetFullPathName(module_full_name, sizeof (dir_name), dir_name, - &base_name_ptr)) - { - return 1; - } - - strmake(base_name, base_name_ptr, FN_REFLEN); - *base_name_ptr= 0; - - strmake(im_name, base_name, FN_REFLEN); - ptr= strrchr(im_name, '.'); - - if (!ptr) - return 1; - - *ptr= 0; - - /* Initialize the defaults. */ - - strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS); - strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS); - strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT, - NullS); - strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS); - - return 0; -} - -#endif diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h deleted file mode 100644 index 5d4df51faae..00000000000 --- a/server-tools/instance-manager/options.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2003-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H - -/* - Options - all possible command-line options for the Instance Manager grouped - in one struct. -*/ - -#include <my_global.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -class User_management_cmd; - -struct Options -{ - /* - NOTE: handle_options() expects value of my_bool type for GET_BOOL - accessor (i.e. bool must not be used). - */ - - struct User_management - { - static User_management_cmd *cmd; - - static char *user_name; - static char *password; - }; - - struct Main - { - /* this is not an option parsed by handle_options(). */ - static bool is_forced_default_file; - - static const char *pid_file_name; -#ifndef __WIN__ - static const char *socket_file_name; -#endif - static const char *password_file_name; - static const char *default_mysqld_path; - static uint monitoring_interval; - static uint port_number; - static const char *bind_address; - static const char *config_file; - static my_bool mysqld_safe_compatible; - }; - -#ifndef DBUG_OFF - struct Debug - { - static const char *config_str; - }; -#endif - -#ifndef __WIN__ - - struct Daemon - { - static my_bool run_as_service; - static const char *log_file_name; - static const char *user; - static const char *angel_pid_file_name; - }; - -#else - - struct Service - { - static my_bool install_as_service; - static my_bool remove_service; - static my_bool stand_alone; - }; - -#endif - -public: - /* Array of paths to be passed to my_search_option_files() later */ - static const char **default_directories; - - static int load(int argc, char **argv); - static void cleanup(); - -private: - Options(); /* Deny instantiation of this class. */ - -private: - /* argv pointer returned by load_defaults() to be used by free_defaults() */ - static char **saved_argv; -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc deleted file mode 100644 index cd20e3bc7ab..00000000000 --- a/server-tools/instance-manager/parse.cc +++ /dev/null @@ -1,509 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "parse.h" -#include "commands.h" - - -enum Token -{ - TOK_CREATE= 0, - TOK_DROP, - TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */ - TOK_FILES, - TOK_FLUSH, - TOK_GENERAL, - TOK_INSTANCE, - TOK_INSTANCES, - TOK_LOG, - TOK_OPTIONS, - TOK_SET, - TOK_SLOW, - TOK_START, - TOK_STATUS, - TOK_STOP, - TOK_SHOW, - TOK_UNSET, - TOK_NOT_FOUND, // must be after all tokens - TOK_END -}; - - -struct tokens_st -{ - uint length; - const char *tok_name; -}; - - -static struct tokens_st tokens[]= { - {6, "CREATE"}, - {4, "DROP"}, - {5, "ERROR"}, - {5, "FILES"}, - {5, "FLUSH"}, - {7, "GENERAL"}, - {8, "INSTANCE"}, - {9, "INSTANCES"}, - {3, "LOG"}, - {7, "OPTIONS"}, - {3, "SET"}, - {4, "SLOW"}, - {5, "START"}, - {6, "STATUS"}, - {4, "STOP"}, - {4, "SHOW"}, - {5, "UNSET"} -}; - -/************************************************************************/ - -Named_value_arr::Named_value_arr() : - initialized(FALSE) -{ -} - - -bool Named_value_arr::init() -{ - if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32)) - return TRUE; - - initialized= TRUE; - - return FALSE; -} - - -Named_value_arr::~Named_value_arr() -{ - if (!initialized) - return; - - for (int i= 0; i < get_size(); ++i) - get_element(i).free(); - - delete_dynamic(&arr); -} - -/************************************************************************/ - -/* - Returns token no if word corresponds to some token, otherwise returns - TOK_NOT_FOUND -*/ - -inline Token find_token(const char *word, size_t word_len) -{ - int i= 0; - do - { - if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name, - tokens[i].length, (const uchar *) word, word_len) == 0) - break; - } - while (++i < TOK_NOT_FOUND); - return (Token) i; -} - - -Token get_token(const char **text, size_t *word_len) -{ - get_word(text, word_len); - if (*word_len) - return find_token(*text, *word_len); - return TOK_END; -} - - -Token shift_token(const char **text, size_t *word_len) -{ - Token save= get_token(text, word_len); - (*text)+= *word_len; - return save; -} - - -int get_text_id(const char **text, LEX_STRING *token) -{ - get_word(text, &token->length); - if (token->length == 0) - return 1; - token->str= (char *) *text; - return 0; -} - - -static bool parse_long(const LEX_STRING *token, long *value) -{ - int err_code; - char *end_ptr= token->str + token->length; - - *value= (long)my_strtoll10(token->str, &end_ptr, &err_code); - - return err_code != 0; -} - - -bool parse_option_value(const char *text, size_t *text_len, char **value) -{ - char beginning_quote; - const char *text_start_ptr; - char *v; - bool escape_mode= FALSE; - - if (!*text || (*text != '\'' && *text != '"')) - return TRUE; /* syntax error: string expected. */ - - beginning_quote= *text; - - ++text; /* skip the beginning quote. */ - - text_start_ptr= text; - - if (!(v= Named_value::alloc_str(text))) - return TRUE; - - *value= v; - - while (TRUE) - { - if (!*text) - { - Named_value::free_str(value); - return TRUE; /* syntax error: missing terminating ' character. */ - } - - if (*text == '\n' || *text == '\r') - { - Named_value::free_str(value); - return TRUE; /* syntax error: option value should be a single line. */ - } - - if (!escape_mode && *text == beginning_quote) - break; - - if (escape_mode) - { - switch (*text) - { - case 'b': /* \b -- backspace */ - if (v > *value) - --v; - break; - - case 't': /* \t -- tab */ - *v= '\t'; - ++v; - break; - - case 'n': /* \n -- newline */ - *v= '\n'; - ++v; - break; - - case 'r': /* \r -- carriage return */ - *v= '\r'; - ++v; - break; - - case '\\': /* \\ -- back slash */ - *v= '\\'; - ++v; - break; - - case 's': /* \s -- space */ - *v= ' '; - ++v; - break; - - default: /* Unknown escape sequence. Treat as error. */ - Named_value::free_str(value); - return TRUE; - } - - escape_mode= FALSE; - } - else - { - if (*text == '\\') - { - escape_mode= TRUE; - } - else - { - *v= *text; - ++v; - } - } - - ++text; - } - - *v= 0; - - /* "2" below stands for beginning and ending quotes. */ - *text_len= text - text_start_ptr + 2; - - return FALSE; -} - - -void skip_spaces(const char **text) -{ - while (**text && my_isspace(default_charset_info, **text)) - ++(*text); -} - - -Command *parse_command(const char *text) -{ - size_t word_len; - LEX_STRING instance_name; - Command *command= 0; - - Token tok1= shift_token(&text, &word_len); - - switch (tok1) { - case TOK_START: // fallthrough - case TOK_STOP: - case TOK_CREATE: - case TOK_DROP: - if (shift_token(&text, &word_len) != TOK_INSTANCE) - goto syntax_error; - get_word(&text, &word_len); - if (word_len == 0) - goto syntax_error; - instance_name.str= (char *) text; - instance_name.length= word_len; - text+= word_len; - - if (tok1 == TOK_CREATE) - { - Create_instance *cmd= new Create_instance(&instance_name); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - } - else - { - /* it should be the end of command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - } - - switch (tok1) { - case TOK_START: - command= new Start_instance(&instance_name); - break; - case TOK_STOP: - command= new Stop_instance(&instance_name); - break; - case TOK_CREATE: - ; /* command already initialized. */ - break; - case TOK_DROP: - command= new Drop_instance(&instance_name); - break; - default: /* this is impossible, but nevertheless... */ - DBUG_ASSERT(0); - } - break; - case TOK_FLUSH: - if (shift_token(&text, &word_len) != TOK_INSTANCES) - goto syntax_error; - - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - - command= new Flush_instances(); - break; - case TOK_UNSET: - case TOK_SET: - { - Abstract_option_cmd *cmd; - - if (tok1 == TOK_SET) - cmd= new Set_option(); - else - cmd= new Unset_option(); - - if (!cmd) - return NULL; /* Report ER_OUT_OF_RESOURCES. */ - - if (cmd->init(&text)) - { - delete cmd; - goto syntax_error; - } - - command= cmd; - - break; - } - case TOK_SHOW: - switch (shift_token(&text, &word_len)) { - case TOK_INSTANCES: - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - command= new Show_instances(); - break; - case TOK_INSTANCE: - switch (Token tok2= shift_token(&text, &word_len)) { - case TOK_OPTIONS: - case TOK_STATUS: - if (get_text_id(&text, &instance_name)) - goto syntax_error; - text+= instance_name.length; - /* check that this is the end of the command */ - get_word(&text, &word_len, NONSPACE); - if (word_len) - goto syntax_error; - if (tok2 == TOK_STATUS) - command= new Show_instance_status(&instance_name); - else - command= new Show_instance_options(&instance_name); - break; - default: - goto syntax_error; - } - break; - default: - instance_name.str= (char *) text - word_len; - instance_name.length= word_len; - if (instance_name.length) - { - Log_type log_type; - - long log_size; - LEX_STRING log_size_str; - - long log_offset= 0; - LEX_STRING log_offset_str= { NULL, 0 }; - - switch (shift_token(&text, &word_len)) { - case TOK_LOG: - switch (Token tok3= shift_token(&text, &word_len)) { - case TOK_FILES: - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - command= new Show_instance_log_files(&instance_name); - break; - case TOK_ERROR: - case TOK_GENERAL: - case TOK_SLOW: - /* define a log type */ - switch (tok3) { - case TOK_ERROR: - log_type= IM_LOG_ERROR; - break; - case TOK_GENERAL: - log_type= IM_LOG_GENERAL; - break; - case TOK_SLOW: - log_type= IM_LOG_SLOW; - break; - default: - goto syntax_error; - } - /* get the size of the log we want to retrieve */ - if (get_text_id(&text, &log_size_str)) - goto syntax_error; - text+= log_size_str.length; - - /* this parameter is required */ - if (!log_size_str.length) - goto syntax_error; - - /* the next token should be comma, or nothing */ - get_word(&text, &word_len); - switch (*text) { - case ',': - text++; /* swallow the comma */ - /* read the next word */ - get_word(&text, &word_len); - if (!word_len) - goto syntax_error; - log_offset_str.str= (char *) text; - log_offset_str.length= word_len; - text+= word_len; - get_word(&text, &word_len, NONSPACE); - /* check that this is the end of the command */ - if (word_len) - goto syntax_error; - break; - case '\0': - break; /* this is ok */ - default: - goto syntax_error; - } - - /* Parse size parameter. */ - - if (parse_long(&log_size_str, &log_size)) - goto syntax_error; - - if (log_size <= 0) - goto syntax_error; - - /* Parse offset parameter (if specified). */ - - if (log_offset_str.length) - { - if (parse_long(&log_offset_str, &log_offset)) - goto syntax_error; - - if (log_offset <= 0) - goto syntax_error; - } - - command= new Show_instance_log(&instance_name, - log_type, log_size, log_offset); - break; - default: - goto syntax_error; - } - break; - default: - goto syntax_error; - } - } - else - goto syntax_error; - break; - } - break; - default: -syntax_error: - command= new Syntax_error(); - } - - DBUG_ASSERT(command); - - return command; -} diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h deleted file mode 100644 index 9c50ace5948..00000000000 --- a/server-tools/instance-manager/parse.h +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> - -class Command; - -enum Log_type -{ - IM_LOG_ERROR= 0, - IM_LOG_GENERAL, - IM_LOG_SLOW -}; - -Command *parse_command(const char *text); - -bool parse_option_value(const char *text, size_t *text_len, char **value); - -void skip_spaces(const char **text); - -/* define kinds of the word seek method */ -enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME }; - -/************************************************************************/ - -class Named_value -{ -public: - /* - The purpose of these methods is just to have one method for - allocating/deallocating memory for strings for Named_value. - */ - - static inline char *alloc_str(const LEX_STRING *str); - static inline char *alloc_str(const char *str); - static inline void free_str(char **str); - -public: - inline Named_value(); - inline Named_value(char *name_arg, char *value_arg); - - inline char *get_name(); - inline char *get_value(); - - inline void free(); - -private: - char *name; - char *value; -}; - -inline char *Named_value::alloc_str(const LEX_STRING *str) -{ - return my_strndup(str->str, str->length, MYF(0)); -} - -inline char *Named_value::alloc_str(const char *str) -{ - return my_strdup(str, MYF(0)); -} - -inline void Named_value::free_str(char **str) -{ - my_free(*str, MYF(MY_ALLOW_ZERO_PTR)); - *str= NULL; -} - -inline Named_value::Named_value() - :name(NULL), value(NULL) -{ } - -inline Named_value::Named_value(char *name_arg, char *value_arg) - :name(name_arg), value(value_arg) -{ } - -inline char *Named_value::get_name() -{ - return name; -} - -inline char *Named_value::get_value() -{ - return value; -} - -void Named_value::free() -{ - free_str(&name); - free_str(&value); -} - -/************************************************************************/ - -class Named_value_arr -{ -public: - Named_value_arr(); - ~Named_value_arr(); - - bool init(); - - inline int get_size() const; - inline Named_value get_element(int idx) const; - inline void remove_element(int idx); - inline bool add_element(Named_value *option); - inline bool replace_element(int idx, Named_value *option); - -private: - bool initialized; - DYNAMIC_ARRAY arr; -}; - - -inline int Named_value_arr::get_size() const -{ - return arr.elements; -} - - -inline Named_value Named_value_arr::get_element(int idx) const -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - Named_value option; - get_dynamic((DYNAMIC_ARRAY *) &arr, (uchar*) &option, idx); - - return option; -} - - -inline void Named_value_arr::remove_element(int idx) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - delete_dynamic_element(&arr, idx); -} - - -inline bool Named_value_arr::add_element(Named_value *option) -{ - return insert_dynamic(&arr, (uchar*) option); -} - - -inline bool Named_value_arr::replace_element(int idx, Named_value *option) -{ - DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements); - - get_element(idx).free(); - - return set_dynamic(&arr, (uchar*) option, idx); -} - -/************************************************************************/ - -/* - tries to find next word in the text - if found, returns the beginning and puts word length to word_len argument. - if not found returns pointer to first non-space or to '\0', word_len == 0 -*/ - -inline void get_word(const char **text, size_t *word_len, - enum_seek_method seek_method= ALPHANUM) -{ - const char *word_end; - - /* skip space */ - while (my_isspace(default_charset_info, **text)) - ++(*text); - - word_end= *text; - - switch (seek_method) { - case ALPHANUM: - while (my_isalnum(default_charset_info, *word_end)) - ++word_end; - break; - case NONSPACE: - while (!my_isspace(default_charset_info, *word_end) && - (*word_end != '\0')) - ++word_end; - break; - case OPTION_NAME: - while (my_isalnum(default_charset_info, *word_end) || - *word_end == '-' || - *word_end == '_') - ++word_end; - break; - } - - *word_len= (uint) (word_end - *text); -} - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */ diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc deleted file mode 100644 index 3511589acd6..00000000000 --- a/server-tools/instance-manager/parse_output.cc +++ /dev/null @@ -1,407 +0,0 @@ -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "parse_output.h" - -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> - -#include <stdio.h> - -#include "parse.h" -#include "portability.h" - -/************************************************************************** - Private module implementation. -**************************************************************************/ - -namespace { /* no-indent */ - -/*************************************************************************/ - -void trim_space(const char **text, uint *word_len) -{ - const char *start= *text; - while (*start != 0 && *start == ' ') - start++; - *text= start; - - int len= strlen(start); - const char *end= start + len - 1; - while (end > start && my_isspace(&my_charset_latin1, *end)) - end--; - *word_len= (end - start)+1; -} - -/*************************************************************************/ - -/** - @brief A facade to the internal workings of optaining the output from an - executed system process. -*/ - -class Mysqld_output_parser -{ -public: - Mysqld_output_parser() - { } - - virtual ~Mysqld_output_parser() - { } - -public: - bool parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -protected: - /** - @brief Run a process and attach stdout- and stdin-pipes to it. - - @param command The path to the process to be executed - - @return Error status. - @retval TRUE An error occurred - @retval FALSE Operation was a success - */ - - virtual bool run_command(const char *command)= 0; - - - /** - @brief Read a sequence of bytes from the executed process' stdout pipe. - - The sequence is terminated by either '\0', LF or CRLF tokens. The - terminating token is excluded from the result. - - @param line_buffer A pointer to a character buffer - @param line_buffer_size The size of the buffer in bytes - - @return Error status. - @retval TRUE An error occured - @retval FALSE Operation was a success - */ - - virtual bool read_line(char *line_buffer, - uint line_buffer_size)= 0; - - - /** - @brief Release any resources needed after a execution and parsing. - */ - - virtual bool cleanup()= 0; -}; - -/*************************************************************************/ - -bool Mysqld_output_parser::parse(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ - /* should be enough to store the string from the output */ - const int LINE_BUFFER_SIZE= 512; - char line_buffer[LINE_BUFFER_SIZE]; - - if (run_command(command)) - return TRUE; - - while (true) - { - if (read_line(line_buffer, LINE_BUFFER_SIZE)) - { - cleanup(); - return TRUE; - } - - uint found_word_len= 0; - char *linep= line_buffer; - - line_buffer[sizeof(line_buffer) - 1]= '\0'; /* safety */ - - /* Find the word(s) we are looking for in the line. */ - - linep= strstr(linep, option_name_str); - - if (!linep) - continue; - - linep+= option_name_length; - - switch (option_type) - { - case GET_VALUE: - trim_space((const char**) &linep, &found_word_len); - - if (option_value_buf_size <= found_word_len) - { - cleanup(); - return TRUE; - } - - strmake(option_value_buf, linep, found_word_len); - - break; - - case GET_LINE: - strmake(option_value_buf, linep, option_value_buf_size - 1); - - break; - } - - cleanup(); - - return FALSE; - } -} - -/************************************************************************** - Platform-specific implementation: UNIX. -**************************************************************************/ - -#ifndef __WIN__ - -class Mysqld_output_parser_unix : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_unix() : - m_stdout(NULL) - { } - -protected: - virtual bool run_command(const char *command); - - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - - virtual bool cleanup(); - -private: - FILE *m_stdout; -}; - -bool Mysqld_output_parser_unix::run_command(const char *command) -{ - if (!(m_stdout= popen(command, "r"))) - return TRUE; - - /* - We want fully buffered stream. We also want system to allocate - appropriate buffer. - */ - - setvbuf(m_stdout, NULL, _IOFBF, 0); - - return FALSE; -} - -bool Mysqld_output_parser_unix::read_line(char *line_buffer, - uint line_buffer_size) -{ - char *retbuff = fgets(line_buffer, line_buffer_size, m_stdout); - /* Remove any tailing new line charaters */ - if (line_buffer[line_buffer_size-1] == LF) - line_buffer[line_buffer_size-1]= '\0'; - return (retbuff == NULL); -} - -bool Mysqld_output_parser_unix::cleanup() -{ - if (m_stdout) - pclose(m_stdout); - - return FALSE; -} - -#else /* Windows */ - -/************************************************************************** - Platform-specific implementation: Windows. -**************************************************************************/ - -class Mysqld_output_parser_win : public Mysqld_output_parser -{ -public: - Mysqld_output_parser_win() : - m_internal_buffer(NULL), - m_internal_buffer_offset(0), - m_internal_buffer_size(0) - { } - -protected: - virtual bool run_command(const char *command); - virtual bool read_line(char *line_buffer, - uint line_buffer_size); - virtual bool cleanup(); - -private: - HANDLE m_h_child_stdout_wr; - HANDLE m_h_child_stdout_rd; - uint m_internal_buffer_offset; - uint m_internal_buffer_size; - char *m_internal_buffer; -}; - -bool Mysqld_output_parser_win::run_command(const char *command) -{ - BOOL op_status; - - SECURITY_ATTRIBUTES sa_attr; - sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle= TRUE; - sa_attr.lpSecurityDescriptor= NULL; - - op_status= CreatePipe(&m_h_child_stdout_rd, - &m_h_child_stdout_wr, - &sa_attr, - 0 /* Use system-default buffer size. */); - - if (!op_status) - return TRUE; - - SetHandleInformation(m_h_child_stdout_rd, HANDLE_FLAG_INHERIT, 0); - - STARTUPINFO si_start_info; - ZeroMemory(&si_start_info, sizeof(STARTUPINFO)); - si_start_info.cb= sizeof(STARTUPINFO); - si_start_info.hStdError= m_h_child_stdout_wr; - si_start_info.hStdOutput= m_h_child_stdout_wr; - si_start_info.dwFlags|= STARTF_USESTDHANDLES; - - PROCESS_INFORMATION pi_proc_info; - - op_status= CreateProcess(NULL, /* Application name. */ - (char*)command, /* Command line. */ - NULL, /* Process security attributes. */ - NULL, /* Primary thread security attr.*/ - TRUE, /* Handles are inherited. */ - 0, /* Creation flags. */ - NULL, /* Use parent's environment. */ - NULL, /* Use parent's curr. directory. */ - &si_start_info, /* STARTUPINFO pointer. */ - &pi_proc_info); /* Rec. PROCESS_INFORMATION. */ - - if (!op_status) - { - CloseHandle(m_h_child_stdout_rd); - CloseHandle(m_h_child_stdout_wr); - - return TRUE; - } - - /* Close unnessary handles. */ - - CloseHandle(pi_proc_info.hProcess); - CloseHandle(pi_proc_info.hThread); - - return FALSE; -} - -bool Mysqld_output_parser_win::read_line(char *line_buffer, - uint line_buffer_size) -{ - DWORD dw_read_count= m_internal_buffer_size; - bzero(line_buffer,line_buffer_size); - char *buff_ptr= line_buffer; - char ch; - - while ((unsigned)(buff_ptr - line_buffer) < line_buffer_size) - { - do - { - ReadFile(m_h_child_stdout_rd, &ch, - 1, &dw_read_count, NULL); - } while ((ch == CR || ch == LF) && buff_ptr == line_buffer); - - if (dw_read_count == 0) - return TRUE; - - if (ch == CR || ch == LF) - break; - - *buff_ptr++ = ch; - } - - return FALSE; -} - -bool Mysqld_output_parser_win::cleanup() -{ - /* Close all handles. */ - - CloseHandle(m_h_child_stdout_wr); - CloseHandle(m_h_child_stdout_rd); - - return FALSE; -} -#endif - -/*************************************************************************/ - -} /* End of private module implementation. */ - -/*************************************************************************/ - -/** - @brief Parse output of the given command - - @param command The command to execute. - @param option_name_str Option name. - @param option_name_length Length of the option name. - @param[out] option_value_buf The buffer to store option value. - @param option_value_buf_size Size of the option value buffer. - @param option_type Type of the option: - - GET_LINE if we want to get all the - line after the option name; - - GET_VALUE otherwise. - - Execute the process by running "command". Find the "option name" and - return the next word if "option_type" is GET_VALUE. Return the rest of - the parsed string otherwise. - - @note This function has a separate windows implementation. - - @return The error status. - @retval FALSE Ok, the option name has been found. - @retval TRUE Error occured or the option name is not found. -*/ - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type) -{ -#ifndef __WIN__ - Mysqld_output_parser_unix parser; -#else /* __WIN__ */ - Mysqld_output_parser_win parser; -#endif - - return parser.parse(command, - option_name_str, - option_name_length, - option_value_buf, - option_value_buf_size, - option_type); -} diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h deleted file mode 100644 index 41618f643a3..00000000000 --- a/server-tools/instance-manager/parse_output.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H -/* Copyright (C) 2004 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include <my_global.h> - -enum enum_option_type -{ - GET_VALUE = 1, - GET_LINE -}; - -bool parse_output_and_get_value(const char *command, - const char *option_name_str, - uint option_name_length, - char *option_value_buf, - size_t option_value_buf_size, - enum_option_type option_type); - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */ diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h deleted file mode 100644 index 990e6140a9e..00000000000 --- a/server-tools/instance-manager/portability.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2005-2006 MySQL AB - - 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 */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H - -#if (defined(_SCO_DS) || defined(UNIXWARE_7)) && !defined(SHUT_RDWR) -/* - SHUT_* functions are defined only if - "(defined(_XOPEN_SOURCE) && _XOPEN_SOURCE_EXTENDED - 0 >= 1)" -*/ -#define SHUT_RDWR 2 -#endif - -#ifdef __WIN__ - -#define vsnprintf _vsnprintf -#define snprintf _snprintf - -#define SIGKILL 9 - -/*TODO: fix this */ -#define PROTOCOL_VERSION 10 - -#define DFLT_CONFIG_FILE_NAME "my.ini" -#define DFLT_MYSQLD_PATH "mysqld" -#define DFLT_PASSWD_FILE_EXT ".passwd" -#define DFLT_PID_FILE_EXT ".pid" -#define DFLT_SOCKET_FILE_EXT ".sock" - -typedef int pid_t; - -#undef popen -#define popen(A,B) _popen(A,B) - -#define NEWLINE "\r\n" -#define NEWLINE_LEN 2 - -const char CR = '\r'; -const char LF = '\n'; - -#else /* ! __WIN__ */ - -#define NEWLINE "\n" -#define NEWLINE_LEN 1 - -const char LF = '\n'; - -#endif /* __WIN__ */ - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */ - - diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc deleted file mode 100644 index 74263934924..00000000000 --- a/server-tools/instance-manager/priv.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "priv.h" - -#include <my_global.h> -#include <mysql_com.h> -#include <my_sys.h> - -#include "log.h" - -/* - The following string must be less then 80 characters, as - mysql_connection.cc relies on it -*/ -const LEX_STRING mysqlmanager_version= { C_STRING_WITH_LEN("1.0-beta") }; - -const unsigned char protocol_version= PROTOCOL_VERSION; - -unsigned long net_buffer_length= 16384; - -unsigned long max_allowed_packet= 16384; - -unsigned long net_read_timeout= NET_WAIT_TIMEOUT; // same as in mysqld - -unsigned long net_write_timeout= 60; // same as in mysqld - -unsigned long net_retry_count= 10; // same as in mysqld - -/* needed by net_serv.cc */ -unsigned int test_flags= 0; -unsigned long bytes_sent = 0L, bytes_received = 0L; -unsigned long mysqld_net_retry_count = 10L; -unsigned long open_files_limit; - - - -bool create_pid_file(const char *pid_file_name, int pid) -{ - FILE *pid_file; - - if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY, - MYF(0)))) - { - log_error("Can not create pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - if (fprintf(pid_file, "%d\n", (int) pid) <= 0) - { - log_error("Can not write to pid file '%s': %s (errno: %d)", - (const char *) pid_file_name, - (const char *) strerror(errno), - (int) errno); - return TRUE; - } - - my_fclose(pid_file, MYF(0)); - - return FALSE; -} diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h deleted file mode 100644 index 1c2124c0e77..00000000000 --- a/server-tools/instance-manager/priv.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H - -#include <my_global.h> -#include <m_string.h> -#include <my_pthread.h> - -#include <sys/types.h> - -#ifndef __WIN__ -#include <unistd.h> -#endif - -#include "portability.h" - -/* IM-wide platform-independent defines */ -#define SERVER_DEFAULT_PORT MYSQL_PORT -#define DEFAULT_MONITORING_INTERVAL 20 -#define DEFAULT_PORT 2273 -/* three-week timeout should be enough */ -#define LONG_TIMEOUT ((ulong) 3600L*24L*21L) - -const int MEM_ROOT_BLOCK_SIZE= 512; - -/* The maximal length of option name and option value. */ -const int MAX_OPTION_LEN= 1024; - -/* - The maximal length of whole option string: - --<option name>=<option value> -*/ -const int MAX_OPTION_STR_LEN= 2 + MAX_OPTION_LEN + 1 + MAX_OPTION_LEN + 1; - -const int MAX_VERSION_LENGTH= 160; - -const int MAX_INSTANCE_NAME_SIZE= FN_REFLEN; - -extern const LEX_STRING mysqlmanager_version; - -/* MySQL client-server protocol version: substituted from configure */ -extern const unsigned char protocol_version; - -/* - These variables are used in MySQL subsystem to work with mysql clients - To be moved to a config file/options one day. -*/ - - -/* Buffer length for TCP/IP and socket communication */ -extern unsigned long net_buffer_length; - - -/* Maximum allowed incoming/ougoung packet length */ -extern unsigned long max_allowed_packet; - - -/* - Number of seconds to wait for more data from a connection before aborting - the read -*/ -extern unsigned long net_read_timeout; - - -/* - Number of seconds to wait for a block to be written to a connection - before aborting the write. -*/ -extern unsigned long net_write_timeout; - - -/* - If a read on a communication port is interrupted, retry this many times - before giving up. -*/ -extern unsigned long net_retry_count; - -extern unsigned int test_flags; -extern unsigned long bytes_sent, bytes_received; -extern unsigned long mysqld_net_retry_count; -extern unsigned long open_files_limit; - -bool create_pid_file(const char *pid_file_name, int pid); - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc deleted file mode 100644 index 8d71fcb8026..00000000000 --- a/server-tools/instance-manager/protocol.cc +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "protocol.h" - -#include "messages.h" - -#include <mysql_com.h> -#include <m_string.h> - - -static uchar eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ -static const char ERROR_PACKET_CODE= (char) 255; - - -int net_send_ok(struct st_net *net, unsigned long connection_id, - const char *message) -{ - /* - The format of a packet - 1 packet type code - 1-9 affected rows count - 1-9 connection id - 2 thread return status - 2 warning count - 1-9 + message length message to send (isn't stored if no message) - */ - Buffer buff; - uchar *pos= buff.buffer; - - /* check that we have space to hold mandatory fields */ - buff.reserve(0, 23); - - enum { OK_PACKET_CODE= 0 }; - *pos++= OK_PACKET_CODE; - pos= net_store_length(pos, (ulonglong) 0); - pos= net_store_length(pos, (ulonglong) connection_id); - int2store(pos, *net->return_status); - pos+= 2; - /* We don't support warnings, so store 0 for total warning count */ - int2store(pos, 0); - pos+= 2; - - size_t position= pos - buff.buffer; /* we might need it for message */ - - if (message != NULL) - { - buff.reserve(position, 9 + strlen(message)); - store_to_protocol_packet(&buff, message, &position); - } - - return my_net_write(net, buff.buffer, position) || net_flush(net); -} - - -int net_send_error(struct st_net *net, uint sql_errno) -{ - const char *err= message(sql_errno); - char buff[1 + // packet type code - 2 + // sql error number - 1 + SQLSTATE_LENGTH + // sql state - MYSQL_ERRMSG_SIZE]; // message - char *pos= buff; - - *pos++= ERROR_PACKET_CODE; - int2store(pos, sql_errno); - pos+= 2; - /* The first # is to make the protocol backward compatible */ - *pos++= '#'; - memcpy(pos, errno_to_sqlstate(sql_errno), SQLSTATE_LENGTH); - pos+= SQLSTATE_LENGTH; - pos= strmake(pos, err, MYSQL_ERRMSG_SIZE - 1) + 1; - return (my_net_write(net, (uchar*) buff, (size_t) (pos - buff)) || - net_flush(net)); -} - - -int net_send_error_323(struct st_net *net, uint sql_errno) -{ - const char *err= message(sql_errno); - char buff[1 + // packet type code - 2 + // sql error number - MYSQL_ERRMSG_SIZE]; // message - char *pos= buff; - - *pos++= ERROR_PACKET_CODE; - int2store(pos, sql_errno); - pos+= 2; - pos= strmake(pos, err, MYSQL_ERRMSG_SIZE - 1) + 1; - return (my_net_write(net, (uchar*) buff, (size_t) (pos - buff)) || - net_flush(net)); -} - -char *net_store_length(char *pkg, uint length) -{ - uchar *packet=(uchar*) pkg; - if (length < 251) - { - *packet=(uchar) length; - return (char*) packet+1; - } - *packet++=252; - int2store(packet,(uint) length); - return (char*) packet+2; -} - - -int store_to_protocol_packet(Buffer *buf, const char *string, size_t *position, - size_t string_len) -{ - uint currpos; - - /* reserve max amount of bytes needed to store length */ - if (buf->reserve(*position, 9)) - goto err; - currpos= (net_store_length(buf->buffer + *position, - (ulonglong) string_len) - buf->buffer); - if (buf->append(currpos, string, string_len)) - goto err; - *position= *position + string_len + (currpos - *position); - - return 0; -err: - return 1; -} - - -int store_to_protocol_packet(Buffer *buf, const char *string, - size_t *position) -{ - size_t string_len; - - string_len= strlen(string); - return store_to_protocol_packet(buf, string, position, string_len); -} - - -int send_eof(struct st_net *net) -{ - uchar buff[1 + /* eof packet code */ - 2 + /* warning count */ - 2]; /* server status */ - - buff[0]=254; - int2store(buff+1, 0); - int2store(buff+3, 0); - return my_net_write(net, buff, sizeof(buff)); -} - - -int send_fields(struct st_net *net, LIST *fields) -{ - LIST *tmp= fields; - Buffer send_buff; - uchar small_buff[4]; - size_t position= 0; - LEX_STRING *field; - - /* send the number of fileds */ - net_store_length(small_buff, (uint) list_length(fields)); - if (my_net_write(net, small_buff, (uint) 1)) - goto err; - - while (tmp) - { - position= 0; - field= (LEX_STRING *) tmp->data; - - store_to_protocol_packet(&send_buff, - (char*) "", &position); /* catalog name */ - store_to_protocol_packet(&send_buff, - (char*) "", &position); /* db name */ - store_to_protocol_packet(&send_buff, - (char*) "", &position); /* table name */ - store_to_protocol_packet(&send_buff, - (char*) "", &position); /* table name alias */ - store_to_protocol_packet(&send_buff, - field->str, &position); /* column name */ - store_to_protocol_packet(&send_buff, - field->str, &position); /* column name alias */ - send_buff.reserve(position, 12); - if (send_buff.is_error()) - goto err; - send_buff.buffer[position++]= 12; - int2store(send_buff.buffer + position, 1); /* charsetnr */ - int4store(send_buff.buffer + position + 2, - field->length); /* field length */ - send_buff.buffer[position+6]= (char) MYSQL_TYPE_STRING; /* type */ - int2store(send_buff.buffer + position + 7, 0); /* flags */ - send_buff.buffer[position + 9]= (char) 0; /* decimals */ - send_buff.buffer[position + 10]= 0; - send_buff.buffer[position + 11]= 0; - position+= 12; - if (my_net_write(net, send_buff.buffer, (uint) position+1)) - goto err; - tmp= list_rest(tmp); - } - - if (my_net_write(net, eof_buff, 1)) - goto err; - return 0; - -err: - return 1; -} diff --git a/server-tools/instance-manager/protocol.h b/server-tools/instance-manager/protocol.h deleted file mode 100644 index b06ae4dfdb2..00000000000 --- a/server-tools/instance-manager/protocol.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H - -#include "buffer.h" - -#include <my_list.h> - -/* default field length to be used in various field-realted functions */ -enum { DEFAULT_FIELD_LENGTH= 20 }; - -struct st_net; - -int net_send_ok(struct st_net *net, unsigned long connection_id, - const char *message); - -int net_send_error(struct st_net *net, unsigned sql_errno); - -int net_send_error_323(struct st_net *net, unsigned sql_errno); - -int send_fields(struct st_net *net, LIST *fields); - -char *net_store_length(char *pkg, uint length); - -int store_to_protocol_packet(Buffer *buf, const char *string, - size_t *position); - -int store_to_protocol_packet(Buffer *buf, const char *string, size_t *position, - size_t string_len); - -int send_eof(struct st_net *net); - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H */ diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc deleted file mode 100644 index 489caa0aaa8..00000000000 --- a/server-tools/instance-manager/thread_registry.cc +++ /dev/null @@ -1,419 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "thread_registry.h" -#include <thr_alarm.h> -#include <signal.h> -#include "log.h" - -#ifndef __WIN__ -/* Kick-off signal handler */ - -enum { THREAD_KICK_OFF_SIGNAL= SIGUSR2 }; - -extern "C" void handle_signal(int); - -void handle_signal(int __attribute__((unused)) sig_no) -{ -} -#endif - -/* Thread_info initializer methods */ - -void Thread_info::init(bool send_signal_on_shutdown_arg) -{ - thread_id= pthread_self(); - send_signal_on_shutdown= send_signal_on_shutdown_arg; -} - -/* - TODO: think about moving signal information (now it's shutdown_in_progress) - to Thread_info. It will reduce contention and allow signal deliverence to - a particular thread, not to the whole worker crew -*/ - -Thread_registry::Thread_registry() : - shutdown_in_progress(FALSE) - ,sigwait_thread_pid(pthread_self()) - ,error_status(FALSE) -{ - pthread_mutex_init(&LOCK_thread_registry, 0); - pthread_cond_init(&COND_thread_registry_is_empty, 0); - - /* head is used by-value to simplify nodes inserting */ - head.next= head.prev= &head; -} - - -Thread_registry::~Thread_registry() -{ - /* Check that no one uses the repository. */ - pthread_mutex_lock(&LOCK_thread_registry); - - for (Thread_info *ti= head.next; ti != &head; ti= ti->next) - { - log_error("Thread_registry: unregistered thread: %lu.", - (unsigned long) ti->thread_id); - } - - /* All threads must unregister */ - DBUG_ASSERT(head.next == &head); - - pthread_mutex_unlock(&LOCK_thread_registry); - pthread_cond_destroy(&COND_thread_registry_is_empty); - pthread_mutex_destroy(&LOCK_thread_registry); -} - - -/* - Set signal handler for kick-off thread, and insert a thread info to the - repository. New node is appended to the end of the list; head.prev always - points to the last node. -*/ - -void Thread_registry::register_thread(Thread_info *info, - bool send_signal_on_shutdown) -{ - info->init(send_signal_on_shutdown); - - DBUG_PRINT("info", ("Thread_registry: registering thread %lu...", - (unsigned long) info->thread_id)); - -#ifndef __WIN__ - struct sigaction sa; - sa.sa_handler= handle_signal; - sa.sa_flags= 0; - sigemptyset(&sa.sa_mask); - sigaction(THREAD_KICK_OFF_SIGNAL, &sa, 0); -#endif - info->current_cond= 0; - - pthread_mutex_lock(&LOCK_thread_registry); - info->next= &head; - info->prev= head.prev; - head.prev->next= info; - head.prev= info; - pthread_mutex_unlock(&LOCK_thread_registry); -} - - -/* - Unregister a thread from the repository and free Thread_info structure. - Every registered thread must unregister. Unregistering should be the last - thing a thread is doing, otherwise it could have no time to finalize. -*/ - -void Thread_registry::unregister_thread(Thread_info *info) -{ - DBUG_PRINT("info", ("Thread_registry: unregistering thread %lu...", - (unsigned long) info->thread_id)); - - pthread_mutex_lock(&LOCK_thread_registry); - info->prev->next= info->next; - info->next->prev= info->prev; - - if (head.next == &head) - { - DBUG_PRINT("info", ("Thread_registry: thread registry is empty!")); - pthread_cond_signal(&COND_thread_registry_is_empty); - } - - pthread_mutex_unlock(&LOCK_thread_registry); -} - - -/* - Check whether shutdown is in progress, and if yes, return immediately. - Else set info->current_cond and call pthread_cond_wait. When - pthread_cond_wait returns, unregister current cond and check the shutdown - status again. - RETURN VALUE - return value from pthread_cond_wait -*/ - -int Thread_registry::cond_wait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex) -{ - pthread_mutex_lock(&LOCK_thread_registry); - if (shutdown_in_progress) - { - pthread_mutex_unlock(&LOCK_thread_registry); - return 0; - } - info->current_cond= cond; - pthread_mutex_unlock(&LOCK_thread_registry); - /* sic: race condition here, cond can be signaled in deliver_shutdown */ - int rc= pthread_cond_wait(cond, mutex); - pthread_mutex_lock(&LOCK_thread_registry); - info->current_cond= 0; - pthread_mutex_unlock(&LOCK_thread_registry); - return rc; -} - - -int Thread_registry::cond_timedwait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex, - struct timespec *wait_time) -{ - int rc; - pthread_mutex_lock(&LOCK_thread_registry); - if (shutdown_in_progress) - { - pthread_mutex_unlock(&LOCK_thread_registry); - return 0; - } - info->current_cond= cond; - pthread_mutex_unlock(&LOCK_thread_registry); - /* sic: race condition here, cond can be signaled in deliver_shutdown */ - if ((rc= pthread_cond_timedwait(cond, mutex, wait_time)) == ETIME) - rc= ETIMEDOUT; // For easier usage - pthread_mutex_lock(&LOCK_thread_registry); - info->current_cond= 0; - pthread_mutex_unlock(&LOCK_thread_registry); - return rc; -} - - -/* - Deliver shutdown message to the workers crew. - As it's impossible to avoid all race conditions, signal latecomers - again. -*/ - -void Thread_registry::deliver_shutdown() -{ - pthread_mutex_lock(&LOCK_thread_registry); - shutdown_in_progress= TRUE; - -#ifndef __WIN__ - /* to stop reading from the network we need to flush alarm queue */ - end_thr_alarm(0); - /* - We have to deliver final alarms this way, as the main thread has already - stopped alarm processing. - */ - process_alarm(THR_SERVER_ALARM); -#endif - - /* - sic: race condition here, the thread may not yet fall into - pthread_cond_wait. - */ - - interrupt_threads(); - - wait_for_threads_to_unregister(); - - /* - If previous signals did not reach some threads, they must be sleeping - in pthread_cond_wait or in a blocking syscall. Wake them up: - every thread shall check signal variables after each syscall/cond_wait, - so this time everybody should be informed (presumably each worker can - get CPU during shutdown_time.) - */ - - interrupt_threads(); - - /* Get the last chance to threads to stop. */ - - wait_for_threads_to_unregister(); - -#ifndef DBUG_OFF - /* - Print out threads, that didn't stopped. Thread_registry destructor will - probably abort the program if there is still any alive thread. - */ - - if (head.next != &head) - { - DBUG_PRINT("info", ("Thread_registry: non-stopped threads:")); - - for (Thread_info *info= head.next; info != &head; info= info->next) - DBUG_PRINT("info", (" - %lu", (unsigned long) info->thread_id)); - } - else - { - DBUG_PRINT("info", ("Thread_registry: all threads stopped.")); - } -#endif // DBUG_OFF - - pthread_mutex_unlock(&LOCK_thread_registry); -} - - -void Thread_registry::request_shutdown() -{ - pthread_kill(sigwait_thread_pid, SIGTERM); -} - - -void Thread_registry::interrupt_threads() -{ - for (Thread_info *info= head.next; info != &head; info= info->next) - { - if (!info->send_signal_on_shutdown) - continue; - - pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL); - if (info->current_cond) - pthread_cond_signal(info->current_cond); - } -} - - -void Thread_registry::wait_for_threads_to_unregister() -{ - struct timespec shutdown_time; - - set_timespec(shutdown_time, 1); - - DBUG_PRINT("info", ("Thread_registry: joining threads...")); - - while (true) - { - if (head.next == &head) - { - DBUG_PRINT("info", ("Thread_registry: emptied.")); - return; - } - - int error= pthread_cond_timedwait(&COND_thread_registry_is_empty, - &LOCK_thread_registry, - &shutdown_time); - - if (error == ETIMEDOUT || error == ETIME) - { - DBUG_PRINT("info", ("Thread_registry: threads shutdown timed out.")); - return; - } - } -} - - -/********************************************************************* - class Thread -*********************************************************************/ - -#if defined(__ia64__) || defined(__ia64) -/* - We can live with 32K, but reserve 64K. Just to be safe. - On ia64 we need to reserve double of the size. -*/ -#define IM_THREAD_STACK_SIZE (128*1024L) -#else -#define IM_THREAD_STACK_SIZE (64*1024) -#endif - -/* - Change the stack size and start a thread. Return an error if either - pthread_attr_setstacksize or pthread_create fails. - Arguments are the same as for pthread_create(). -*/ - -static -int set_stacksize_and_create_thread(pthread_t *thread, pthread_attr_t *attr, - void *(*start_routine)(void *), void *arg) -{ - int rc= 0; - -#ifndef __WIN__ -#ifndef PTHREAD_STACK_MIN -#define PTHREAD_STACK_MIN 32768 -#endif - /* - Set stack size to be safe on the platforms with too small - default thread stack. - */ - rc= pthread_attr_setstacksize(attr, - (size_t) (PTHREAD_STACK_MIN + - IM_THREAD_STACK_SIZE)); -#endif - if (!rc) - rc= pthread_create(thread, attr, start_routine, arg); - return rc; -} - - -Thread::~Thread() -{ -} - - -void *Thread::thread_func(void *arg) -{ - Thread *thread= (Thread *) arg; - my_thread_init(); - - thread->run(); - - my_thread_end(); - return NULL; -} - - -bool Thread::start(enum_thread_type thread_type) -{ - pthread_attr_t attr; - int rc; - - pthread_attr_init(&attr); - - if (thread_type == DETACHED) - { - detached = TRUE; - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - } - else - { - detached = FALSE; - } - - rc= set_stacksize_and_create_thread(&id, &attr, Thread::thread_func, this); - pthread_attr_destroy(&attr); - - return rc != 0; -} - - -bool Thread::join() -{ - DBUG_ASSERT(!detached); - - return pthread_join(id, NULL) != 0; -} - - -int Thread_registry::get_error_status() -{ - int ret_error_status; - - pthread_mutex_lock(&LOCK_thread_registry); - ret_error_status= error_status; - pthread_mutex_unlock(&LOCK_thread_registry); - - return ret_error_status; -} - - -void Thread_registry::set_error_status() -{ - pthread_mutex_lock(&LOCK_thread_registry); - error_status= TRUE; - pthread_mutex_unlock(&LOCK_thread_registry); -} diff --git a/server-tools/instance-manager/thread_registry.h b/server-tools/instance-manager/thread_registry.h deleted file mode 100644 index d04c8442e44..00000000000 --- a/server-tools/instance-manager/thread_registry.h +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H - -/* - A multi-threaded application shall nicely work with signals. - - This means it shall, first of all, shut down nicely on ``quit'' signals: - stop all running threads, cleanup and exit. - - Note, that a thread can't be shut down nicely if it doesn't want to be. - That's why to perform clean shutdown, all threads constituting a process - must observe certain rules. Here we use the rules, described in Butenhof - book 'Programming with POSIX threads', namely: - - all user signals are handled in 'signal thread' in synchronous manner - (by means of sigwait). To guarantee that the signal thread is the only who - can receive user signals, all threads block them, and signal thread is - the only who calls sigwait() with an apporpriate sigmask. - To propogate a signal to the workers the signal thread sets - a variable, corresponding to the signal. Additionally the signal thread - sends each worker an internal signal (by means of pthread_kill) to kick it - out from possible blocking syscall, and possibly pthread_cond_signal if - some thread is blocked in pthread_cond_[timed]wait. - - a worker handles only internal 'kick' signal (the handler does nothing). - In case when a syscall returns 'EINTR' the worker checks all - signal-related variables and behaves accordingly. - Also these variables shall be checked from time to time in long - CPU-bounded operations, and before/after pthread_cond_wait. (It's supposed - that a worker thread either waits in a syscall/conditional variable, or - computes something.) - - to guarantee signal deliverence, there should be some kind of feedback, - e. g. all workers shall account in the signal thread Thread Repository and - unregister from it on exit. - - Configuration reload (on SIGHUP) and thread timeouts/alarms can be handled - in manner, similar to ``quit'' signals. -*/ - -#include <my_global.h> -#include <my_pthread.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/** - Thread_info - repository entry for each worker thread - All entries comprise double-linked list like: - 0 -- entry -- entry -- entry - 0 - Double-linked list is used to unregister threads easy. -*/ - -class Thread_info -{ -public: - Thread_info() {} - friend class Thread_registry; -private: - void init(bool send_signal_on_shutdown); -private: - pthread_cond_t *current_cond; - Thread_info *prev, *next; - pthread_t thread_id; - bool send_signal_on_shutdown; -}; - - -/** - A base class for a detached thread. -*/ - -class Thread -{ -public: - enum enum_thread_type - { - DETACHED, - JOINABLE - }; -public: - Thread() - { } - -public: - inline bool is_detached() const; - - bool start(enum_thread_type thread_type = JOINABLE); - bool join(); - -protected: - virtual void run()= 0; - virtual ~Thread(); - -private: - pthread_t id; - bool detached; - -private: - static void *thread_func(void *arg); - -private: - Thread(const Thread & /* rhs */); /* not implemented */ - Thread &operator=(const Thread & /* rhs */); /* not implemented */ -}; - -inline bool Thread::is_detached() const -{ - return detached; -} - - -/** - Thread_registry - contains handles for each worker thread to deliver - signal information to workers. -*/ - -class Thread_registry -{ -public: - Thread_registry(); - ~Thread_registry(); - - void register_thread(Thread_info *info, bool send_signal_on_shutdown= TRUE); - void unregister_thread(Thread_info *info); - void deliver_shutdown(); - void request_shutdown(); - inline bool is_shutdown(); - int cond_wait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex); - int cond_timedwait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex, struct timespec *wait_time); - int get_error_status(); - void set_error_status(); - -private: - void interrupt_threads(); - void wait_for_threads_to_unregister(); - -private: - Thread_info head; - bool shutdown_in_progress; - pthread_mutex_t LOCK_thread_registry; - pthread_cond_t COND_thread_registry_is_empty; - pthread_t sigwait_thread_pid; - bool error_status; - -private: - Thread_registry(const Thread_registry &); - Thread_registry &operator =(const Thread_registry &); -}; - - -inline bool Thread_registry::is_shutdown() -{ - pthread_mutex_lock(&LOCK_thread_registry); - bool res= shutdown_in_progress; - pthread_mutex_unlock(&LOCK_thread_registry); - return res; -} - - -#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H */ diff --git a/server-tools/instance-manager/user_management_commands.cc b/server-tools/instance-manager/user_management_commands.cc deleted file mode 100644 index 2eb0ae30aa5..00000000000 --- a/server-tools/instance-manager/user_management_commands.cc +++ /dev/null @@ -1,421 +0,0 @@ -/* Copyright (C) 2006 MySQL AB - - 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 */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "user_management_commands.h" - -#include "exit_codes.h" -#include "options.h" -#include "user_map.h" - -/************************************************************************* - Module-specific (internal) functions. -*************************************************************************/ - -/* - The function returns user name. The user name is retrieved from command-line - options (if specified) or from console. - - NOTE - This function must not be used in user-management command implementations. - Use get_user_name() instead. - - SYNOPSIS - get_user_name_impl() - - RETURN - NULL on error - valid pointer on success -*/ - -static char *get_user_name_impl() -{ - static char user_name_buf[1024]; - char *ptr; - - if (Options::User_management::user_name) - return Options::User_management::user_name; - - printf("Enter user name: "); - fflush(stdout); - - if (!fgets(user_name_buf, sizeof (user_name_buf), stdin)) - return NULL; - - if ((ptr= strchr(user_name_buf, '\n'))) - *ptr= 0; - - if ((ptr= strchr(user_name_buf, '\r'))) - *ptr= 0; - - return user_name_buf; -} - - -/* - The function is intended to provide user name for user-management - operations. It also checks that length of the specified user name is correct - (not empty, not exceeds USERNAME_LENGTH). Report to stderr if something is - wrong. - - SYNOPSIS - get_user_name() - user_name [OUT] on success contains user name - - RETURN - TRUE on error - FALSE on success -*/ - -static bool get_user_name(LEX_STRING *user_name) -{ - char *user_name_str= get_user_name_impl(); - - if (!user_name_str) - { - fprintf(stderr, "Error: unable to read user name from stdin.\n"); - return TRUE; - } - - user_name->str= user_name_str; - user_name->length= strlen(user_name->str); - - if (user_name->length == 0) - { - fprintf(stderr, "Error: user name can not be empty.\n"); - return TRUE; - } - - if (user_name->length > USERNAME_LENGTH) - { - fprintf(stderr, "Error: user name must not exceed %d characters.\n", - (int) USERNAME_LENGTH); - return TRUE; - } - - return FALSE; -} - - -/* - The function is intended to provide password for user-management operations. - The password is retrieved from command-line options (if specified) or from - console. - - SYNOPSIS - get_password() - - RETURN - NULL on error - valid pointer on success -*/ - -static const char *get_password() -{ - if (Options::User_management::password) - return Options::User_management::password; - - const char *passwd1= get_tty_password("Enter password: "); - const char *passwd2= get_tty_password("Re-type password: "); - - if (strcmp(passwd1, passwd2)) - { - fprintf(stderr, "Error: passwords do not match.\n"); - return 0; - } - - return passwd1; -} - - -/* - Load password file into user map. - - SYNOPSIS - load_password_file() - user_map target user map - - RETURN - See exit_codes.h for possible values. -*/ - -static int load_password_file(User_map *user_map) -{ - int err_code; - const char *err_msg; - - if (user_map->init()) - { - fprintf(stderr, "Error: can not initialize user map.\n"); - return ERR_OUT_OF_MEMORY; - } - - if ((err_code= user_map->load(Options::Main::password_file_name, &err_msg))) - fprintf(stderr, "Error: %s.\n", (const char *) err_msg); - - return err_code; -} - - -/* - Save user map into password file. - - SYNOPSIS - save_password_file() - user_map user map - - RETURN - See exit_codes.h for possible values. -*/ - -static int save_password_file(User_map *user_map) -{ - int err_code; - const char *err_msg; - - if ((err_code= user_map->save(Options::Main::password_file_name, &err_msg))) - fprintf(stderr, "Error: %s.\n", (const char *) err_msg); - - return err_code; -} - -/************************************************************************* - Print_password_line_cmd -*************************************************************************/ - -int Print_password_line_cmd::execute() -{ - LEX_STRING user_name; - const char *password; - - printf("Creating record for new user.\n"); - - if (get_user_name(&user_name)) - return ERR_CAN_NOT_READ_USER_NAME; - - if (!(password= get_password())) - return ERR_CAN_NOT_READ_PASSWORD; - - { - User user(&user_name, password); - - printf("%s:%s\n", - (const char *) user.user, - (const char *) user.scrambled_password); - } - - return ERR_OK; -} - - -/************************************************************************* - Add_user_cmd -*************************************************************************/ - -int Add_user_cmd::execute() -{ - LEX_STRING user_name; - const char *password; - - User_map user_map; - User *new_user; - - int err_code; - - if (get_user_name(&user_name)) - return ERR_CAN_NOT_READ_USER_NAME; - - /* Load the password file. */ - - if ((err_code= load_password_file(&user_map)) != ERR_OK) - return err_code; - - /* Check that the user does not exist. */ - - if (user_map.find_user(&user_name)) - { - fprintf(stderr, "Error: user '%s' already exists.\n", - (const char *) user_name.str); - return ERR_USER_ALREADY_EXISTS; - } - - /* Add the user. */ - - if (!(password= get_password())) - return ERR_CAN_NOT_READ_PASSWORD; - - if (!(new_user= new User(&user_name, password))) - return ERR_OUT_OF_MEMORY; - - if (user_map.add_user(new_user)) - { - delete new_user; - return ERR_OUT_OF_MEMORY; - } - - /* Save the password file. */ - - return save_password_file(&user_map); -} - - -/************************************************************************* - Drop_user_cmd -*************************************************************************/ - -int Drop_user_cmd::execute() -{ - LEX_STRING user_name; - - User_map user_map; - User *user; - - int err_code; - - if (get_user_name(&user_name)) - return ERR_CAN_NOT_READ_USER_NAME; - - /* Load the password file. */ - - if ((err_code= load_password_file(&user_map)) != ERR_OK) - return err_code; - - /* Find the user. */ - - user= user_map.find_user(&user_name); - - if (!user) - { - fprintf(stderr, "Error: user '%s' does not exist.\n", - (const char *) user_name.str); - return ERR_USER_NOT_FOUND; - } - - /* Remove the user (ignore possible errors). */ - - user_map.remove_user(user); - - /* Save the password file. */ - - return save_password_file(&user_map); -} - - -/************************************************************************* - Edit_user_cmd -*************************************************************************/ - -int Edit_user_cmd::execute() -{ - LEX_STRING user_name; - const char *password; - - User_map user_map; - User *user; - - int err_code; - - if (get_user_name(&user_name)) - return ERR_CAN_NOT_READ_USER_NAME; - - /* Load the password file. */ - - if ((err_code= load_password_file(&user_map)) != ERR_OK) - return err_code; - - /* Find the user. */ - - user= user_map.find_user(&user_name); - - if (!user) - { - fprintf(stderr, "Error: user '%s' does not exist.\n", - (const char *) user_name.str); - return ERR_USER_NOT_FOUND; - } - - /* Modify user's password. */ - - if (!(password= get_password())) - return ERR_CAN_NOT_READ_PASSWORD; - - user->set_password(password); - - /* Save the password file. */ - - return save_password_file(&user_map); -} - - -/************************************************************************* - Clean_db_cmd -*************************************************************************/ - -int Clean_db_cmd::execute() -{ - User_map user_map; - - if (user_map.init()) - { - fprintf(stderr, "Error: can not initialize user map.\n"); - return ERR_OUT_OF_MEMORY; - } - - return save_password_file(&user_map); -} - - -/************************************************************************* - Check_db_cmd -*************************************************************************/ - -int Check_db_cmd::execute() -{ - User_map user_map; - - return load_password_file(&user_map); -} - - -/************************************************************************* - List_users_cmd -*************************************************************************/ - -int List_users_cmd::execute() -{ - User_map user_map; - - int err_code; - - /* Load the password file. */ - - if ((err_code= load_password_file(&user_map))) - return err_code; - - /* Print out registered users. */ - - { - User_map::Iterator it(&user_map); - User *user; - - while ((user= it.next())) - fprintf(stderr, "%s\n", (const char *) user->user); - } - - return ERR_OK; -} diff --git a/server-tools/instance-manager/user_management_commands.h b/server-tools/instance-manager/user_management_commands.h deleted file mode 100644 index c925e6ae363..00000000000 --- a/server-tools/instance-manager/user_management_commands.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H - -/* - Copyright (C) 2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - This header contains declarations of classes inteded to support - user-management commands (such as add user, get list of users, etc). - - The general idea is to have one interface (pure abstract class) for such a - command. Each concrete user-management command is implemented in concrete - class, derived from the common interface. -*/ - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -/************************************************************************* - User_management_cmd -- base class for User-management commands. -*************************************************************************/ - -class User_management_cmd -{ -public: - User_management_cmd() - { } - - virtual ~User_management_cmd() - { } - -public: - /* - Executes user-management command. - - SYNOPSIS - execute() - - RETURN - See exit_codes.h for possible values. - */ - - virtual int execute() = 0; -}; - - -/************************************************************************* - Print_password_line_cmd: support for --print-password-line command-line - option. -*************************************************************************/ - -class Print_password_line_cmd: public User_management_cmd -{ -public: - Print_password_line_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - Add_user_cmd: support for --add-user command-line option. -*************************************************************************/ - -class Add_user_cmd: public User_management_cmd -{ -public: - Add_user_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - Drop_user_cmd: support for --drop-user command-line option. -*************************************************************************/ - -class Drop_user_cmd: public User_management_cmd -{ -public: - Drop_user_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - Edit_user_cmd: support for --edit-user command-line option. -*************************************************************************/ - -class Edit_user_cmd: public User_management_cmd -{ -public: - Edit_user_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - Clean_db_cmd: support for --clean-db command-line option. -*************************************************************************/ - -class Clean_db_cmd: public User_management_cmd -{ -public: - Clean_db_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - Check_db_cmd: support for --check-db command-line option. -*************************************************************************/ - -class Check_db_cmd: public User_management_cmd -{ -public: - Check_db_cmd() - { } - -public: - virtual int execute(); -}; - - -/************************************************************************* - List_users_cmd: support for --list-users command-line option. -*************************************************************************/ - -class List_users_cmd: public User_management_cmd -{ -public: - List_users_cmd() - { } - -public: - virtual int execute(); -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc deleted file mode 100644 index 49c35c16ca9..00000000000 --- a/server-tools/instance-manager/user_map.cc +++ /dev/null @@ -1,395 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION) -#pragma implementation -#endif - -#include "user_map.h" -#include "exit_codes.h" -#include "log.h" -#include "portability.h" - -User::User(const LEX_STRING *user_name_arg, const char *password) -{ - user_length= (uint8) (strmake(user, user_name_arg->str, - USERNAME_LENGTH + 1) - user); - set_password(password); -} - -int User::init(const char *line) -{ - const char *name_begin, *name_end, *password; - int password_length; - - if (line[0] == '\'' || line[0] == '"') - { - name_begin= line + 1; - name_end= strchr(name_begin, line[0]); - if (name_end == 0 || name_end[1] != ':') - { - log_error("Invalid format (unmatched quote) of user line (%s).", - (const char *) line); - return 1; - } - password= name_end + 2; - } - else - { - name_begin= line; - name_end= strchr(name_begin, ':'); - if (name_end == 0) - { - log_error("Invalid format (no delimiter) of user line (%s).", - (const char *) line); - return 1; - } - password= name_end + 1; - } - - user_length= (uint8) (name_end - name_begin); - if (user_length > USERNAME_LENGTH) - { - log_error("User name is too long (%d). Max length: %d. " - "User line: '%s'.", - (int) user_length, - (int) USERNAME_LENGTH, - (const char *) line); - return 1; - } - - password_length= (int) strlen(password); - if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH) - { - log_error("Password is too long (%d). Max length: %d." - "User line: '%s'.", - (int) password_length, - (int) SCRAMBLED_PASSWORD_CHAR_LENGTH, - (const char *) line); - return 1; - } - - memcpy(user, name_begin, user_length); - user[user_length]= 0; - - memcpy(scrambled_password, password, password_length); - scrambled_password[password_length]= 0; - - get_salt_from_password(salt, password); - - log_info("Loaded user '%s'.", (const char *) user); - - return 0; -} - - -C_MODE_START - -static uchar* get_user_key(const uchar* u, size_t* len, - my_bool __attribute__((unused)) t) -{ - const User *user= (const User *) u; - *len= user->user_length; - return (uchar *) user->user; -} - -static void delete_user(void *u) -{ - User *user= (User *) u; - delete user; -} - -C_MODE_END - - -void User_map::Iterator::reset() -{ - cur_idx= 0; -} - - -User *User_map::Iterator::next() -{ - if (cur_idx < user_map->hash.records) - return (User *) hash_element(&user_map->hash, cur_idx++); - - return NULL; -} - - -int User_map::init() -{ - enum { START_HASH_SIZE= 16 }; - if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, - get_user_key, delete_user, 0)) - return 1; - - initialized= TRUE; - - return 0; -} - - -User_map::User_map() - :initialized(FALSE) -{ -} - - -User_map::~User_map() -{ - if (initialized) - hash_free(&hash); -} - - -/* - Load password database. - - SYNOPSIS - load() - password_file_name [IN] password file path - err_msg [OUT] error message - - DESCRIPTION - Load all users from the password file. Must be called once right after - construction. In case of failure, puts error message to the log file and - returns specific error code. - - RETURN - 0 on success - !0 on error -*/ - -int User_map::load(const char *password_file_name, const char **err_msg) -{ - static const int ERR_MSG_BUF_SIZE = 255; - static char err_msg_buf[ERR_MSG_BUF_SIZE]; - - FILE *file; - char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH + - 2 + /* for possible quotes */ - 1 + /* for ':' */ - 2 + /* for newline */ - 1]; /* for trailing zero */ - User *user; - - if (my_access(password_file_name, F_OK) != 0) - { - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "password file (%s) does not exist", - (const char *) password_file_name); - *err_msg= err_msg_buf; - } - - return ERR_PASSWORD_FILE_DOES_NOT_EXIST; - } - - if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0) - { - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "can not open password file (%s): %s", - (const char *) password_file_name, - (const char *) strerror(errno)); - *err_msg= err_msg_buf; - } - - return ERR_IO_ERROR; - } - - log_info("Loading the password database..."); - - while (fgets(line, sizeof(line), file)) - { - char *user_line= line; - - /* - We need to skip EOL-symbols also from the beginning of the line, because - if the previous line was ended by \n\r sequence, we get \r in our line. - */ - - while (user_line[0] == '\r' || user_line[0] == '\n') - ++user_line; - - /* Skip EOL-symbols in the end of the line. */ - - { - char *ptr; - - if ((ptr= strchr(user_line, '\n'))) - *ptr= 0; - - if ((ptr= strchr(user_line, '\r'))) - *ptr= 0; - } - - /* skip comments and empty lines */ - if (!user_line[0] || user_line[0] == '#') - continue; - - if ((user= new User) == 0) - { - my_fclose(file, MYF(0)); - - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "out of memory while parsing password file (%s)", - (const char *) password_file_name); - *err_msg= err_msg_buf; - } - - return ERR_OUT_OF_MEMORY; - } - - if (user->init(user_line)) - { - delete user; - my_fclose(file, MYF(0)); - - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "password file (%s) corrupted", - (const char *) password_file_name); - *err_msg= err_msg_buf; - } - - return ERR_PASSWORD_FILE_CORRUPTED; - } - - if (my_hash_insert(&hash, (uchar *) user)) - { - delete user; - my_fclose(file, MYF(0)); - - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "out of memory while parsing password file (%s)", - (const char *) password_file_name); - *err_msg= err_msg_buf; - } - - return ERR_OUT_OF_MEMORY; - } - } - - log_info("The password database loaded successfully."); - - my_fclose(file, MYF(0)); - - if (err_msg) - *err_msg= NULL; - - return ERR_OK; -} - - -int User_map::save(const char *password_file_name, const char **err_msg) -{ - static const int ERR_MSG_BUF_SIZE = 255; - static char err_msg_buf[ERR_MSG_BUF_SIZE]; - - FILE *file; - - if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY, - MYF(0))) == 0) - { - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "can not open password file (%s) for writing: %s", - (const char *) password_file_name, - (const char *) strerror(errno)); - *err_msg= err_msg_buf; - } - - return ERR_IO_ERROR; - } - - { - User_map::Iterator it(this); - User *user; - - while ((user= it.next())) - { - if (fprintf(file, "%s:%s\n", (const char *) user->user, - (const char *) user->scrambled_password) < 0) - { - if (err_msg) - { - snprintf(err_msg_buf, ERR_MSG_BUF_SIZE, - "can not write to password file (%s): %s", - (const char *) password_file_name, - (const char *) strerror(errno)); - *err_msg= err_msg_buf; - } - - my_fclose(file, MYF(0)); - - return ERR_IO_ERROR; - } - } - } - - my_fclose(file, MYF(0)); - - return ERR_OK; -} - - -/* - Check if user exists and password is correct - RETURN VALUE - 0 - user found and password OK - 1 - password mismatch - 2 - user not found -*/ - -int User_map::authenticate(const LEX_STRING *user_name, - const char *scrambled_password, - const char *scramble) const -{ - const User *user= find_user(user_name); - return user ? check_scramble(scrambled_password, scramble, user->salt) : 2; -} - - -User *User_map::find_user(const LEX_STRING *user_name) -{ - return (User*) hash_search(&hash, (uchar*) user_name->str, user_name->length); -} - -const User *User_map::find_user(const LEX_STRING *user_name) const -{ - return const_cast<User_map *> (this)->find_user(user_name); -} - - -bool User_map::add_user(User *user) -{ - return my_hash_insert(&hash, (uchar*) user) == 0 ? FALSE : TRUE; -} - - -bool User_map::remove_user(User *user) -{ - return hash_delete(&hash, (uchar*) user) == 0 ? FALSE : TRUE; -} diff --git a/server-tools/instance-manager/user_map.h b/server-tools/instance-manager/user_map.h deleted file mode 100644 index 6168f2b04fa..00000000000 --- a/server-tools/instance-manager/user_map.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright (C) 2004-2006 MySQL AB - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H -#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H - -#include <my_global.h> -#include <my_sys.h> -#include <mysql_com.h> -#include <m_string.h> -#include <hash.h> - -#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE) -#pragma interface -#endif - -struct User -{ - User() - {} - - User(const LEX_STRING *user_name_arg, const char *password); - - int init(const char *line); - - inline void set_password(const char *password) - { - make_scrambled_password(scrambled_password, password); - } - - char user[USERNAME_LENGTH + 1]; - char scrambled_password[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1]; - uint8 user_length; - uint8 salt[SCRAMBLE_LENGTH]; -}; - -/* - User_map -- all users and passwords -*/ - -class User_map -{ -public: - /* User_map iterator */ - - class Iterator - { - public: - Iterator(User_map *user_map_arg) : - user_map(user_map_arg), cur_idx(0) - { } - - public: - void reset(); - - User *next(); - - private: - User_map *user_map; - uint cur_idx; - }; - -public: - User_map(); - ~User_map(); - - int init(); - int load(const char *password_file_name, const char **err_msg); - int save(const char *password_file_name, const char **err_msg); - int authenticate(const LEX_STRING *user_name, - const char *scrambled_password, - const char *scramble) const; - - const User *find_user(const LEX_STRING *user_name) const; - User *find_user(const LEX_STRING *user_name); - - bool add_user(User *user); - bool remove_user(User *user); - -private: - User_map(const User_map &); - User_map &operator =(const User_map &); - -private: - HASH hash; - bool initialized; - - friend class Iterator; -}; - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H |