Commit 7782bca1 authored by unknown's avatar unknown

Merge rburnett@bk-internal.mysql.com:/home/bk/mysql-5.0

into  fedora.(none):/home/reggie/bk/im_patch

parents 548ff2a3 9a2ea370
#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);
};
......@@ -470,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)))
......@@ -482,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);
......@@ -605,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,
......@@ -693,7 +693,6 @@ int Set_option::correct_file(int skip)
error= modify_defaults_file(Options::config_file, option,
option_value, instance_name, skip);
switch (error)
{
case 0:
......
......@@ -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 @@ int Instance::stop()
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 @@ class Instance
*/
pthread_cond_t COND_instance_stopped;
Instance_map *instance_map;
void remove_pid();
int launch_and_wait();
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
......@@ -139,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
}
......
......@@ -19,6 +19,7 @@
#include <my_global.h>
#include <my_sys.h>
#include "parse.h"
#include "port.h"
#ifdef __GNUC__
#pragma interface
......
This diff is collapsed.
......@@ -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 @@ int main(int argc, char *argv[])
/******************* 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 @@ static void angel(const Options &options)
}
}
#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,15 +30,25 @@
#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 */
const char *Options::config_file= NULL;
#else
char Options::install_as_service;
char Options::remove_service;
const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE);
#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::config_file= QUOTE(DEFAULT_CONFIG_FILE);
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 */
......@@ -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 },
......@@ -221,7 +243,7 @@ C_MODE_END
int Options::load(int argc, char **argv)
{
saved_argv= argv;
if (argc >= 2)
{
if (is_prefix(argv[1], "--defaults-file="))
......@@ -239,6 +261,22 @@ int Options::load(int argc, char **argv)
}
}
#ifdef __WIN__
setup_windows_defaults(*argv);
/*
On Windows, there are two possibilities. Either we are given
a defaults file on the command line or we use the my.ini file
that is in our app dir
*/
if (Options::config_file == NULL)
{
::GetModuleFileName(NULL, default_config_file, sizeof(default_config_file)); char *filename= strrchr(default_config_file, "\\");
strcpy(filename, "\\my.ini");
Options::config_file= default_config_file;
}
#endif
/* config-file options are prepended to command-line ones */
load_defaults(config_file, default_groups, &argc,
&saved_argv);
......@@ -257,4 +295,32 @@ 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,13 +28,18 @@
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 uint monitoring_interval;
static uint port_number;
......@@ -44,8 +49,11 @@ struct Options
/* argv pointer returned by load_defaults() to be used by free_defaults() */
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