Commit 01027326 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

Revert "MDEV-26713 Windows - improve utf8 support for command line tools"

This reverts commit several commits pushed by mistake.
parent 220dc1fd
......@@ -88,7 +88,9 @@ extern "C" {
#endif /* defined(HAVE_CURSES_H) && defined(HAVE_TERM_H) */
#undef bcmp // Fix problem with new readline
#if !defined(_WIN32)
#if defined(_WIN32)
#include <conio.h>
#else
# ifdef __APPLE__
# include <editline/readline.h>
# else
......@@ -102,101 +104,6 @@ extern "C" {
#endif
}
#if defined(_WIN32)
/*
Set console mode for the whole duration of the client session.
We need for input
- line input (i.e read lines from console)
- echo typed characters
- "cooked" mode, i.e we do not want to handle all keystrokes,
like DEL etc ourselves, yet. We might want handle keystrokes
in the future, to implement tab completion, and better
(multiline) history.
Disable VT escapes for the output.We do not know what kind of escapes SELECT would return.
*/
struct Console_mode
{
HANDLE in= GetStdHandle(STD_INPUT_HANDLE);
HANDLE out= GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode_in=0;
DWORD mode_out=0;
enum {STDIN_CHANGED = 1, STDOUT_CHANGED = 2};
int changes=0;
Console_mode()
{
if (in && in != INVALID_HANDLE_VALUE && GetConsoleMode(in, &mode_in))
{
SetConsoleMode(in, ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT);
changes |= STDIN_CHANGED;
}
if (out && out != INVALID_HANDLE_VALUE && GetConsoleMode(out, &mode_out))
{
#ifdef ENABLE_VIRTUAL_TERMINAL_INPUT
SetConsoleMode(out, mode_out & ~ENABLE_VIRTUAL_TERMINAL_INPUT);
changes |= STDOUT_CHANGED;
#endif
}
}
~Console_mode()
{
if (changes & STDIN_CHANGED)
SetConsoleMode(in, mode_in);
if(changes & STDOUT_CHANGED)
SetConsoleMode(out, mode_out);
}
};
static Console_mode my_conmode;
#define MAX_CGETS_LINE_LEN 65535
/** Read line from console in ANSI codepage, chomp EOL*/
static char *win_readline()
{
static wchar_t wstrbuf[MAX_CGETS_LINE_LEN];
static char strbuf[MAX_CGETS_LINE_LEN*2];
DWORD nchars= 0;
SetLastError(0);
if (!ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), wstrbuf, MAX_CGETS_LINE_LEN-1,
&nchars, NULL))
goto err;
if (nchars == 0 && GetLastError() == ERROR_OPERATION_ABORTED)
goto err;
while (nchars > 0)
{
if (wstrbuf[nchars - 1] != '\n' && wstrbuf[nchars - 1] != '\r')
break;
wstrbuf[--nchars]= 0;
}
wstrbuf[nchars]= 0;
if (nchars > 0)
{
int len = WideCharToMultiByte(GetConsoleCP(), 0, wstrbuf, nchars + 1,
strbuf, sizeof(strbuf),NULL, NULL);
if (len < 1)
strbuf[0]= 0;
}
else
{
strbuf[0]= 0;
}
return strbuf;
err:
return NULL;
}
#endif
#ifdef HAVE_VIDATTR
static int have_curses= 0;
static void my_vidattr(chtype attrs)
......@@ -1812,10 +1719,8 @@ static void usage(int version)
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
readline, rl_library_version);
#else
printf("%s Ver %s Distrib %s, for %s (%s), source revision %s"
IF_WIN(", codepage %u",) "\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,SOURCE_REVISION,
IF_WIN(GetConsoleCP(),));
printf("%s Ver %s Distrib %s, for %s (%s), source revision %s\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,SOURCE_REVISION);
#endif
if (version)
......@@ -2210,7 +2115,26 @@ static int read_and_execute(bool interactive)
#if defined(_WIN32)
tee_fputs(prompt, stdout);
line= win_readline();
if (!tmpbuf.is_alloced())
tmpbuf.alloc(65535);
tmpbuf.length(0);
buffer.length(0);
size_t clen;
do
{
line= my_cgets((char*)tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen);
buffer.append(line, clen);
/*
if we got buffer fully filled than there is a chance that
something else is still in console input buffer
*/
} while (tmpbuf.alloced_length() <= clen);
/*
An empty line is returned from my_cgets when there's error reading :
Ctrl-c for example
*/
if (line)
line= buffer.c_ptr();
#else
if (opt_outfile)
fputs(prompt, OUTFILE);
......
......@@ -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 , or winsvc.h macros min/max
ADD_DEFINITIONS(-DNOMINMAX -DNOSERVICE)
# We do not want the windows.h macros min/max
ADD_DEFINITIONS(-DNOMINMAX)
# Speed up build process excluding unused header files
ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN)
......
......@@ -19,9 +19,4 @@
</application>
</compatibility>
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</asmv1:assembly>
......@@ -29,14 +29,6 @@
#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
......
--source include/windows.inc
--exec set MARIADB_DISABLE_UTF8_CONSOLE=1 && chcp 1257 > NUL && $MYSQL --default-character-set=auto -e "select @@character_set_client"
--exec chcp 1257 > NUL && $MYSQL --default-character-set=auto -e "select @@character_set_client"
--source include/windows.inc
--exec $MYSQL --default-character-set=auto -e "select @@character_set_client"
# UTF8 parameters to mysql client do not work on Windows
--source include/not_windows.inc
--source include/not_embedded.inc
#
......
......@@ -87,23 +87,6 @@ sub skip_combinations {
$skip{'main/ssl_verify_ip.test'} = 'x509v3 support required'
unless $openssl_ver ge "1.0.2";
sub utf8_command_line_ok() {
if (IS_WINDOWS) {
# Can use UTF8 on command line since Windows 10 1903 (10.0.18362)
my($os_name, $os_major, $os_minor, $os_build, $os_id) = Win32::GetOSVersion();
if($os_major lt 10){
return 0;
} elsif($os_major gt 10 or $os_minor gt 0 or $os_build ge 18362) {
return 1;
}
return 0;
}
return 1;
}
$skip{'main/charset_client_win_utf8mb4.test'} =
$skip{'main/grant_utf8_cli.test'} = 'No utf8 command line support'
unless utf8_command_line_ok();
%skip;
}
......
......@@ -1393,7 +1393,7 @@ static const MY_CSET_OS_NAME charsets[] =
#ifdef UNCOMMENT_THIS_WHEN_WL_WL_4024_IS_DONE
{"cp54936", "gb18030", my_cs_exact},
#endif
{"cp65001", "utf8mb4", my_cs_exact},
{"cp65001", "utf8", my_cs_exact},
#else /* not Windows */
......
......@@ -62,40 +62,34 @@
char *get_tty_password(const char *opt_message)
{
wchar_t wbuf[80];
char to[80*3]; /* there is at most 3 bytes per wchar, in any codepage */
wchar_t *pos=wbuf,*end=wbuf + array_elements(wbuf)-1;
char to[80];
char *pos=to,*end=to+sizeof(to)-1;
DBUG_ENTER("get_tty_password");
_cputs(opt_message ? opt_message : "Enter password: ");
for (;;)
{
int wc;
wc=_getwch();
if (wc == '\b' || wc == 127)
char tmp;
tmp=_getch();
if (tmp == '\b' || (int) tmp == 127)
{
if (pos != wbuf)
if (pos != to)
{
_cputs("\b \b");
pos--;
continue;
_cputs("\b \b");
pos--;
continue;
}
}
if (wc == '\n' || wc == '\r' || wc == 3 || pos == end)
if (tmp == '\n' || tmp == '\r' || tmp == 3)
break;
if (iswcntrl(wc))
if (iscntrl(tmp) || pos == end)
continue;
/* Do not print '*' for half-unicode char(high surrogate)*/
if (wc < 0xD800 || wc > 0xDBFF)
{
_cputs("*");
}
*(pos++)= (wchar_t)wc;
_cputs("*");
*(pos++) = tmp;
}
while (pos != to && isspace(pos[-1]) == ' ')
pos--; /* Allow dummy space at end */
*pos=0;
_cputs("\n");
if (!WideCharToMultiByte(GetConsoleCP(), 0 , wbuf , -1 , to, sizeof(to), NULL, NULL))
to[0]=0;
DBUG_RETURN(my_strdup(PSI_INSTRUMENT_ME, to,MYF(MY_FAE)));
}
......
......@@ -38,7 +38,7 @@ static double getopt_double(char *arg, const struct my_option *optp, int *err);
static void init_variables(const struct my_option *, init_func_p);
static void init_one_value(const struct my_option *, void *, longlong);
static void fini_one_value(const struct my_option *, void *, longlong);
static int setval(const struct my_option *, void *, char *, my_bool, const char *);
static int setval(const struct my_option *, void *, char *, my_bool);
static char *check_struct_option(char *cur_arg, char *key_name);
/*
......@@ -133,48 +133,6 @@ double getopt_ulonglong2double(ulonglong v)
return u.dbl;
}
#ifdef _WIN32
/**
On Windows, if program is running in UTF8 mode, but some arguments are not UTF8.
This will mostly likely be a sign of old "ANSI" my.ini, and it is likely that
something will go wrong, e.g file access error.
*/
static void validate_value(const char *key, const char *value,
const char *filename)
{
MY_STRCOPY_STATUS status;
const struct charset_info_st *cs= &my_charset_utf8mb4_bin;
size_t len;
if (GetACP() != CP_UTF8)
return;
len= strlen(value);
if (!len)
return;
cs->cset->well_formed_char_length(cs, value, value + len, len, &status);
if (!status.m_well_formed_error_pos)
return;
if (filename && *filename)
{
my_getopt_error_reporter(WARNING_LEVEL,
"%s: invalid (non-UTF8) characters found for option '%s'"
" in file '%s'",
my_progname, key, filename);
}
else
{
DBUG_ASSERT(0);
my_getopt_error_reporter(
WARNING_LEVEL, "%s: invalid (non-UTF8) characters for option %s",
my_progname, key);
}
}
#else
#define validate_value(key, value, filename) (void)filename
#endif
/**
Handle command line options.
Sort options.
......@@ -606,7 +564,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts,
}
}
if ((error= setval(optp, optp->value, argument,
set_maximum_value,filename)))
set_maximum_value)))
DBUG_RETURN(error);
if (get_one_option(optp, argument, filename))
DBUG_RETURN(EXIT_UNSPECIFIED_ERROR);
......@@ -652,7 +610,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts,
continue;
}
if ((!option_is_autoset) &&
((error= setval(optp, value, argument, set_maximum_value,filename))) &&
((error= setval(optp, value, argument, set_maximum_value))) &&
!option_is_loose)
DBUG_RETURN(error);
if (get_one_option(optp, argument, filename))
......@@ -753,7 +711,7 @@ static my_bool get_bool_argument(const struct my_option *opts,
*/
static int setval(const struct my_option *opts, void *value, char *argument,
my_bool set_maximum_value, const char *option_file)
my_bool set_maximum_value)
{
int err= 0, res= 0;
DBUG_ENTER("setval");
......@@ -900,7 +858,6 @@ static int setval(const struct my_option *opts, void *value, char *argument,
goto ret;
};
}
validate_value(opts->name, argument, option_file);
DBUG_RETURN(0);
ret:
......
......@@ -67,38 +67,6 @@ static ulong atoi_octal(const char *str)
MYSQL_FILE *mysql_stdin= NULL;
static MYSQL_FILE instrumented_stdin;
#ifdef _WIN32
UINT orig_console_cp, orig_console_output_cp;
static void reset_console_cp(void)
{
SetConsoleCP(orig_console_cp);
SetConsoleOutputCP(orig_console_output_cp);
}
/*
The below fixes discrepancies in console output and
command line parameter encoding. command line is in
ANSI codepage, output to console by default is in OEM, but
we like them to be in the same encoding.
We do this only if current codepage is UTF8, i.e when we
know we're on Windows that can handle UTF8 well.
*/
static void set_console_cp()
{
UINT acp= GetACP();
if (acp == CP_UTF8 && !getenv("MARIADB_DISABLE_UTF8_CONSOLE"))
{
orig_console_cp= GetConsoleCP();
SetConsoleCP(acp);
orig_console_output_cp= GetConsoleOutputCP();
SetConsoleOutputCP(acp);
atexit(reset_console_cp);
}
}
#endif
/**
Initialize my_sys functions, resources and variables
......@@ -163,7 +131,6 @@ my_bool my_init(void)
#ifdef _WIN32
if (win32_init_tcp_ip())
DBUG_RETURN(1);
set_console_cp();
#endif
#ifdef CHECK_UNLIKELY
init_my_likely();
......
......@@ -481,11 +481,10 @@ IF(WIN32)
MYSQL_ADD_EXECUTABLE(mariadb-install-db
mysql_install_db.cc
${CMAKE_CURRENT_BINARY_DIR}/mysql_bootstrap_sql.c
password.c
COMPONENT Server
)
SET_TARGET_PROPERTIES(mariadb-install-db PROPERTIES COMPILE_FLAGS -DINSTALL_PLUGINDIR=${INSTALL_PLUGINDIR})
TARGET_LINK_LIBRARIES(mariadb-install-db mysys mysys_ssl shlwapi)
TARGET_LINK_LIBRARIES(mariadb-install-db mysys shlwapi)
ADD_LIBRARY(winservice STATIC winservice.c)
TARGET_LINK_LIBRARIES(winservice shell32)
......
......@@ -21,7 +21,6 @@
#include "mariadb.h"
#include <my_getopt.h>
#include <m_string.h>
#include <password.h>
#include <windows.h>
#include <shellapi.h>
......@@ -31,7 +30,6 @@
#include <sddl.h>
struct IUnknown;
#include <shlwapi.h>
#include <winservice.h>
#include <string>
......@@ -444,14 +442,16 @@ static int create_myini()
}
static constexpr const char* update_root_passwd=
static const char update_root_passwd_part1[]=
"UPDATE mysql.global_priv SET priv=json_set(priv,"
"'$.password_last_changed', UNIX_TIMESTAMP(),"
"'$.plugin','mysql_native_password',"
"'$.authentication_string','%s') where User='root';\n";
static constexpr char remove_default_user_cmd[]=
"'$.authentication_string',PASSWORD(";
static const char update_root_passwd_part2[]=
")) where User='root';\n";
static const char remove_default_user_cmd[]=
"DELETE FROM mysql.user where User='';\n";
static constexpr char allow_remote_root_access_cmd[]=
static const char allow_remote_root_access_cmd[]=
"CREATE TEMPORARY TABLE tmp_user LIKE global_priv;\n"
"INSERT INTO tmp_user SELECT * from global_priv where user='root' "
" AND host='localhost';\n"
......@@ -870,10 +870,18 @@ static int create_db_instance(const char *datadir)
/* Change root password if requested. */
if (opt_password && opt_password[0])
{
verbose("Setting root password");
char buf[2 * MY_SHA1_HASH_SIZE + 2];
my_make_scrambled_password(buf, opt_password, strlen(opt_password));
fprintf(in, update_root_passwd, buf);
verbose("Setting root password",remove_default_user_cmd);
fputs(update_root_passwd_part1, in);
/* Use hex encoding for password, to avoid escaping problems.*/
fputc('0', in);
fputc('x', in);
for(int i= 0; opt_password[i]; i++)
{
fprintf(in,"%02x",opt_password[i]);
}
fputs(update_root_passwd_part2, in);
fflush(in);
}
......
......@@ -366,6 +366,7 @@ static void get_service_config()
*/
static void change_service_config()
{
char defaults_file[MAX_PATH];
char default_character_set[64];
char buf[MAX_PATH];
char commandline[3 * MAX_PATH + 19];
......@@ -375,17 +376,13 @@ static void change_service_config()
Write datadir to my.ini, after converting backslashes to
unix style slashes.
*/
if (service_properties.datadir[0])
strcpy_s(buf, MAX_PATH, service_properties.datadir);
for(i= 0; buf[i]; i++)
{
strcpy_s(buf, MAX_PATH, service_properties.datadir);
for (i= 0; buf[i]; i++)
{
if (buf[i] == '\\')
buf[i]= '/';
}
WritePrivateProfileString("mysqld", "datadir", buf,
service_properties.inifile);
if (buf[i] == '\\')
buf[i]= '/';
}
WritePrivateProfileString("mysqld", "datadir",buf, service_properties.inifile);
/*
Remove basedir from defaults file, otherwise the service wont come up in
......@@ -400,19 +397,19 @@ static void change_service_config()
*/
default_character_set[0]= 0;
GetPrivateProfileString("mysqld", "default-character-set", NULL,
default_character_set, sizeof(default_character_set), service_properties.inifile);
default_character_set, sizeof(default_character_set), defaults_file);
if (default_character_set[0])
{
WritePrivateProfileString("mysqld", "default-character-set", NULL,
service_properties.inifile);
defaults_file);
WritePrivateProfileString("mysqld", "character-set-server",
default_character_set, service_properties.inifile);
default_character_set, defaults_file);
}
sprintf(defaults_file_param,"--defaults-file=%s", service_properties.inifile);
sprintf_s(commandline, "\"%s\" \"%s\" \"%s\"", mysqld_path,
defaults_file_param, opt_service);
if (!my_ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
if (!ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
SERVICE_NO_CHANGE, commandline, NULL, NULL, NULL, NULL, NULL, NULL))
{
die("ChangeServiceConfig failed with %u", GetLastError());
......@@ -486,8 +483,13 @@ int main(int argc, char **argv)
}
}
old_mysqld_exe_exists= (GetFileAttributes(service_properties.mysqld_exe) !=
INVALID_FILE_ATTRIBUTES);
old_mysqld_exe_exists = (GetFileAttributes(service_properties.mysqld_exe) != INVALID_FILE_ATTRIBUTES);
log("Phase %d/%d: Fixing server config file%s", ++phase, max_phases, my_ini_exists ? "" : "(skipped)");
snprintf(my_ini_bck, sizeof(my_ini_bck), "%s.BCK", service_properties.inifile);
CopyFile(service_properties.inifile, my_ini_bck, FALSE);
upgrade_config_file(service_properties.inifile);
bool do_start_stop_server = old_mysqld_exe_exists && initial_service_state != SERVICE_RUNNING;
log("Phase %d/%d: Start and stop server in the old version, to avoid crash recovery %s", ++phase, max_phases,
......@@ -542,14 +544,6 @@ int main(int argc, char **argv)
start_duration_ms += 500;
}
}
log("Phase %d/%d: Fixing server config file%s", ++phase, max_phases,
my_ini_exists ? "" : "(skipped)");
snprintf(my_ini_bck, sizeof(my_ini_bck), "%s.BCK",
service_properties.inifile);
CopyFile(service_properties.inifile, my_ini_bck, FALSE);
upgrade_config_file(service_properties.inifile);
/*
Start mysqld.exe as non-service skipping privileges (so we do not
care about the password). But disable networking and enable pipe
......
......@@ -127,7 +127,6 @@
#ifdef _WIN32
#include <handle_connections_win.h>
#include <sddl.h>
#include <winservice.h> /* SERVICE_STOPPED, SERVICE_RUNNING etc */
#endif
#include <my_service_manager.h>
......
......@@ -158,196 +158,51 @@ static int cmp_strings(const void* a, const void *b)
return strcmp((const char *)a, *(const char **)b);
}
static bool is_utf8_str(const char *s)
/**
Convert file from a previous version, by removing
*/
int upgrade_config_file(const char *myini_path)
{
const unsigned char *bytes= (const unsigned char *) s;
int num;
while (*bytes)
#define MY_INI_SECTION_SIZE 32*1024 +3
static char section_data[MY_INI_SECTION_SIZE];
for (const char *section_name : { "mysqld","server","mariadb" })
{
if ((*bytes & 0x80) == 0x00)
num= 1;
else if ((*bytes & 0xE0) == 0xC0)
num= 2;
else if ((*bytes & 0xF0) == 0xE0)
num= 3;
else if ((*bytes & 0xF8) == 0xF0)
num= 4;
else
return false;
bytes++;
for (int i= 1; i < num; i++)
DWORD size = GetPrivateProfileSection(section_name, section_data, MY_INI_SECTION_SIZE, myini_path);
if (size == MY_INI_SECTION_SIZE - 2)
{
if ((*bytes & 0xC0) != 0x80)
return false;
bytes++;
return -1;
}
}
return true;
}
static UINT get_system_acp()
{
static DWORD system_acp;
if (system_acp)
return system_acp;
char str_cp[10];
int cch= GetLocaleInfo(GetSystemDefaultLCID(), LOCALE_IDEFAULTANSICODEPAGE,
str_cp, sizeof(str_cp));
system_acp= cch > 0 ? atoi(str_cp) : 1252;
return system_acp;
}
#define MY_INI_SECTION_SIZE 32 * 1024 + 3
static char *ansi_to_utf8(const char *s)
{
#define MAX_STR_LEN MY_INI_SECTION_SIZE
static wchar_t utf16_buf[MAX_STR_LEN];
static char utf8_buf[MAX_STR_LEN];
if (MultiByteToWideChar(get_system_acp(), 0, s, -1, utf16_buf, MAX_STR_LEN))
{
if (WideCharToMultiByte(CP_UTF8, 0, utf16_buf, -1, utf8_buf, MAX_STR_LEN,
0, 0))
return utf8_buf;
}
return 0;
}
int fix_section(const char *myini_path, const char *section_name,
bool is_server)
{
if (!is_server && GetACP() != CP_UTF8)
return 0;
static char section_data[MY_INI_SECTION_SIZE];
DWORD size= GetPrivateProfileSection(section_name, section_data,
MY_INI_SECTION_SIZE, myini_path);
if (size == MY_INI_SECTION_SIZE - 2)
{
return -1;
}
for (char *keyval= section_data; *keyval; keyval += strlen(keyval)+1)
{
char varname[256];
char *value;
char *key_end= strchr(keyval, '=');
if (!key_end)
key_end= keyval + strlen(keyval);
if (key_end - keyval > sizeof(varname))
continue;
value= key_end + 1;
if (GetACP() == CP_UTF8 && !is_utf8_str(value))
for (char *keyval = section_data; *keyval; keyval += strlen(keyval) + 1)
{
char *new_val= ansi_to_utf8(value);
if (new_val)
char varname[256];
char *key_end = strchr(keyval, '=');
if (!key_end)
key_end = keyval+ strlen(keyval);
if (key_end - keyval > sizeof(varname))
continue;
// copy and normalize (convert dash to underscore) to variable names
for (char *p = keyval, *q = varname;; p++,q++)
{
*key_end= 0;
fprintf(stdout, "Fixing variable '%s' charset, value=%s\n", keyval,
new_val);
WritePrivateProfileString(section_name, keyval, new_val, myini_path);
*key_end= '=';
if (p == key_end)
{
*q = 0;
break;
}
*q = (*p == '-') ? '_' : *p;
}
}
if (!is_server)
continue;
const char *v = (const char *)bsearch(varname, removed_variables, sizeof(removed_variables) / sizeof(removed_variables[0]),
sizeof(char *), cmp_strings);
// Check if variable should be removed from config.
// First, copy and normalize (convert dash to underscore) to variable
// names
for (char *p= keyval, *q= varname;; p++, q++)
{
if (p == key_end)
if (v)
{
*q= 0;
break;
fprintf(stdout, "Removing variable '%s' from config file\n", varname);
// delete variable
*key_end = 0;
WritePrivateProfileString(section_name, keyval, 0, myini_path);
}
*q= (*p == '-') ? '_' : *p;
}
const char *v= (const char *) bsearch(varname, removed_variables, sizeof(removed_variables) / sizeof(removed_variables[0]),
sizeof(char *), cmp_strings);
if (v)
{
fprintf(stdout, "Removing variable '%s' from config file\n", varname);
// delete variable
*key_end= 0;
WritePrivateProfileString(section_name, keyval, 0, myini_path);
}
}
return 0;
}
static bool is_mariadb_section(const char *name, bool *is_server)
{
if (strncmp(name, "mysql", 5)
&& strncmp(name, "mariadb", 7)
&& strcmp(name, "client")
&& strcmp(name, "client-server")
&& strcmp(name, "server"))
{
return false;
}
for (const char *section_name : {"mysqld", "server", "mariadb"})
if (*is_server= !strcmp(section_name, name))
break;
return *is_server;
}
/**
Convert file from a previous version, by removing obsolete variables
Also, fix values to be UTF8, if MariaDB is running in utf8 mode
*/
int upgrade_config_file(const char *myini_path)
{
static char all_sections[MY_INI_SECTION_SIZE];
int sz= GetPrivateProfileSectionNamesA(all_sections, MY_INI_SECTION_SIZE,
myini_path);
if (!sz)
return 0;
if (sz > MY_INI_SECTION_SIZE - 2)
{
fprintf(stderr, "Too many sections in config file\n");
return -1;
}
for (char *section= all_sections; *section; section+= strlen(section) + 1)
{
bool is_server_section;
if (is_mariadb_section(section, &is_server_section))
fix_section(myini_path, section, is_server_section);
}
return 0;
}
#ifdef MAIN
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage : %s <config_file>\n", argv[0]);
return 1;
}
int rc= upgrade_config_file(argv[1]);
if (rc)
{
fprintf(stderr, "upgrade_config_file(\"%s\") returned an error\n",
argv[1]);
return 1;
}
return 0;
}
#endif
......@@ -55,7 +55,6 @@
#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;
......
......@@ -134,20 +134,6 @@ static void get_datadir_from_ini(const char *ini, char *service_name, char *data
}
static int fix_and_check_datadir(mysqld_service_properties *props)
{
normalize_path(props->datadir, MAX_PATH);
/* Check if datadir really exists */
if (GetFileAttributes(props->datadir) != INVALID_FILE_ATTRIBUTES)
return 0;
/*
It is possible, that datadir contains some unconvertable character.
We just pretend not to know what's the data directory
*/
props->datadir[0]= 0;
return 0;
}
/*
Retrieve some properties from windows mysqld service binary path.
We're interested in ini file location and datadir, and also in version of
......@@ -197,7 +183,7 @@ int get_mysql_service_properties(const wchar_t *bin_path,
}
/* Last parameter is the service name*/
WideCharToMultiByte(CP_ACP, 0, args[numargs - 1], -1, service_name, MAX_PATH, NULL, NULL);
wcstombs(service_name, args[numargs-1], MAX_PATH);
if(have_inifile && wcsncmp(args[1], L"--defaults-file=", 16) != 0)
goto end;
......@@ -216,7 +202,7 @@ int get_mysql_service_properties(const wchar_t *bin_path,
goto end;
}
WideCharToMultiByte(CP_ACP, 0, mysqld_path, -1, props->mysqld_exe, MAX_PATH, NULL, NULL);
wcstombs(props->mysqld_exe, mysqld_path, MAX_PATH);
/* If mysqld.exe exists, try to get its version from executable */
if (GetFileAttributes(props->mysqld_exe) != INVALID_FILE_ATTRIBUTES)
{
......@@ -227,8 +213,7 @@ int get_mysql_service_properties(const wchar_t *bin_path,
if (have_inifile)
{
/* We have --defaults-file in service definition. */
WideCharToMultiByte(CP_ACP, 0, args[1] + 16, -1, props->inifile,
MAX_PATH, NULL, NULL);
wcstombs(props->inifile, args[1]+16, MAX_PATH);
normalize_path(props->inifile, MAX_PATH);
if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES)
{
......@@ -299,9 +284,16 @@ int get_mysql_service_properties(const wchar_t *bin_path,
}
}
if (props->datadir[0] == 0 || fix_and_check_datadir(props))
if (props->datadir[0])
{
normalize_path(props->datadir, MAX_PATH);
/* Check if datadir really exists */
if (GetFileAttributes(props->datadir) == INVALID_FILE_ATTRIBUTES)
goto end;
}
else
{
/* There is no datadir in ini file, or non-existing dir, bail out.*/
/* There is no datadir in ini file, bail out.*/
goto end;
}
......
/*
Copyright (c) 2011, 2021 Monty Program Ab
Copyright (c) 2011, 2012, Monty Program Ab
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -21,9 +21,7 @@
extern "C" {
#endif
#include <windows.h>
#pragma warning(suppress : 4995)
#include <winsvc.h>
#include <windows.h>
typedef struct mysqld_service_properties_st
{
char mysqld_exe[MAX_PATH];
......@@ -34,171 +32,9 @@ 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)
#include <malloc.h>
/*
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)
*/
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(CP_ACP, 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;
SC_HANDLE sch;
AWSTRDUP(w_ServiceName, lpServiceName);
sch= OpenServiceW(hSCManager, w_servicename, dwDesiredAccess);
if (!sch)
{
ok= FALSE;
last_error= GetLastError();
}
end:
free(w_ServiceName);
if (!ret)
SetLastError(last_error);
return ret;
}
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_Depedencies= NULL;
wchar_t *w_ServiceStartName= NULL;
wchar_t *w_Password= NULL;
SC_HANDLE sch;
DWORD last_error;
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_Depedencies, 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_Depedencies);
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_Depedencies= NULL;
wchar_t *w_ServiceStartName= NULL;
wchar_t *w_Password= NULL;
SC_HANDLE sch;
DWORD last_error;
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_Depedencies, w_ServiceStartName,
w_Password, w_DisplayName);
if (!ok)
{
last_error= GetLastError();
}
end:
free(w_DisplayName);
free(w_BinaryPathName);
free(w_LoadOrderGroup);
free(w_Depedencies);
free(w_ServiceStartName);
free(w_Password);
if (last_error)
SetLastError(last_error);
return ret;
}
#undef AWSTRDUP
#undef OpenService
#define OpenService my_OpenService
#undef ChangeServiceConfig
#define ChangeServiceConfig my_ChangeServiceConfig
#undef CreateService
#define CreateService my_CreateService
#endif
#ifdef __cplusplus
}
#endif
......@@ -461,7 +461,7 @@
Section="mysqld"
Name="my.ini"
Key="character-set-server"
Value="utf8mb4" />
Value="utf8" />
</Component>
<!-- Shortcuts in program menu (mysql client etc) -->
......
......@@ -5,7 +5,6 @@ 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)
......
......@@ -141,24 +141,24 @@ void CUpgradeDlg::PopulateServicesList()
ErrorExit("OpenSCManager failed");
}
static BYTE buf[2*64*1024];
static BYTE buf[64*1024];
static BYTE configBuffer[8*1024];
DWORD bufsize= sizeof(buf);
DWORD bufneed;
DWORD num_services;
BOOL ok= EnumServicesStatusExW(scm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
BOOL ok= EnumServicesStatusEx(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_PROCESSW info =
(LPENUM_SERVICE_STATUS_PROCESSW)buf;
LPENUM_SERVICE_STATUS_PROCESS info =
(LPENUM_SERVICE_STATUS_PROCESS)buf;
int index=-1;
for (ULONG i=0; i < num_services; i++)
{
SC_HANDLE service= OpenServiceW(scm, info[i].lpServiceName,
SC_HANDLE service= OpenService(scm, info[i].lpServiceName,
SERVICE_QUERY_CONFIG);
if (!service)
continue;
......@@ -187,11 +187,7 @@ void CUpgradeDlg::PopulateServicesList()
ServiceProperties props;
props.myini= service_props.inifile;
props.datadir= service_props.datadir;
char service_name_buf[1024];
WideCharToMultiByte(CP_ACP, 0, info[i].lpServiceName, -1,
service_name_buf, sizeof(service_name_buf),
0, 0);
props.servicename= service_name_buf;
props.servicename = info[i].lpServiceName;
if (service_props.version_major)
{
char ver[64];
......@@ -202,7 +198,7 @@ void CUpgradeDlg::PopulateServicesList()
else
props.version= "<unknown>";
index = m_Services.AddString(service_name_buf);
index = m_Services.AddString(info[i].lpServiceName);
services.resize(index+1);
services[index] = props;
}
......
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