summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2021-11-19 14:03:51 +0100
committerSergei Golubchik <serg@mariadb.org>2021-12-15 19:13:57 +0100
commitea0a5cb0a4efbca1fc35885599e07baf10dc3e9e (patch)
tree8282d58bf98178b764b6f6f09c594670a4091e5a
parent99e5ae3b1a68ad1029f06aa3d2a5078d78cf19e5 (diff)
downloadmariadb-git-ea0a5cb0a4efbca1fc35885599e07baf10dc3e9e.tar.gz
MDEV-27092 Windows - services that have non-ASCII characters do not work with activeCodePage=UTF8
CreateServiceA, OpenServiceA, and couple of other functions do not work correctly with non-ASCII character, in the special case where application has defined activeCodePage=UTF8. Workaround by redefining affected ANSI functions to own wrapper, which works by converting narrow(ANSI) to wide, then calling wide function. Deprecate original ANSI service functions, via declspec, so that we can catch their use.
-rw-r--r--cmake/os/Windows.cmake4
-rw-r--r--include/my_global.h8
-rw-r--r--sql/mysql_install_db.cc3
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/winmain.cc1
-rw-r--r--sql/winservice.h177
-rw-r--r--win/upgrade_wizard/CMakeLists.txt1
-rw-r--r--win/upgrade_wizard/upgradeDlg.cpp18
8 files changed, 201 insertions, 12 deletions
diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake
index d9a0dfba46a..da75c73d585 100644
--- a/cmake/os/Windows.cmake
+++ b/cmake/os/Windows.cmake
@@ -60,8 +60,8 @@ ENDIF()
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00)
-# We do not want the windows.h macros min/max
-ADD_DEFINITIONS(-DNOMINMAX)
+# We do not want the windows.h , or winsvc.h macros min/max
+ADD_DEFINITIONS(-DNOMINMAX -DNOSERVICE)
# Speed up build process excluding unused header files
ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN)
diff --git a/include/my_global.h b/include/my_global.h
index 224909116dd..ed213e69f85 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -29,6 +29,14 @@
#pragma GCC poison __WIN__
#endif
+#if defined(_MSC_VER)
+/*
+ Following functions have bugs, when used with UTF-8 active codepage.
+ #include <winservice.h> will use the non-buggy wrappers
+*/
+#pragma deprecated("CreateServiceA", "OpenServiceA", "ChangeServiceConfigA")
+#endif
+
/*
InnoDB depends on some MySQL internals which other plugins should not
need. This is because of InnoDB's foreign key support, "safe" binlog
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index f712e29b843..026ac3e668e 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -30,6 +30,7 @@
#include <sddl.h>
struct IUnknown;
#include <shlwapi.h>
+#include <winservice.h>
#include <string>
@@ -916,7 +917,7 @@ end:
auto sc_manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (sc_manager)
{
- auto sc_handle= OpenServiceA(sc_manager,opt_service, DELETE);
+ auto sc_handle= OpenService(sc_manager,opt_service, DELETE);
if (sc_handle)
{
DeleteService(sc_handle);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 808e590435a..46c28c862f6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -127,6 +127,7 @@
#ifdef _WIN32
#include <handle_connections_win.h>
#include <sddl.h>
+#include <winservice.h> /* SERVICE_STOPPED, SERVICE_RUNNING etc */
#endif
#include <my_service_manager.h>
diff --git a/sql/winmain.cc b/sql/winmain.cc
index f999767cb27..bdad409065d 100644
--- a/sql/winmain.cc
+++ b/sql/winmain.cc
@@ -55,6 +55,7 @@
#include <windows.h>
#include <string>
#include <cassert>
+#include <winservice.h>
static SERVICE_STATUS svc_status{SERVICE_WIN32_OWN_PROCESS};
static SERVICE_STATUS_HANDLE svc_status_handle;
diff --git a/sql/winservice.h b/sql/winservice.h
index f9ab3eda332..a14ee73d146 100644
--- a/sql/winservice.h
+++ b/sql/winservice.h
@@ -17,11 +17,22 @@
/*
Extract properties of a windows service binary path
*/
+#pragma once
+
#ifdef __cplusplus
extern "C" {
#endif
-#include <windows.h>
+#include <windows.h>
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4995)
+#endif
+#include <winsvc.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
typedef struct mysqld_service_properties_st
{
char mysqld_exe[MAX_PATH];
@@ -32,9 +43,171 @@ typedef struct mysqld_service_properties_st
int version_patch;
} mysqld_service_properties;
-extern int get_mysql_service_properties(const wchar_t *bin_path,
+extern int get_mysql_service_properties(const wchar_t *bin_path,
mysqld_service_properties *props);
+
+#if !defined(UNICODE)
+/*
+ The following wrappers workaround Windows bugs
+ with CreateService/OpenService with ANSI codepage UTF8.
+
+ Apparently, these function in ANSI mode, for this codepage only
+ do *not* behave as expected (as-if string parameters were
+ converted to UTF16 and "wide" function were called)
+*/
+#include <malloc.h>
+static inline wchar_t* awstrdup(const char *str)
+{
+ if (!str)
+ return NULL;
+ size_t len= strlen(str) + 1;
+ wchar_t *wstr= (wchar_t *) malloc(sizeof(wchar_t)*len);
+ if (MultiByteToWideChar(GetACP(), 0, str, (int)len, wstr, (int)len) == 0)
+ {
+ free(wstr);
+ return NULL;
+ }
+ return wstr;
+}
+
+#define AWSTRDUP(dest, src) \
+ dest= awstrdup(src); \
+ if (src && !dest) \
+ { \
+ ok= FALSE; \
+ last_error = ERROR_OUTOFMEMORY; \
+ goto end; \
+ }
+
+static inline SC_HANDLE my_OpenService(SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAccess)
+{
+ wchar_t *w_ServiceName= NULL;
+ BOOL ok=TRUE;
+ DWORD last_error=0;
+ SC_HANDLE sch=NULL;
+
+ AWSTRDUP(w_ServiceName, lpServiceName);
+ sch= OpenServiceW(hSCManager, w_ServiceName, dwDesiredAccess);
+ if (!sch)
+ {
+ ok= FALSE;
+ last_error= GetLastError();
+ }
+
+end:
+ free(w_ServiceName);
+ if (!ok)
+ SetLastError(last_error);
+ return sch;
+}
+
+static inline SC_HANDLE my_CreateService(SC_HANDLE hSCManager,
+ LPCSTR lpServiceName, LPCSTR lpDisplayName,
+ DWORD dwDesiredAccess, DWORD dwServiceType,
+ DWORD dwStartType, DWORD dwErrorControl,
+ LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup,
+ LPDWORD lpdwTagId, LPCSTR lpDependencies,
+ LPCSTR lpServiceStartName, LPCSTR lpPassword)
+{
+ wchar_t *w_ServiceName= NULL;
+ wchar_t *w_DisplayName= NULL;
+ wchar_t *w_BinaryPathName= NULL;
+ wchar_t *w_LoadOrderGroup= NULL;
+ wchar_t *w_Dependencies= NULL;
+ wchar_t *w_ServiceStartName= NULL;
+ wchar_t *w_Password= NULL;
+ SC_HANDLE sch = NULL;
+ DWORD last_error=0;
+ BOOL ok= TRUE;
+
+ AWSTRDUP(w_ServiceName,lpServiceName);
+ AWSTRDUP(w_DisplayName,lpDisplayName);
+ AWSTRDUP(w_BinaryPathName, lpBinaryPathName);
+ AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup);
+ AWSTRDUP(w_Dependencies, lpDependencies);
+ AWSTRDUP(w_ServiceStartName, lpServiceStartName);
+ AWSTRDUP(w_Password, lpPassword);
+
+ sch= CreateServiceW(
+ hSCManager, w_ServiceName, w_DisplayName, dwDesiredAccess, dwServiceType,
+ dwStartType, dwErrorControl, w_BinaryPathName, w_LoadOrderGroup,
+ lpdwTagId, w_Dependencies, w_ServiceStartName, w_Password);
+ if(!sch)
+ {
+ ok= FALSE;
+ last_error= GetLastError();
+ }
+
+end:
+ free(w_ServiceName);
+ free(w_DisplayName);
+ free(w_BinaryPathName);
+ free(w_LoadOrderGroup);
+ free(w_Dependencies);
+ free(w_ServiceStartName);
+ free(w_Password);
+
+ if (!ok)
+ SetLastError(last_error);
+ return sch;
+}
+
+static inline BOOL my_ChangeServiceConfig(SC_HANDLE hService, DWORD dwServiceType,
+ DWORD dwStartType, DWORD dwErrorControl,
+ LPCSTR lpBinaryPathName, LPCSTR lpLoadOrderGroup,
+ LPDWORD lpdwTagId, LPCSTR lpDependencies,
+ LPCSTR lpServiceStartName, LPCSTR lpPassword,
+ LPCSTR lpDisplayName)
+{
+ wchar_t *w_DisplayName= NULL;
+ wchar_t *w_BinaryPathName= NULL;
+ wchar_t *w_LoadOrderGroup= NULL;
+ wchar_t *w_Dependencies= NULL;
+ wchar_t *w_ServiceStartName= NULL;
+ wchar_t *w_Password= NULL;
+ SC_HANDLE sch = NULL;
+ DWORD last_error=0;
+ BOOL ok= TRUE;
+
+ AWSTRDUP(w_DisplayName, lpDisplayName);
+ AWSTRDUP(w_BinaryPathName, lpBinaryPathName);
+ AWSTRDUP(w_LoadOrderGroup, lpLoadOrderGroup);
+ AWSTRDUP(w_Dependencies, lpDependencies);
+ AWSTRDUP(w_ServiceStartName, lpServiceStartName);
+ AWSTRDUP(w_Password, lpPassword);
+
+ ok= ChangeServiceConfigW(
+ hService, dwServiceType, dwStartType, dwErrorControl, w_BinaryPathName,
+ w_LoadOrderGroup, lpdwTagId, w_Dependencies, w_ServiceStartName,
+ w_Password, w_DisplayName);
+ if (!ok)
+ {
+ last_error= GetLastError();
+ }
+
+end:
+ free(w_DisplayName);
+ free(w_BinaryPathName);
+ free(w_LoadOrderGroup);
+ free(w_Dependencies);
+ free(w_ServiceStartName);
+ free(w_Password);
+
+ if (last_error)
+ SetLastError(last_error);
+ return ok;
+}
+#undef AWSTRDUP
+
+#undef OpenService
+#define OpenService my_OpenService
+#undef ChangeServiceConfig
+#define ChangeServiceConfig my_ChangeServiceConfig
+#undef CreateService
+#define CreateService my_CreateService
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/win/upgrade_wizard/CMakeLists.txt b/win/upgrade_wizard/CMakeLists.txt
index 20a06a41215..fd3560e1ee6 100644
--- a/win/upgrade_wizard/CMakeLists.txt
+++ b/win/upgrade_wizard/CMakeLists.txt
@@ -5,6 +5,7 @@ ENDIF()
# We need MFC
# /permissive- flag does not play well with MFC, disable it.
STRING(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+REMOVE_DEFINITIONS(-DNOSERVICE) # fixes "already defined" warning in an AFX header
FIND_PACKAGE(MFC)
IF(NOT MFC_FOUND)
diff --git a/win/upgrade_wizard/upgradeDlg.cpp b/win/upgrade_wizard/upgradeDlg.cpp
index 80f7c18f757..7aae4890b51 100644
--- a/win/upgrade_wizard/upgradeDlg.cpp
+++ b/win/upgrade_wizard/upgradeDlg.cpp
@@ -141,24 +141,24 @@ void CUpgradeDlg::PopulateServicesList()
ErrorExit("OpenSCManager failed");
}
- static BYTE buf[64*1024];
+ static BYTE buf[2*64*1024];
static BYTE configBuffer[8*1024];
DWORD bufsize= sizeof(buf);
DWORD bufneed;
DWORD num_services;
- BOOL ok= EnumServicesStatusEx(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
+ BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_STATE_ALL, buf, bufsize, &bufneed, &num_services, NULL, NULL);
if(!ok)
ErrorExit("EnumServicesStatusEx failed");
- LPENUM_SERVICE_STATUS_PROCESS info =
- (LPENUM_SERVICE_STATUS_PROCESS)buf;
+ LPENUM_SERVICE_STATUS_PROCESSW info =
+ (LPENUM_SERVICE_STATUS_PROCESSW)buf;
int index=-1;
for (ULONG i=0; i < num_services; i++)
{
- SC_HANDLE service= OpenService(scm, info[i].lpServiceName,
+ SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName,
SERVICE_QUERY_CONFIG);
if (!service)
continue;
@@ -187,7 +187,11 @@ void CUpgradeDlg::PopulateServicesList()
ServiceProperties props;
props.myini= service_props.inifile;
props.datadir= service_props.datadir;
- props.servicename = info[i].lpServiceName;
+ char service_name_buf[1024];
+ WideCharToMultiByte(GetACP(), 0, info[i].lpServiceName, -1,
+ service_name_buf, sizeof(service_name_buf),
+ 0, 0);
+ props.servicename= service_name_buf;
if (service_props.version_major)
{
char ver[64];
@@ -198,7 +202,7 @@ void CUpgradeDlg::PopulateServicesList()
else
props.version= "<unknown>";
- index = m_Services.AddString(info[i].lpServiceName);
+ index = m_Services.AddString(service_name_buf);
services.resize(index+1);
services[index] = props;
}