summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xserver-tools/instance-manager/IMService.cpp73
-rwxr-xr-xserver-tools/instance-manager/IMService.h14
-rwxr-xr-xserver-tools/instance-manager/WindowsService.cpp200
-rwxr-xr-xserver-tools/instance-manager/WindowsService.h44
-rw-r--r--server-tools/instance-manager/commands.cc9
-rw-r--r--server-tools/instance-manager/guardian.cc12
-rw-r--r--server-tools/instance-manager/instance.cc212
-rw-r--r--server-tools/instance-manager/instance.h3
-rw-r--r--server-tools/instance-manager/instance_map.cc13
-rw-r--r--server-tools/instance-manager/instance_options.h1
-rw-r--r--server-tools/instance-manager/listener.cc296
-rw-r--r--server-tools/instance-manager/listener.h2
-rw-r--r--server-tools/instance-manager/log.cc2
-rw-r--r--server-tools/instance-manager/manager.cc95
-rw-r--r--server-tools/instance-manager/manager.h2
-rw-r--r--server-tools/instance-manager/mysqlmanager.cc24
-rwxr-xr-xserver-tools/instance-manager/mysqlmanager.vcproj295
-rw-r--r--server-tools/instance-manager/options.cc91
-rw-r--r--server-tools/instance-manager/options.h13
-rw-r--r--server-tools/instance-manager/parse_output.cc1
-rwxr-xr-xserver-tools/instance-manager/port.h25
-rw-r--r--server-tools/instance-manager/priv.cc2
-rw-r--r--server-tools/instance-manager/priv.h6
-rw-r--r--server-tools/instance-manager/thread_registry.cc9
-rw-r--r--server-tools/instance-manager/user_map.cc12
25 files changed, 1236 insertions, 220 deletions
diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp
new file mode 100755
index 00000000000..920a0f3db0c
--- /dev/null
+++ b/server-tools/instance-manager/IMService.cpp
@@ -0,0 +1,73 @@
+#include <windows.h>
+#include "log.h"
+#include "options.h"
+#include "IMService.h"
+
+IMService::IMService(void)
+{
+ serviceName = "MySqlManager";
+ displayName = "MySQL Manager";
+}
+
+IMService::~IMService(void)
+{
+}
+
+void IMService::Stop()
+{
+ ReportStatus(SERVICE_STOP_PENDING);
+ // stop the IM work
+}
+
+void IMService::Run()
+{
+ // report to the SCM that we're about to start
+ ReportStatus((DWORD)SERVICE_START_PENDING);
+
+ // init goes here
+
+ ReportStatus((DWORD)SERVICE_RUNNING);
+
+ // wait for main loop to terminate
+}
+
+void IMService::Log(const char *msg)
+{
+ log_info(msg);
+}
+
+int HandleServiceOptions(Options options)
+{
+ int ret_val = 0;
+
+ IMService winService;
+
+ if (options.install_as_service)
+ {
+ if (winService.IsInstalled())
+ log_info("Service is already installed\n");
+ else if (winService.Install())
+ log_info("Service installed successfully\n");
+ else
+ {
+ log_info("Service failed to install\n");
+ ret_val = -1;
+ }
+ }
+ else if (options.remove_service)
+ {
+ if (! winService.IsInstalled())
+ log_info("Service is not installed\n");
+ else if (winService.Remove())
+ log_info("Service removed successfully\n");
+ else
+ {
+ log_info("Service failed to remove\n");
+ ret_val = -1;
+ }
+ }
+ else
+ return (int)winService.Init();
+ return ret_val;
+}
+
diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h
new file mode 100755
index 00000000000..60c202fc561
--- /dev/null
+++ b/server-tools/instance-manager/IMService.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "windowsservice.h"
+
+class IMService : public WindowsService
+{
+public:
+ IMService(void);
+ ~IMService(void);
+
+protected:
+ void Log(const char *msg);
+ void Stop();
+ void Run();
+};
diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp
new file mode 100755
index 00000000000..851ac9beac8
--- /dev/null
+++ b/server-tools/instance-manager/WindowsService.cpp
@@ -0,0 +1,200 @@
+#include <windows.h>
+#include <assert.h>
+#include ".\windowsservice.h"
+
+static WindowsService *gService;
+
+WindowsService::WindowsService(void)
+: statusCheckpoint(0), serviceName(NULL), inited(false),
+ dwAcceptedControls(SERVICE_ACCEPT_STOP)
+{
+ gService = this;
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ status.dwServiceSpecificExitCode = 0;
+}
+
+WindowsService::~WindowsService(void)
+{
+}
+
+BOOL WindowsService::Install()
+{
+ 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()
+{
+ 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();
+ 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)
+{
+ assert(gService != NULL);
+
+ // register our service control handler:
+ gService->RegisterAndRun(argc, argv);
+}
+
+void WINAPI WindowsService::ControlHandler(DWORD opcode)
+{
+ assert(gService != NULL);
+
+ return gService->HandleControlCode(opcode);
+}
+
+
diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h
new file mode 100755
index 00000000000..b266bbca533
--- /dev/null
+++ b/server-tools/instance-manager/WindowsService.h
@@ -0,0 +1,44 @@
+#pragma once
+
+class WindowsService
+{
+protected:
+ bool inited;
+ const char *serviceName;
+ const char *displayName;
+ const char *username;
+ const char *password;
+ SERVICE_STATUS_HANDLE statusHandle;
+ DWORD statusCheckpoint;
+ SERVICE_STATUS status;
+ DWORD dwAcceptedControls;
+ bool debugging;
+
+public:
+ WindowsService(void);
+ ~WindowsService(void);
+
+ BOOL Install();
+ 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() = 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/commands.cc b/server-tools/instance-manager/commands.cc
index 2357f97fd93..3cc5039a59c 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -22,6 +22,7 @@
#include "mysql_manager_error.h"
#include "protocol.h"
#include "buffer.h"
+#include "options.h"
#include <m_string.h>
#include <mysql.h>
@@ -469,7 +470,7 @@ int Show_instance_log::execute(struct st_net *net, ulong connection_id)
size_t buff_size;
int read_len;
/* calculate buffer size */
- struct stat file_stat;
+ MY_STAT file_stat;
/* my_fstat doesn't use the flag parameter */
if (my_fstat(fd, &file_stat, MYF(0)))
@@ -481,7 +482,7 @@ int Show_instance_log::execute(struct st_net *net, ulong connection_id)
read_len= my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
char *bf= (char*) malloc(sizeof(char)*buff_size);
- if ((read_len= my_read(fd, bf, buff_size, MYF(0))) < 0)
+ if ((read_len= my_read(fd, (byte*)bf, buff_size, MYF(0))) < 0)
return ER_READ_FILE;
store_to_protocol_packet(&send_buff, (char*) bf, &position, read_len);
close(fd);
@@ -604,7 +605,7 @@ int Show_instance_log_files::execute(struct st_net *net, ulong connection_id)
store_to_protocol_packet(&send_buff, "", &position);
store_to_protocol_packet(&send_buff, (char*) "0", &position);
}
- else if (S_ISREG(file_stat.st_mode))
+ else if (MY_S_ISREG(file_stat.st_mode))
{
store_to_protocol_packet(&send_buff,
(char*) log_files->value,
@@ -689,7 +690,7 @@ int Set_option::correct_file(int skip)
{
int error;
- error= modify_defaults_file("/etc/my.cnf", option,
+ error= modify_defaults_file(Options::config_file, option,
option_value, instance_name, skip);
if (error > 0)
return ER_OUT_OF_RESOURCES;
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
index 404e9f34ab5..0d6ebfa8d79 100644
--- a/server-tools/instance-manager/guardian.cc
+++ b/server-tools/instance-manager/guardian.cc
@@ -25,6 +25,7 @@
#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
+#include "port.h"
#include <string.h>
#include <sys/types.h>
@@ -32,7 +33,6 @@
-
C_MODE_START
pthread_handler_decl(guardian, arg)
@@ -426,11 +426,21 @@ int Guardian_thread::stop_instances(bool stop_instances_arg)
int Guardian_thread::lock()
{
+#ifdef __WIN__
+ pthread_mutex_lock(&LOCK_guardian);
+ return 0;
+#else
return pthread_mutex_lock(&LOCK_guardian);
+#endif
}
int Guardian_thread::unlock()
{
+#ifdef __WIN__
+ pthread_mutex_unlock(&LOCK_guardian);
+ return 0;
+#else
return pthread_mutex_unlock(&LOCK_guardian);
+#endif
}
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 2b25c74439e..5e3c07b9b31 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -18,14 +18,19 @@
#pragma implementation
#endif
+#ifdef __WIN__
+#include <process.h>
+#endif
#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
#include "instance_map.h"
#include "priv.h"
-
+#include "port.h"
+#ifndef __WIN__
#include <sys/wait.h>
+#endif
#include <my_sys.h>
#include <signal.h>
#include <m_string.h>
@@ -50,6 +55,16 @@ pthread_handler_decl(proxy, arg)
C_MODE_END
+void Instance::remove_pid()
+{
+ int pid;
+ if ((pid= options.get_pid()) != 0) /* check the pidfile */
+ if (options.unlink_pidfile()) /* remove stalled pidfile */
+ log_error("cannot remove pidfile for instance %i, this might be \
+ since IM lacks permmissions or hasn't found the pidifle",
+ options.instance_name);
+}
+
/*
The method starts an instance.
@@ -65,8 +80,6 @@ C_MODE_END
int Instance::start()
{
- pid_t pid;
-
/* clear crash flag */
pthread_mutex_lock(&LOCK_instance);
crashed= 0;
@@ -75,11 +88,7 @@ int Instance::start()
if (!is_running())
{
- if ((pid= options.get_pid()) != 0) /* check the pidfile */
- if (options.unlink_pidfile()) /* remove stalled pidfile */
- log_error("cannot remove pidfile for instance %i, this might be \
- since IM lacks permmissions or hasn't found the pidifle",
- options.instance_name);
+ remove_pid();
/*
No need to monitor this thread in the Thread_registry, as all
@@ -107,20 +116,21 @@ int Instance::start()
return ER_INSTANCE_ALREADY_STARTED;
}
-
-void Instance::fork_and_monitor()
+#ifndef __WIN__
+int Instance::launch_and_wait()
{
- pid_t pid;
- log_info("starting instance %s", options.instance_name);
- switch (pid= fork()) {
- case 0:
- execv(options.mysqld_path, options.argv);
- /* exec never returns */
- exit(1);
- case -1:
- log_info("cannot fork() to start instance %s", options.instance_name);
- return;
- default:
+ pid_t pid = fork();
+
+ switch (pid)
+ {
+ case 0:
+ execv(options.mysqld_path, options.argv);
+ /* exec never returns */
+ exit(1);
+ case -1:
+ log_info("cannot fork() to start instance %s", options.instance_name);
+ return -1;
+ default:
/*
Here we wait for the child created. This process differs for systems
running LinuxThreads and POSIX Threads compliant systems. This is because
@@ -141,22 +151,89 @@ void Instance::fork_and_monitor()
wait(NULL); /* LinuxThreads were detected */
else
waitpid(pid, NULL, 0);
- /* set instance state to crashed */
- pthread_mutex_lock(&LOCK_instance);
- crashed= 1;
- pthread_mutex_unlock(&LOCK_instance);
-
- /*
- Wake connection threads waiting for an instance to stop. This
- is needed if a user issued command to stop an instance via
- mysql connection. This is not the case if Guardian stop the thread.
- */
- pthread_cond_signal(&COND_instance_stopped);
- /* wake guardian */
- pthread_cond_signal(&instance_map->guardian->COND_guardian);
- /* thread exits */
- return;
}
+ return 0;
+}
+#else
+int Instance::launch_and_wait()
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ int cmdlen = 0;
+ for (int i=1; options.argv[i] != 0; i++)
+ cmdlen += strlen(options.argv[i]) + 1;
+ cmdlen++; // we have to add a single space for CreateProcess (read the docs)
+
+ char *cmdline = NULL;
+ if (cmdlen > 0)
+ {
+ cmdline = new char[cmdlen];
+ cmdline[0] = 0;
+ for (int i=1; options.argv[i] != 0; i++)
+ {
+ strcat(cmdline, " ");
+ strcat(cmdline, options.argv[i]);
+ }
+ }
+
+ // Start the child process.
+ BOOL result = CreateProcess(options.mysqld_path, // file to execute
+ 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;
+ if (! result)
+ return -1;
+
+ // 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 );
+
+ return exitcode;
+}
+#endif
+
+
+void Instance::fork_and_monitor()
+{
+ log_info("starting instance %s", options.instance_name);
+
+ int result = launch_and_wait();
+ if (result == -1) return;
+
+ /* set instance state to crashed */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 1;
+ pthread_mutex_unlock(&LOCK_instance);
+
+ /*
+ Wake connection threads waiting for an instance to stop. This
+ is needed if a user issued command to stop an instance via
+ mysql connection. This is not the case if Guardian stop the thread.
+ */
+ pthread_cond_signal(&COND_instance_stopped);
+ /* wake guardian */
+ pthread_cond_signal(&instance_map->guardian->COND_guardian);
+ /* thread exits */
+ return;
+
/* we should never end up here */
DBUG_ASSERT(0);
}
@@ -253,7 +330,6 @@ bool Instance::is_running()
int Instance::stop()
{
- pid_t pid;
struct timespec timeout;
uint waitchild= (uint) DEFAULT_SHUTDOWN_DELAY;
@@ -290,6 +366,68 @@ err:
return ER_STOP_INSTANCE;
}
+#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
void Instance::kill_instance(int signum)
{
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index 39a2b8ee846..0ff5ecc179e 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -61,6 +61,9 @@ private:
*/
pthread_cond_t COND_instance_stopped;
Instance_map *instance_map;
+
+ void remove_pid();
+ int launch_and_wait();
};
#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
index fa8a5d58114..2c7166c59f5 100644
--- a/server-tools/instance-manager/instance_map.cc
+++ b/server-tools/instance-manager/instance_map.cc
@@ -22,6 +22,7 @@
#include "buffer.h"
#include "instance.h"
+#include "options.h"
#include <m_ctype.h>
#include <mysql_com.h>
@@ -138,13 +139,23 @@ Instance_map::~Instance_map()
int Instance_map::lock()
{
+#ifdef __WIN__
+ pthread_mutex_lock(&LOCK_instance_map);
+ return 0;
+#else
return pthread_mutex_lock(&LOCK_instance_map);
+#endif
}
int Instance_map::unlock()
{
+#ifdef __WIN__
+ pthread_mutex_unlock(&LOCK_instance_map);
+ return 0;
+#else
return pthread_mutex_unlock(&LOCK_instance_map);
+#endif
}
@@ -245,7 +256,7 @@ int Instance_map::load()
else
argv_options[1]= '\0';
- if (my_search_option_files("my", &argc, (char ***) &argv, &args_used,
+ if (my_search_option_files(Options::config_file, &argc, (char ***) &argv, &args_used,
process_option, (void*) this) ||
complete_initialization())
return 1;
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
index 9dac8b39bdc..a5a38ff1221 100644
--- a/server-tools/instance-manager/instance_options.h
+++ b/server-tools/instance-manager/instance_options.h
@@ -19,6 +19,7 @@
#include <my_global.h>
#include <my_sys.h>
#include "parse.h"
+#include "port.h"
#ifdef __GNUC__
#pragma interface
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 4aed18c753d..a161fc9730b 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -19,11 +19,13 @@
#endif
#include "listener.h"
-
+#include "priv.h"
#include <m_string.h>
#include <mysql.h>
#include <violite.h>
+#ifndef __WIN__
#include <sys/un.h>
+#endif
#include <sys/stat.h>
#include "thread_registry.h"
@@ -31,7 +33,7 @@
#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
-#include "priv.h"
+#include "port.h"
/*
@@ -47,10 +49,17 @@ public:
private:
ulong total_connection_count;
Thread_info thread_info;
+
+ int sockets[2];
+ int num_sockets;
+ fd_set read_fds;
private:
void handle_new_mysql_connection(Vio *vio);
+ int create_tcp_socket();
+ int create_unix_socket(struct sockaddr_un &unix_socket_address);
};
+const int LISTEN_BACK_LOG_SIZE = 5; // standard backlog size
Listener_thread::Listener_thread(const Listener_thread_args &args) :
Listener_thread_args(args.thread_registry, args.options, args.user_map,
@@ -58,6 +67,7 @@ Listener_thread::Listener_thread(const Listener_thread_args &args) :
,total_connection_count(0)
,thread_info(pthread_self())
{
+ num_sockets= 0;
}
@@ -78,30 +88,134 @@ Listener_thread::~Listener_thread()
void Listener_thread::run()
{
- enum { LISTEN_BACK_LOG_SIZE = 5 }; // standard backlog size
- int flags;
- int arg= 1; /* value to be set by setsockopt */
- int unix_socket;
- uint im_port;
/* we use this var to check whether we are running on LinuxThreads */
pid_t thread_pid;
+ int n;
thread_pid= getpid();
+
+#ifndef __WIN__
+ struct sockaddr_un unix_socket_address;
/* set global variable */
linuxthreads= (thread_pid != manager_pid);
+#endif
thread_registry.register_thread(&thread_info);
my_thread_init();
+ 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 (int i=0; i < num_sockets; i++)
+ n = max(n, sockets[i]);
+ n++;
+
+ while (thread_registry.is_shutdown() == false)
+ {
+ fd_set read_fds_arg= read_fds;
+
+ /*
+ 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, 0);
+
+
+ if (rc == -1 && errno != EINTR)
+ {
+ log_error("Listener_thread::run(): select() failed, %s",
+ 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
+ {
+ Vio *vio = vio_new(client_fd, socket_index==0?VIO_TYPE_SOCKET:VIO_TYPE_TCPIP,
+ socket_index==0?1:0);
+ if (vio != 0)
+ handle_new_mysql_connection(vio);
+ else
+ {
+ shutdown(client_fd, SHUT_RDWR);
+ close(client_fd);
+ }
+ }
+ }
+ }
+ }
+
+ /* III. Release all resources and exit */
+
+ log_info("Listener_thread::run(): shutdown requested, exiting...");
+
+ for (int i=0; i < num_sockets; i++)
+ close(sockets[i]);
+
+#ifndef __WIN__
+ unlink(unix_socket_address.sun_path);
+#endif
+
+ thread_registry.unregister_thread(&thread_info);
+ my_thread_end();
+ return;
+
+err:
+ thread_registry.unregister_thread(&thread_info);
+ thread_registry.request_shutdown();
+ my_thread_end();
+ return;
+}
+
+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
+}
+
+void set_no_inherit(int socket)
+{
+#ifndef __WIN__
+ int flags= fcntl(socket, F_GETFD, 0);
+ fcntl(socket, F_SETFD, flags | FD_CLOEXEC);
+#else
+#endif
+}
+
+int Listener_thread::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_thead::run(): socket(AF_INET) failed, %s",
strerror(errno));
- goto err;
+ return -1;
}
struct sockaddr_in ip_socket_address;
@@ -115,7 +229,7 @@ void Listener_thread::run()
}
else
im_bind_addr= htonl(INADDR_ANY);
- im_port= options.port_number;
+ uint im_port= options.port_number;
ip_socket_address.sin_family= AF_INET;
ip_socket_address.sin_addr.s_addr = im_bind_addr;
@@ -130,154 +244,86 @@ void Listener_thread::run()
{
log_error("Listener_thread::run(): bind(ip socket) failed, '%s'",
strerror(errno));
- goto err;
+ close(ip_socket);
+ return -1;
}
if (listen(ip_socket, LISTEN_BACK_LOG_SIZE))
{
log_error("Listener_thread::run(): listen(ip socket) failed, %s",
strerror(errno));
- goto err;
+ close(ip_socket);
+ return -1;
}
- /* set the socket nonblocking */
- flags= fcntl(ip_socket, F_GETFL, 0);
- fcntl(ip_socket, F_SETFL, flags | O_NONBLOCK);
- /* make sure that instances won't be listening our sockets */
- flags= fcntl(ip_socket, F_GETFD, 0);
- fcntl(ip_socket, F_SETFD, flags | FD_CLOEXEC);
+ /* 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("accepting connections on ip socket");
+ return 0;
+}
- /*--------------------------------------------------------------*/
- unix_socket= socket(AF_UNIX, SOCK_STREAM, 0);
+#ifndef __WIN__
+int Listener_thread::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_thead::run(): socket(AF_UNIX) failed, %s",
strerror(errno));
- goto err;
+ return -1;
}
- struct sockaddr_un unix_socket_address;
bzero(&unix_socket_address, sizeof(unix_socket_address));
unix_socket_address.sun_family= AF_UNIX;
strmake(unix_socket_address.sun_path, options.socket_file_name,
sizeof(unix_socket_address.sun_path));
- unlink(unix_socket_address.sun_path); /* in case we have stale socket file */
+ 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)))
{
- /*
- 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_thread::run(): bind(unix socket) failed, "
+ log_error("Listener_thread::run(): bind(unix socket) failed, "
"socket file name is '%s', error '%s'",
unix_socket_address.sun_path, strerror(errno));
- goto err;
- }
- umask(old_mask);
-
- if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
- {
- log_error("Listener_thread::run(): listen(unix socket) failed, %s",
- strerror(errno));
- goto err;
- }
-
- /* set the socket nonblocking */
- flags= fcntl(unix_socket, F_GETFL, 0);
- fcntl(unix_socket, F_SETFL, flags | O_NONBLOCK);
- /* make sure that instances won't be listening our sockets */
- flags= fcntl(unix_socket, F_GETFD, 0);
- fcntl(unix_socket, F_SETFD, flags | FD_CLOEXEC);
+ close(unix_socket);
+ return -1;
}
- log_info("accepting connections on unix socket %s",
- unix_socket_address.sun_path);
-
- /* II. Listen sockets and spawn childs */
-
+
+ umask(old_mask);
+
+ if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
{
- int n= max(unix_socket, ip_socket) + 1;
- fd_set read_fds;
-
- FD_ZERO(&read_fds);
- FD_SET(unix_socket, &read_fds);
- FD_SET(ip_socket, &read_fds);
-
- while (thread_registry.is_shutdown() == false)
- {
- fd_set read_fds_arg= read_fds;
-
- /*
- 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, 0);
-
-
- if (rc == -1 && errno != EINTR)
- log_error("Listener_thread::run(): select() failed, %s",
- strerror(errno));
- else
- {
- /* Assuming that rc > 0 as we asked to wait forever */
- if (FD_ISSET(unix_socket, &read_fds_arg))
- {
- int client_fd= accept(unix_socket, 0, 0);
- /* accept may return -1 (failure or spurious wakeup) */
- if (client_fd >= 0) // connection established
- {
- if (Vio *vio= vio_new(client_fd, VIO_TYPE_SOCKET, 1))
- handle_new_mysql_connection(vio);
- else
- {
- shutdown(client_fd, SHUT_RDWR);
- close(client_fd);
- }
- }
- }
- else if (FD_ISSET(ip_socket, &read_fds_arg))
- {
- int client_fd= accept(ip_socket, 0, 0);
- /* accept may return -1 (failure or spurious wakeup) */
- if (client_fd >= 0) // connection established
- {
- if (Vio *vio= vio_new(client_fd, VIO_TYPE_TCPIP, 0))
- handle_new_mysql_connection(vio);
- else
- {
- shutdown(client_fd, SHUT_RDWR);
- close(client_fd);
- }
- }
- }
- }
- }
+ log_error("Listener_thread::run(): listen(unix socket) failed, %s",
+ strerror(errno));
+ close(unix_socket);
+ return -1;
}
- /* III. Release all resources and exit */
-
- log_info("Listener_thread::run(): shutdown requested, exiting...");
-
- close(unix_socket);
- close(ip_socket);
- unlink(unix_socket_address.sun_path);
+ /* set the socket nonblocking */
+ set_non_blocking(unix_socket);
- thread_registry.unregister_thread(&thread_info);
- my_thread_end();
- return;
+ /* make sure that instances won't be listening our sockets */
+ set_no_inherit(unix_socket);
-err:
- thread_registry.unregister_thread(&thread_info);
- thread_registry.request_shutdown();
- my_thread_end();
- return;
+ log_info("accepting connections on unix socket %s", unix_socket_address.sun_path);
+ sockets[num_sockets++] = unix_socket;
+ FD_SET(unix_socket, &read_fds);
+ return 0;
}
+#endif
/*
diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h
index 7a8af49e2b3..67a090c3aa2 100644
--- a/server-tools/instance-manager/listener.h
+++ b/server-tools/instance-manager/listener.h
@@ -31,7 +31,7 @@ pthread_handler_decl(listener, arg);
C_MODE_END
class Thread_registry;
-class Options;
+struct Options;
class User_map;
class Instance_map;
diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc
index 3c18d2816bf..2a363312fed 100644
--- a/server-tools/instance-manager/log.cc
+++ b/server-tools/instance-manager/log.cc
@@ -17,7 +17,7 @@
#include <my_global.h>
#include "log.h"
-
+#include "port.h"
#include <stdarg.h>
#include <m_string.h>
#include <my_sys.h>
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
index a4c81739b17..5f2d9d0b493 100644
--- a/server-tools/instance-manager/manager.cc
+++ b/server-tools/instance-manager/manager.cc
@@ -30,7 +30,9 @@
#include <m_string.h>
#include <signal.h>
#include <thr_alarm.h>
+#ifndef __WIN__
#include <sys/wait.h>
+#endif
static int create_pid_file(const char *pid_file_name)
@@ -50,6 +52,61 @@ static int create_pid_file(const char *pid_file_name)
return 0;
}
+#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)
+{
+// MSG msg;
+ while (!have_signal)
+ {
+ Sleep(100);
+ }
+ return 0;
+}
+
+#endif
+
/*
manager - entry point to the main instance manager process: start
@@ -98,21 +155,8 @@ void manager(const Options &options)
if (create_pid_file(options.pid_file_name))
return;
- /* block signals */
sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGPIPE);
- sigaddset(&mask, SIGHUP);
- /*
- 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);
+ set_signals(&mask);
/* create the listener */
{
@@ -166,12 +210,7 @@ void manager(const Options &options)
bool shutdown_complete;
shutdown_complete= FALSE;
- /*
- 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);
+
/* init list of guarded instances */
guardian_thread.lock();
@@ -185,8 +224,6 @@ void manager(const Options &options)
*/
pthread_cond_signal(&guardian_thread.COND_guardian);
- signal(SIGPIPE, SIG_IGN);
-
while (!shutdown_complete)
{
int status= 0;
@@ -197,11 +234,11 @@ void manager(const Options &options)
goto err;
}
- switch (signo) {
- case THR_SERVER_ALARM:
- process_alarm(signo);
- break;
- default:
+#ifndef __WIN__
+ if (THR_SERVER_ALARM == signo)
+ process_alarm(signo);
+ else
+#endif
{
if (!guardian_thread.is_stopped())
{
@@ -215,16 +252,16 @@ void manager(const Options &options)
shutdown_complete= TRUE;
}
}
- break;
}
- }
err:
/* delete the pid file */
my_delete(options.pid_file_name, MYF(0));
+#ifndef __WIN__
/* free alarm structures */
end_thr_alarm(1);
/* don't pthread_exit to kill all threads who did not shut down in time */
+#endif
}
diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h
index d73f4b35f18..12ed6b3b1ff 100644
--- a/server-tools/instance-manager/manager.h
+++ b/server-tools/instance-manager/manager.h
@@ -16,7 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-class Options;
+struct Options;
void manager(const Options &options);
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index 5a6c398614b..1533580de31 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -23,12 +23,16 @@
#include <my_sys.h>
#include <string.h>
#include <signal.h>
+#ifndef __WIN__
#include <pwd.h>
#include <grp.h>
#include <sys/wait.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
-
+#ifdef __WIN__
+#include "windowsservice.h"
+#endif
/*
Few notes about Instance Manager architecture:
@@ -55,10 +59,14 @@
*/
static void init_environment(char *progname);
+#ifndef __WIN__
static void daemonize(const char *log_file_name);
static void angel(const Options &options);
static struct passwd *check_user(const char *user);
static int set_user(const char *user, struct passwd *user_info);
+#else
+int HandleServiceOptions(Options options);
+#endif
/*
@@ -78,6 +86,7 @@ int main(int argc, char *argv[])
if (options.load(argc, argv))
goto err;
+#ifndef __WIN__
if ((user_info= check_user(options.user)))
{
if (set_user(options.user, user_info))
@@ -94,6 +103,12 @@ int main(int argc, char *argv[])
/* forks again, and returns only in child: parent becomes angel */
angel(options);
}
+#else
+#ifdef NDEBUG
+ return HandleServiceOptions(options);
+#endif
+#endif
+
manager(options);
options.cleanup();
my_end(0);
@@ -105,11 +120,11 @@ err:
/******************* Auxilary 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)
{
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
struct passwd *user_info;
uid_t user_id= geteuid();
@@ -150,7 +165,6 @@ static struct passwd *check_user(const char *user)
err:
log_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n", user);
-#endif
return NULL;
}
@@ -172,7 +186,7 @@ static int set_user(const char *user, struct passwd *user_info)
}
return 0;
}
-
+#endif
/*
@@ -188,6 +202,7 @@ static void init_environment(char *progname)
}
+#ifndef __WIN__
/*
Become a UNIX service
SYNOPSYS
@@ -342,3 +357,4 @@ spawn:
}
}
+#endif
diff --git a/server-tools/instance-manager/mysqlmanager.vcproj b/server-tools/instance-manager/mysqlmanager.vcproj
new file mode 100755
index 00000000000..5263deae6a9
--- /dev/null
+++ b/server-tools/instance-manager/mysqlmanager.vcproj
@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="mysqlmanager"
+ ProjectGUID="{6D524B3E-210A-4FCD-8D41-FEC0D21E83AC}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\include"
+ PreprocessorDefinitions="MYSQL_INSTANCE_MANAGER;MYSQL_SERVER;_DEBUG;SAFEMALLOC;SAFE_MUTEX;_WINDOWS;CONSOLE"
+ MinimalRebuild="TRUE"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wsock32.lib"
+ OutputFile="$(OutDir)/mysqlmanager.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/mysqlmanager.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\include"
+ PreprocessorDefinitions="MYSQL_INSTANCE_MANAGER;MYSQL_SERVER;_WINDOWS;CONSOLE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wsock32.lib"
+ OutputFile="$(OutDir)/mysqlmanager.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath=".\buffer.cc">
+ </File>
+ <File
+ RelativePath="..\sql\client.c">
+ </File>
+ <File
+ RelativePath=".\command.cc">
+ </File>
+ <File
+ RelativePath=".\commands.cc">
+ </File>
+ <File
+ RelativePath=".\factory.cc">
+ </File>
+ <File
+ RelativePath="..\libmysql\get_password.c">
+ </File>
+ <File
+ RelativePath=".\guardian.cc">
+ </File>
+ <File
+ RelativePath=".\IMService.cpp">
+ </File>
+ <File
+ RelativePath=".\instance.cc">
+ </File>
+ <File
+ RelativePath=".\instance_map.cc">
+ </File>
+ <File
+ RelativePath=".\instance_options.cc">
+ </File>
+ <File
+ RelativePath=".\listener.cc">
+ </File>
+ <File
+ RelativePath=".\log.cc">
+ </File>
+ <File
+ RelativePath=".\manager.cc">
+ </File>
+ <File
+ RelativePath=".\messages.cc">
+ </File>
+ <File
+ RelativePath="..\sql\mini_client_errors.c">
+ </File>
+ <File
+ RelativePath=".\mysql_connection.cc">
+ </File>
+ <File
+ RelativePath=".\mysqlmanager.cc">
+ </File>
+ <File
+ RelativePath="..\sql\net_serv.cpp">
+ </File>
+ <File
+ RelativePath=".\options.cc">
+ </File>
+ <File
+ RelativePath="..\sql\pack.c">
+ </File>
+ <File
+ RelativePath=".\parse.cc">
+ </File>
+ <File
+ RelativePath=".\parse_output.cc">
+ </File>
+ <File
+ RelativePath="..\sql\password.c">
+ </File>
+ <File
+ RelativePath=".\priv.cc">
+ </File>
+ <File
+ RelativePath=".\protocol.cc">
+ </File>
+ <File
+ RelativePath=".\service_funcs.cpp">
+ </File>
+ <File
+ RelativePath="..\sql\sql_state.c">
+ </File>
+ <File
+ RelativePath=".\thread_registry.cc">
+ </File>
+ <File
+ RelativePath=".\user_map.cc">
+ </File>
+ <File
+ RelativePath=".\WindowsService.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath=".\buffer.h">
+ </File>
+ <File
+ RelativePath=".\command.h">
+ </File>
+ <File
+ RelativePath=".\commands.h">
+ </File>
+ <File
+ RelativePath=".\factory.h">
+ </File>
+ <File
+ RelativePath=".\guardian.h">
+ </File>
+ <File
+ RelativePath=".\IMService.h">
+ </File>
+ <File
+ RelativePath=".\instance.h">
+ </File>
+ <File
+ RelativePath=".\instance_map.h">
+ </File>
+ <File
+ RelativePath=".\instance_options.h">
+ </File>
+ <File
+ RelativePath=".\listener.h">
+ </File>
+ <File
+ RelativePath=".\log.h">
+ </File>
+ <File
+ RelativePath=".\manager.h">
+ </File>
+ <File
+ RelativePath=".\messages.h">
+ </File>
+ <File
+ RelativePath=".\mysql_connection.h">
+ </File>
+ <File
+ RelativePath=".\mysql_manager_error.h">
+ </File>
+ <File
+ RelativePath=".\options.h">
+ </File>
+ <File
+ RelativePath=".\parse.h">
+ </File>
+ <File
+ RelativePath=".\parse_output.h">
+ </File>
+ <File
+ RelativePath=".\port.h">
+ </File>
+ <File
+ RelativePath=".\priv.h">
+ </File>
+ <File
+ RelativePath=".\protocol.h">
+ </File>
+ <File
+ RelativePath=".\thread_registry.h">
+ </File>
+ <File
+ RelativePath=".\user_map.h">
+ </File>
+ <File
+ RelativePath=".\WindowsService.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
index e44e4c6ff34..f563fa783d2 100644
--- a/server-tools/instance-manager/options.cc
+++ b/server-tools/instance-manager/options.cc
@@ -21,7 +21,7 @@
#include "options.h"
#include "priv.h"
-
+#include "port.h"
#include <my_sys.h>
#include <my_getopt.h>
#include <m_string.h>
@@ -30,19 +30,29 @@
#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
+const char *default_password_file_name = QUOTE(DEFAULT_PASSWORD_FILE_NAME);
+const char *default_log_file_name = QUOTE(DEFAULT_LOG_FILE_NAME);
+char default_config_file[FN_REFLEN] = "/etc/my.cnf";
+
+#ifndef __WIN__
char Options::run_as_service;
-const char *Options::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
+const char *Options::user= 0; /* No default value */
+#else
+char Options::install_as_service;
+char Options::remove_service;
+#endif
+const char *Options::log_file_name= default_log_file_name;
const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
-const char *Options::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
+const char *Options::password_file_name= default_password_file_name;
const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
const char *Options::first_option= 0; /* No default value */
const char *Options::bind_address= 0; /* No default value */
-const char *Options::user= 0; /* No default value */
uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
uint Options::port_number= DEFAULT_PORT;
/* just to declare */
char **Options::saved_argv;
+const char *Options::config_file = NULL;
/*
List of options, accepted by the instance manager.
@@ -55,8 +65,13 @@ enum options {
OPT_SOCKET,
OPT_PASSWORD_FILE,
OPT_MYSQLD_PATH,
+#ifndef __WIN__
OPT_RUN_AS_SERVICE,
OPT_USER,
+#else
+ OPT_INSTALL_SERVICE,
+ OPT_REMOVE_SERVICE,
+#endif
OPT_MONITORING_INTERVAL,
OPT_PORT,
OPT_BIND_ADDRESS
@@ -107,7 +122,14 @@ static struct my_option my_long_options[] =
(gptr *) &Options::monitoring_interval,
0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
0, 0, 0, 0, 0 },
-
+#ifdef __WIN__
+ { "install", OPT_INSTALL_SERVICE, "Install as system service.",
+ (gptr *) &Options::install_as_service, (gptr*) &Options::install_as_service,
+ 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
+ { "remove", OPT_REMOVE_SERVICE, "Remove system service.",
+ (gptr *)&Options::remove_service, (gptr*) &Options::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.", (gptr *) &Options::run_as_service,
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
@@ -116,7 +138,7 @@ static struct my_option my_long_options[] =
(gptr *) &Options::user,
(gptr *) &Options::user,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
-
+#endif
{ "version", 'V', "Output version information and exit.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
@@ -214,20 +236,44 @@ C_MODE_END
int Options::load(int argc, char **argv)
{
int rc;
+ char** argv_ptr = argv;
+
+#ifdef __WIN__
+ setup_windows_defaults(*argv);
+#endif
+ config_file=NULL;
if (argc >= 2)
{
+ if (is_prefix(argv[1], "--defaults-file="))
+ config_file=argv[1];
if (is_prefix(argv[1],"--defaults-file=") ||
is_prefix(argv[1],"--defaults-extra-file="))
Options::first_option= argv[1];
}
+ // we were not given a config file on the command line so we
+ // set have to construct a new argv array
+ if (config_file == NULL)
+ {
+#ifdef __WIN__
+ ::GetModuleFileName(NULL, default_config_file, sizeof(default_config_file));
+ char *filename = strstr(default_config_file, "mysqlmanager.exe");
+ strcpy(filename, "my.ini");
+#endif
+ config_file = default_config_file;
+ }
+
/* config-file options are prepended to command-line ones */
- load_defaults("my", default_groups, &argc, &argv);
- Options::saved_argv= argv;
+ load_defaults(config_file, default_groups, &argc, &argv);
+
+ rc= handle_options(&argc, &argv, my_long_options, get_one_option);
- if ((rc= handle_options(&argc, &argv, my_long_options, get_one_option)) != 0)
+ if (rc != 0)
return rc;
+
+ Options::saved_argv= argv;
+
return 0;
}
@@ -235,4 +281,31 @@ void Options::cleanup()
{
/* free_defaults returns nothing */
free_defaults(Options::saved_argv);
+
+#ifdef __WIN__
+ free((char*)default_password_file_name);
+#endif
+}
+
+#ifdef __WIN__
+
+char* change_extension(const char *src, const char *newext)
+{
+ char *dot = (char*)strrchr(src, '.');
+ if (!dot) return (char*)src;
+
+ int newlen = dot-src+strlen(newext)+1;
+ char *temp = (char*)malloc(newlen);
+ bzero(temp, newlen);
+ strncpy(temp, src, dot-src+1);
+ strcat(temp, newext);
+ return temp;
}
+
+void Options::setup_windows_defaults(const char *progname)
+{
+ Options::password_file_name = default_password_file_name = change_extension(progname, "passwd");
+ Options::log_file_name = default_log_file_name = change_extension(progname, "log");
+}
+
+#endif
diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h
index 3df259864be..3ef054b6339 100644
--- a/server-tools/instance-manager/options.h
+++ b/server-tools/instance-manager/options.h
@@ -28,23 +28,32 @@
struct Options
{
+#ifdef __WIN__
+ static char install_as_service;
+ static char remove_service;
+#else
static char run_as_service; /* handle_options doesn't support bool */
+ static const char *user;
+#endif
static const char *log_file_name;
static const char *pid_file_name;
static const char *socket_file_name;
static const char *password_file_name;
static const char *default_mysqld_path;
- static const char *user;
/* the option which should be passed to process_default_option_files */
static const char *first_option;
static uint monitoring_interval;
static uint port_number;
static const char *bind_address;
+ static const char *config_file;
static char **saved_argv;
- static int load(int argc, char **argv);
+ int load(int argc, char **argv);
void cleanup();
+#ifdef __WIN__
+ void setup_windows_defaults(const char *progname);
+#endif
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
index e83a75c6778..4b3a8b75ca1 100644
--- a/server-tools/instance-manager/parse_output.cc
+++ b/server-tools/instance-manager/parse_output.cc
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <my_sys.h>
#include <m_string.h>
+#include "port.h"
/*
diff --git a/server-tools/instance-manager/port.h b/server-tools/instance-manager/port.h
new file mode 100755
index 00000000000..3b1c3e2ad93
--- /dev/null
+++ b/server-tools/instance-manager/port.h
@@ -0,0 +1,25 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PORT_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_PORT_H
+
+#ifdef __WIN__
+
+#define vsnprintf _vsnprintf
+
+#define SIGKILL 9
+#define SHUT_RDWR 0x2
+
+//TODO: fix this
+#define DEFAULT_MONITORING_INTERVAL 20
+#define DEFAULT_PORT 2273
+#define PROTOCOL_VERSION 10
+
+typedef int pid_t;
+
+#undef popen
+#define popen(A,B) _popen(A,B)
+
+#endif /* __WIN__ */
+
+#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORT_H */
+
+
diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc
index dd192370aaf..496992aa43b 100644
--- a/server-tools/instance-manager/priv.cc
+++ b/server-tools/instance-manager/priv.cc
@@ -14,7 +14,9 @@
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 "priv.h"
+#include "port.h"
/* the pid of the manager process (of the signal thread on the LinuxThreads) */
pid_t manager_pid;
diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h
index decc3605dff..0f4c9be9a11 100644
--- a/server-tools/instance-manager/priv.h
+++ b/server-tools/instance-manager/priv.h
@@ -17,17 +17,23 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <sys/types.h>
+#ifdef __WIN__
+#include "port.h"
+#else
#include <unistd.h>
+#endif
/* the pid of the manager process (of the signal thread on the LinuxThreads) */
extern pid_t manager_pid;
+#ifndef __WIN__
/*
This flag is set if mysqlmanager has detected that it is running on the
system using LinuxThreads
*/
extern bool linuxthreads;
+#endif
extern const char mysqlmanager_version[];
extern const int mysqlmanager_version_length;
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
index 16821df4146..0d47664a89a 100644
--- a/server-tools/instance-manager/thread_registry.cc
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -27,6 +27,7 @@
#include <thr_alarm.h>
+#ifndef __WIN__
/* Kick-off signal handler */
enum { THREAD_KICK_OFF_SIGNAL= SIGUSR2 };
@@ -34,7 +35,7 @@ enum { THREAD_KICK_OFF_SIGNAL= SIGUSR2 };
static void handle_signal(int __attribute__((unused)) sig_no)
{
}
-
+#endif
/*
TODO: think about moving signal information (now it's shutdown_in_progress)
@@ -76,12 +77,13 @@ Thread_registry::~Thread_registry()
void Thread_registry::register_thread(Thread_info *info)
{
+#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);
@@ -156,6 +158,7 @@ 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);
/*
@@ -163,6 +166,8 @@ void Thread_registry::deliver_shutdown()
stopped alarm processing.
*/
process_alarm(THR_SERVER_ALARM);
+#endif
+
for (info= head.next; info != &head; info= info->next)
{
pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index 7cb2cd67d7f..a80cb7767d1 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -36,7 +36,8 @@ struct User
int User::init(const char *line)
{
- const char *name_begin, *name_end, *password;
+ const char *name_begin, *name_end;
+ char *password;
if (line[0] == '\'' || line[0] == '"')
{
@@ -44,7 +45,7 @@ int User::init(const char *line)
name_end= strchr(name_begin, line[0]);
if (name_end == 0 || name_end[1] != ':')
goto err;
- password= name_end + 2;
+ password= (char*)(name_end + 2);
}
else
{
@@ -52,13 +53,18 @@ int User::init(const char *line)
name_end= strchr(name_begin, ':');
if (name_end == 0)
goto err;
- password= name_end + 1;
+ password= (char*)(name_end + 1);
}
user_length= name_end - name_begin;
if (user_length > USERNAME_LENGTH)
goto err;
/* assume that newline characater is present */
+ if (password[strlen(password)-2] == '\r')
+ {
+ password[strlen(password)-2] = '\n';
+ password[strlen(password)-1] = 0;
+ }
if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + 1)
goto err;