From 1b28a0883dc02946384843af281e968913b4ed1e Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 30 Jan 2011 22:42:02 +0100 Subject: split long lines, use get_mysql_service_properties() --- sql/winservice.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 sql/winservice.c (limited to 'sql/winservice.c') diff --git a/sql/winservice.c b/sql/winservice.c new file mode 100644 index 00000000000..17d678e4f1a --- /dev/null +++ b/sql/winservice.c @@ -0,0 +1,167 @@ +/* + Get Properties of an existing mysqld Windows service +*/ + +#include +#include +#include "winservice.h" +#include +#include +#include + + +/* + Get version from an executable file +*/ +void get_file_version(const char *path, int *major, int *minor, int *patch) +{ + DWORD version_handle; + char *ver= 0; + VS_FIXEDFILEINFO info; + UINT len; + DWORD size; + void *p; + *major= *minor= *patch= 0; + + size= GetFileVersionInfoSize(path, &version_handle); + if (size == 0) + return; + ver= (char *)malloc(size); + if(!GetFileVersionInfo(path, version_handle, size, ver)) + goto end; + + if(!VerQueryValue(ver,"\\",&p,&len)) + goto end; + memcpy(&info,p ,sizeof(VS_FIXEDFILEINFO)); + + *major= (info.dwFileVersionMS & 0xFFFF0000) >> 16; + *minor= (info.dwFileVersionMS & 0x0000FFFF); + *patch= (info.dwFileVersionLS & 0xFFFF0000) >> 16; +end: + free(ver); +} + +void normalize_path(char *path, size_t size) +{ + char buf[MAX_PATH]; + if (*path== '"') + { + char *p; + strcpy_s(buf, MAX_PATH, path+1); + p= strchr(buf, '"'); + if (p) + *p=0; + } + else + strcpy_s(buf, MAX_PATH, path); + GetFullPathName(buf, MAX_PATH, buf, NULL); + strcpy_s(path, size, buf); +} + +/* + Retrieve some properties from windows mysqld service binary path. + We're interested in ini file location and datadir, and also in version of + the data. We tolerate missing mysqld.exe. + + Note that this function carefully avoids using mysql libraries (e.g dbug), + since it is used in unusual environments (windows installer, MFC), where we + do not have much control over how threads are created and destroyed, so we + cannot assume MySQL thread initilization here. +*/ +int get_mysql_service_properties(const wchar_t *bin_path, + mysqld_service_properties *props) +{ + int numargs; + wchar_t mysqld_path[MAX_PATH + 4]; + wchar_t *file_part; + wchar_t **args= NULL; + int retval= 1; + + props->datadir[0]= 0; + props->inifile[0]= 0; + props->mysqld_exe[0]= 0; + props->version_major= 0; + props->version_minor= 0; + props->version_patch= 0; + + args= CommandLineToArgvW(bin_path, &numargs); + + if(numargs != 3) + goto end; + + if(wcsncmp(args[1], L"--defaults-file=", 16) != 0) + goto end; + + GetFullPathNameW(args[0], MAX_PATH, mysqld_path, &file_part); + + if(wcsstr(mysqld_path, L".exe") == NULL) + wcscat(mysqld_path, L".exe"); + + if(wcsicmp(file_part, L"mysqld.exe") != 0 && + wcsicmp(file_part, L"mysqld.exe") != 0 && + wcsicmp(file_part, L"mysqld-nt.exe") != 0) + { + /* The service executable is not mysqld. */ + goto end; + } + + wcstombs(props->mysqld_exe, args[0], MAX_PATH); + wcstombs(props->inifile, args[1]+16, MAX_PATH); + normalize_path(props->inifile, MAX_PATH); + + if (GetFileAttributes(props->inifile) == INVALID_FILE_ATTRIBUTES) + goto end; + + /* If mysqld.exe exists, try to get its version from executable */ + if (GetFileAttributes(props->mysqld_exe) != INVALID_FILE_ATTRIBUTES) + { + get_file_version(props->mysqld_exe, &props->version_major, + &props->version_minor, &props->version_patch); + } + + GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, + props->inifile); + + 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, bail out.*/ + goto end; + } + + /* + If version could not be determined so far, try mysql_upgrade_info in + database directory. + */ + if(props->version_major == 0) + { + char buf[MAX_PATH]; + FILE *mysql_upgrade_info; + + sprintf_s(buf, MAX_PATH, "%s\\mysql_upgrade_info", props->datadir); + mysql_upgrade_info= fopen(buf, "r"); + if(mysql_upgrade_info) + { + if (fgets(buf, MAX_PATH, mysql_upgrade_info)) + { + int major,minor,patch; + if (sscanf(buf, "%d.%d.%d", &major, &minor, &patch) == 3) + { + props->version_major= major; + props->version_minor= minor; + props->version_patch= patch; + } + } + } + } + retval = 0; +end: + LocalFree((HLOCAL)args); + return retval; +} \ No newline at end of file -- cgit v1.2.1 From 3cb88652ddc711954e9f18ad2799c57997c9fd1a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 3 Feb 2011 17:51:03 +0100 Subject: MWL#55: correct mysqld.exe file path, to extract version from it. Take into account that services registered by MySQL do not have .exe extension in service binary path. --- sql/winservice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/winservice.c') diff --git a/sql/winservice.c b/sql/winservice.c index 17d678e4f1a..0c238d4d33d 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -105,7 +105,7 @@ int get_mysql_service_properties(const wchar_t *bin_path, goto end; } - wcstombs(props->mysqld_exe, args[0], MAX_PATH); + wcstombs(props->mysqld_exe, mysqld_path, MAX_PATH); wcstombs(props->inifile, args[1]+16, MAX_PATH); normalize_path(props->inifile, MAX_PATH); -- cgit v1.2.1 From 614a6dfcd4320600762a9bf39587c4df08a3d9af Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 4 Feb 2011 12:20:41 +0100 Subject: MWL#55: Handle cases where service was installed with mysqld --install without any parameters. In such case, service name is always MYSQL, as service binary path is "path\to\mysqld.exe" "MySQL". Guess data directory it is either from my.ini (which is assumed to be in the installation root), or just data directory under install root. --- sql/winservice.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 12 deletions(-) (limited to 'sql/winservice.c') diff --git a/sql/winservice.c b/sql/winservice.c index 0c238d4d33d..ee29d3556d8 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -76,6 +76,7 @@ int get_mysql_service_properties(const wchar_t *bin_path, wchar_t *file_part; wchar_t **args= NULL; int retval= 1; + BOOL have_inifile; props->datadir[0]= 0; props->inifile[0]= 0; @@ -85,11 +86,28 @@ int get_mysql_service_properties(const wchar_t *bin_path, props->version_patch= 0; args= CommandLineToArgvW(bin_path, &numargs); - - if(numargs != 3) + if(numargs == 2) + { + /* + There are rare cases where service config does not have + --defaults-filein the binary parth . There services were registered with + plain mysqld --install, the data directory is next to "bin" in this case. + Service name (second parameter) must be MySQL. + */ + if(wcscmp(args[1], L"MySQL") != 0) + goto end; + have_inifile= FALSE; + } + else if(numargs == 3) + { + have_inifile= TRUE; + } + else + { goto end; + } - if(wcsncmp(args[1], L"--defaults-file=", 16) != 0) + if(have_inifile && wcsncmp(args[1], L"--defaults-file=", 16) != 0) goto end; GetFullPathNameW(args[0], MAX_PATH, mysqld_path, &file_part); @@ -106,21 +124,66 @@ int get_mysql_service_properties(const wchar_t *bin_path, } wcstombs(props->mysqld_exe, mysqld_path, MAX_PATH); - wcstombs(props->inifile, args[1]+16, MAX_PATH); - normalize_path(props->inifile, MAX_PATH); - - if (GetFileAttributes(props->inifile) == INVALID_FILE_ATTRIBUTES) - goto end; - /* If mysqld.exe exists, try to get its version from executable */ if (GetFileAttributes(props->mysqld_exe) != INVALID_FILE_ATTRIBUTES) { - get_file_version(props->mysqld_exe, &props->version_major, + get_file_version(props->mysqld_exe, &props->version_major, &props->version_minor, &props->version_patch); } + if (have_inifile) + { + /* Easy case, we have --defaults-file in service definition. */ + wcstombs(props->inifile, args[1]+16, MAX_PATH); + normalize_path(props->inifile, MAX_PATH); + if (GetFileAttributes(props->inifile) == INVALID_FILE_ATTRIBUTES) + goto end; + GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, + props->inifile); + } + else + { + /* + Hard, although a rare case, we're guessing datadir and defaults-file. + On Windows, defaults-file is traditionally install-root\my.ini + and datadir is install-root\data + */ + char install_root[MAX_PATH]; + int i; + char *p; + + /* + Get the install root(parent of bin directory where mysqld.exe) + is located. + */ + strcpy_s(install_root, MAX_PATH, props->mysqld_exe); + for (i=0; i< 2; i++) + { + p= strrchr(install_root, '\\'); + if(!p) + goto end; + *p= 0; + } + + /* Look for my.ini in the install root */ + sprintf_s(props->inifile, MAX_PATH, "%s\\my.ini", install_root); + if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES) + { + /* Ini file found, get datadir from there */ + GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, + MAX_PATH, props->inifile); + } + else + { + /* Ini file was not found */ + props->inifile[0]= 0; + } - GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, - props->inifile); + /* Try datadir in install directory.*/ + if (props->datadir[0] == 0) + { + sprintf_s(props->datadir, MAX_PATH, "%s\\data", install_root); + } + } if (props->datadir[0]) { -- cgit v1.2.1 From 577d02b17d0a9c6df7f9b943c69c246519362d88 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 8 Feb 2011 13:07:31 +0100 Subject: MWL#55: look for my.cnf in addition to my.ini trying to figure out defaults file for the service --- sql/winservice.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql/winservice.c') diff --git a/sql/winservice.c b/sql/winservice.c index ee29d3556d8..1cbe5e906e8 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -164,8 +164,12 @@ int get_mysql_service_properties(const wchar_t *bin_path, *p= 0; } - /* Look for my.ini in the install root */ + /* Look for my.ini, my.cnf in the install root */ sprintf_s(props->inifile, MAX_PATH, "%s\\my.ini", install_root); + if (GetFileAttributes(props->inifile) == INVALID_FILE_ATTRIBUTES) + { + sprintf_s(props->inifile, MAX_PATH, "%s\\my.cnf", install_root); + } if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES) { /* Ini file found, get datadir from there */ @@ -174,7 +178,7 @@ int get_mysql_service_properties(const wchar_t *bin_path, } else { - /* Ini file was not found */ + /* No ini file */ props->inifile[0]= 0; } -- cgit v1.2.1 From 7ac23980b8009c7d446b008208f1bd6ba6ae9839 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 15 Feb 2011 13:04:55 +0100 Subject: MWL#55 : Philip's review: Take into account that mysql services start even with invalid defaults files (using data file relative to mysqld.exe location). Handle this case in upgrade scenarios, as if there was no --defaults-file in service definition. --- sql/winservice.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'sql/winservice.c') diff --git a/sql/winservice.c b/sql/winservice.c index 1cbe5e906e8..562f047fa79 100644 --- a/sql/winservice.c +++ b/sql/winservice.c @@ -130,17 +130,30 @@ int get_mysql_service_properties(const wchar_t *bin_path, get_file_version(props->mysqld_exe, &props->version_major, &props->version_minor, &props->version_patch); } + if (have_inifile) { - /* Easy case, we have --defaults-file in service definition. */ + /* We have --defaults-file in service definition. */ wcstombs(props->inifile, args[1]+16, MAX_PATH); normalize_path(props->inifile, MAX_PATH); - if (GetFileAttributes(props->inifile) == INVALID_FILE_ATTRIBUTES) - goto end; - GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, - props->inifile); + if (GetFileAttributes(props->inifile) != INVALID_FILE_ATTRIBUTES) + { + GetPrivateProfileString("mysqld", "datadir", NULL, props->datadir, MAX_PATH, + props->inifile); + } + else + { + /* + Service will start even with invalid .ini file, using lookup for + datadir relative to mysqld.exe. This is equivalent to the case no ini + file used. + */ + props->inifile[0]= 0; + have_inifile= FALSE; + } } - else + + if(!have_inifile) { /* Hard, although a rare case, we're guessing datadir and defaults-file. -- cgit v1.2.1