Commit 875b0e63 authored by unknown's avatar unknown

initial import of Windows port of IM.


server-tools/instance-manager/commands.cc:
  type cleanups for compiling on Windows
  now using Options::config_file for the location of the single 
  my.cnf file we are using
server-tools/instance-manager/guardian.cc:
  pthread_mutex_lock and unlock do not return a value on Windows
  so we return 0 in all cases
server-tools/instance-manager/instance.cc:
  big changes here.
  Had to implement Windows versions of launch_and_wait and kill()
server-tools/instance-manager/instance.h:
  added some function defs
server-tools/instance-manager/instance_map.cc:
  pthread_mutex_lock and unlock do not return a value on Windows
  Also, now using only the file named as Options::config_file
server-tools/instance-manager/instance_options.h:
  added reference to port.h
server-tools/instance-manager/listener.cc:
  reworked and simplified the socket handling code.
  Added windows versions of the code that sets the sockets to be
  non-blocking and non-inheritable
server-tools/instance-manager/listener.h:
  change Options to always be a struct.  Really surprised GCC was 
  letting this go.  Options was declared to be struct in some places
  and class in other places.
server-tools/instance-manager/log.cc:
  added reference to port.h
server-tools/instance-manager/manager.cc:
  moved all the signal code inside some #ifndef __WIN__ blocks
server-tools/instance-manager/manager.h:
  change Options to always be a struct.  Really surprised GCC was 
  letting this go.  Options was declared to be struct in some places
  and class in other places.
server-tools/instance-manager/mysqlmanager.cc:
  added in the Windows service code.
server-tools/instance-manager/options.cc:
  Added in the windows options for running as a service and the code
  for loading settings only from a single file
server-tools/instance-manager/options.h:
  added definitions for the new Windows service vars and routines
server-tools/instance-manager/parse_output.cc:
  added reference to port.h
server-tools/instance-manager/priv.cc:
  added reference to port.h
server-tools/instance-manager/priv.h:
  linuxthreads should not be visible on Windows
server-tools/instance-manager/thread_registry.cc:
  more __WIN__ blocking
server-tools/instance-manager/user_map.cc:
  fixed passwd file code to handle files with \r\n line endings
server-tools/instance-manager/IMService.cpp:
  New BitKeeper file ``server-tools/instance-manager/IMService.cpp''
server-tools/instance-manager/IMService.h:
  New BitKeeper file ``server-tools/instance-manager/IMService.h''
server-tools/instance-manager/WindowsService.cpp:
  New BitKeeper file ``server-tools/instance-manager/WindowsService.cpp''
server-tools/instance-manager/WindowsService.h:
  New BitKeeper file ``server-tools/instance-manager/WindowsService.h''
server-tools/instance-manager/mysqlmanager.vcproj:
  New BitKeeper file ``server-tools/instance-manager/mysqlmanager.vcproj''
server-tools/instance-manager/port.h:
  New BitKeeper file ``server-tools/instance-manager/port.h''
parent 6ae06030
#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;
}
#pragma once
#include "windowsservice.h"
class IMService : public WindowsService
{
public:
IMService(void);
~IMService(void);
protected:
void Log(const char *msg);
void Stop();
void Run();
};
#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);
}
#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);
};
......@@ -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;
......
......@@ -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
}
......@@ -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)
{
......
......@@ -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 */
......@@ -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;
......
......@@ -19,6 +19,7 @@
#include <my_global.h>
#include <my_sys.h>
#include "parse.h"
#include "port.h"
#ifdef __GNUC__
#pragma interface
......
......@@ -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
/*
......
......@@ -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;
......
......@@ -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>
......
......@@ -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
}
......@@ -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);
......
......@@ -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
<?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>
......@@ -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
......@@ -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
......@@ -21,6 +21,7 @@
#include <stdio.h>
#include <my_sys.h>
#include <m_string.h>
#include "port.h"
/*
......
#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 */
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment