mirror of
https://github.com/MariaDB/server.git
synced 2025-02-22 21:33:08 +01:00

This fixed the MySQL bug# 20338 about misuse of double underscore prefix __WIN__, which was old MySQL's idea of identifying Windows Replace it by _WIN32 standard symbol for targeting Windows OS (both 32 and 64 bit) Not that connect storage engine is not fixed in this patch (must be fixed in "upstream" branch)
442 lines
12 KiB
C++
442 lines
12 KiB
C++
/* Copyright (C) 2010 Sergei Golubchik and 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
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#include "feedback.h"
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined (_WIN32)
|
|
#define HAVE_SYS_UTSNAME_H
|
|
|
|
#ifndef VER_SUITE_WH_SERVER
|
|
#define VER_SUITE_WH_SERVER 0x00008000
|
|
#endif
|
|
|
|
struct utsname {
|
|
char sysname[16]; // Name of this implementation of the operating system.
|
|
char nodename[16]; // Name of this node within the communications
|
|
// network to which this node is attached, if any.
|
|
char release[16]; // Current release level of this implementation.
|
|
char version[256]; // Current version level of this release.
|
|
char machine[16]; // Name of the hardware type on which the system is running.
|
|
};
|
|
|
|
/* Get commonly used name for Windows version */
|
|
static const char *get_os_version_name(OSVERSIONINFOEX *ver)
|
|
{
|
|
DWORD major = ver->dwMajorVersion;
|
|
DWORD minor = ver->dwMinorVersion;
|
|
if (major == 10 && minor == 0)
|
|
{
|
|
return (ver->wProductType == VER_NT_WORKSTATION) ?
|
|
"Windows 10" : "Windows Server 2016";
|
|
}
|
|
if (major == 6 && minor == 3)
|
|
{
|
|
return (ver->wProductType == VER_NT_WORKSTATION)?
|
|
"Windows 8.1":"Windows Server 2012 R2";
|
|
}
|
|
if (major == 6 && minor == 2)
|
|
{
|
|
return (ver->wProductType == VER_NT_WORKSTATION)?
|
|
"Windows 8":"Windows Server 2012";
|
|
}
|
|
if (major == 6 && minor == 1)
|
|
{
|
|
return (ver->wProductType == VER_NT_WORKSTATION)?
|
|
"Windows 7":"Windows Server 2008 R2";
|
|
}
|
|
if (major == 6 && minor == 0)
|
|
{
|
|
return (ver->wProductType == VER_NT_WORKSTATION)?
|
|
"Windows Vista":"Windows Server 2008";
|
|
}
|
|
if (major == 5 && minor == 2)
|
|
{
|
|
if (GetSystemMetrics(SM_SERVERR2) != 0)
|
|
return "Windows Server 2003 R2";
|
|
if (ver->wSuiteMask & VER_SUITE_WH_SERVER)
|
|
return "Windows Home Server";
|
|
SYSTEM_INFO sysinfo;
|
|
GetSystemInfo(&sysinfo);
|
|
if (ver->wProductType == VER_NT_WORKSTATION &&
|
|
sysinfo.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
|
|
return "Windows XP Professional x64 Edition";
|
|
|
|
return "Windows Server 2003";
|
|
}
|
|
if (major == 5 && minor == 1)
|
|
return "Windows XP";
|
|
if (major == 5 && minor == 0)
|
|
return "Windows 2000";
|
|
|
|
return "";
|
|
}
|
|
|
|
|
|
static int uname(struct utsname *buf)
|
|
{
|
|
OSVERSIONINFOEX ver;
|
|
ver.dwOSVersionInfoSize = (DWORD)sizeof(ver);
|
|
/* GetVersionEx got deprecated, we need it anyway, so disable deprecation warnings. */
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable : 4996)
|
|
#endif
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
#endif
|
|
if (!GetVersionEx((OSVERSIONINFO *)&ver))
|
|
return -1;
|
|
|
|
buf->nodename[0]= 0;
|
|
strcpy(buf->sysname, "Windows");
|
|
sprintf(buf->release, "%d.%d", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion);
|
|
|
|
const char *version_str= get_os_version_name(&ver);
|
|
if(version_str && version_str[0])
|
|
sprintf(buf->version, "%s %s",version_str, ver.szCSDVersion);
|
|
else
|
|
{
|
|
/* Fallback for unknown versions, e.g "Windows <major_ver>.<minor_ver>" */
|
|
sprintf(buf->version, "Windows %d.%d%s",
|
|
(int)ver.dwMajorVersion, (int)ver.dwMinorVersion,
|
|
(ver.wProductType == VER_NT_WORKSTATION ? "" : " Server"));
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
strcpy(buf->machine, "x64");
|
|
#else
|
|
BOOL isX64;
|
|
if (IsWow64Process(GetCurrentProcess(), &isX64) && isX64)
|
|
strcpy(buf->machine, "x64");
|
|
else
|
|
strcpy(buf->machine,"x86");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#elif defined(HAVE_SYS_UTSNAME_H)
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UTSNAME_H
|
|
static bool have_ubuf= false;
|
|
static struct utsname ubuf;
|
|
#endif
|
|
|
|
#ifdef TARGET_OS_LINUX
|
|
#include <glob.h>
|
|
static bool have_distribution= false;
|
|
static char distribution[256];
|
|
|
|
static const char *masks[]= {
|
|
"/etc/*-version", "/etc/*-release",
|
|
"/etc/*_version", "/etc/*_release"
|
|
};
|
|
#endif
|
|
|
|
bool schema_table_store_record(THD *thd, TABLE *table);
|
|
|
|
namespace feedback {
|
|
|
|
/*
|
|
convenience macros for inserting rows into I_S table.
|
|
*/
|
|
#define INSERT2(NAME,LEN,VALUE) \
|
|
do { \
|
|
table->field[0]->store(NAME, (uint) LEN, system_charset_info); \
|
|
table->field[1]->store VALUE; \
|
|
if (schema_table_store_record(thd, table)) \
|
|
return 1; \
|
|
} while (0)
|
|
|
|
#define INSERT1(NAME,VALUE) \
|
|
do { \
|
|
table->field[0]->store(NAME, (uint) sizeof(NAME)-1, system_charset_info); \
|
|
table->field[1]->store VALUE; \
|
|
if (schema_table_store_record(thd, table)) \
|
|
return 1; \
|
|
} while (0)
|
|
|
|
static const bool UNSIGNED= true; ///< used below when inserting integers
|
|
|
|
/**
|
|
callback for fill_plugins()
|
|
*/
|
|
static my_bool show_plugins(THD *thd, plugin_ref plugin, void *arg)
|
|
{
|
|
TABLE *table= (TABLE*) arg;
|
|
char name[NAME_LEN*2];
|
|
size_t name_len;
|
|
char version[20];
|
|
size_t version_len;
|
|
|
|
name_len= my_snprintf(name, sizeof(name), "%s version",
|
|
plugin_name(plugin)->str);
|
|
|
|
version_len= my_snprintf(version, sizeof(version), "%d.%d",
|
|
(plugin_decl(plugin)->version) >> 8,
|
|
(plugin_decl(plugin)->version) & 0xff);
|
|
|
|
INSERT2(name, name_len,
|
|
(version, (uint)version_len, system_charset_info));
|
|
|
|
name_len= my_snprintf(name, sizeof(name), "%s used",
|
|
plugin_name(plugin)->str);
|
|
|
|
INSERT2(name, name_len, (plugin_ref_to_int(plugin)->locks_total, UNSIGNED));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
inserts all plugins, their versions, and usage counters
|
|
*/
|
|
int fill_plugin_version(THD *thd, TABLE_LIST *tables)
|
|
{
|
|
return plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
|
|
~PLUGIN_IS_FREED, tables->table);
|
|
}
|
|
|
|
#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
|
|
#define _SC_PAGESIZE _SC_PAGE_SIZE
|
|
#endif
|
|
|
|
/**
|
|
return the amount of physical memory
|
|
*/
|
|
static ulonglong my_getphysmem()
|
|
{
|
|
#ifdef _WIN32
|
|
MEMORYSTATUSEX memstatus;
|
|
memstatus.dwLength= sizeof(memstatus);
|
|
GlobalMemoryStatusEx(&memstatus);
|
|
return memstatus.ullTotalPhys;
|
|
#else
|
|
ulonglong pages= 0;
|
|
|
|
#ifdef _SC_PHYS_PAGES
|
|
pages= sysconf(_SC_PHYS_PAGES);
|
|
#endif
|
|
|
|
#ifdef _SC_PAGESIZE
|
|
return pages * sysconf(_SC_PAGESIZE);
|
|
#else
|
|
return pages * my_getpagesize();
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/* get the number of (online) CPUs */
|
|
int my_getncpus()
|
|
{
|
|
#ifdef _SC_NPROCESSORS_ONLN
|
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
|
#elif defined(_WIN32)
|
|
SYSTEM_INFO sysinfo;
|
|
GetSystemInfo(&sysinfo);
|
|
return sysinfo.dwNumberOfProcessors;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
Find the version of the kernel and the linux distribution
|
|
*/
|
|
int prepare_linux_info()
|
|
{
|
|
#ifdef HAVE_SYS_UTSNAME_H
|
|
have_ubuf= (uname(&ubuf) != -1);
|
|
#endif
|
|
|
|
#ifdef TARGET_OS_LINUX
|
|
/*
|
|
let's try to find what linux distribution it is
|
|
we read *[-_]{release,version} file in /etc.
|
|
|
|
Either it will be /etc/lsb-release, such as
|
|
|
|
==> /etc/lsb-release <==
|
|
DISTRIB_ID=Ubuntu
|
|
DISTRIB_RELEASE=8.04
|
|
DISTRIB_CODENAME=hardy
|
|
DISTRIB_DESCRIPTION="Ubuntu 8.04.4 LTS"
|
|
|
|
Or a one-liner with the description (/etc/SuSE-release has more
|
|
than one line, but the description is the first, so it can be
|
|
treated as a one-liner).
|
|
|
|
We'll read lsb-release first, and if it's not found will search
|
|
for other files (*-version *-release *_version *_release)
|
|
*/
|
|
int fd;
|
|
have_distribution= false;
|
|
if ((fd= my_open("/etc/lsb-release", O_RDONLY, MYF(0))) != -1)
|
|
{
|
|
/* Cool, LSB-compliant distribution! */
|
|
size_t len= my_read(fd, (uchar*)distribution, sizeof(distribution)-1, MYF(0));
|
|
my_close(fd, MYF(0));
|
|
if (len != (size_t)-1)
|
|
{
|
|
distribution[len]= 0; // safety
|
|
char *found= strstr(distribution, "DISTRIB_DESCRIPTION=");
|
|
if (found)
|
|
{
|
|
have_distribution= true;
|
|
char *end= strstr(found, "\n");
|
|
if (end == NULL)
|
|
end= distribution + len;
|
|
found+= 20;
|
|
|
|
if (*found == '"' && end[-1] == '"')
|
|
{
|
|
found++;
|
|
end--;
|
|
}
|
|
*end= 0;
|
|
|
|
char *to= strmov(distribution, "lsb: ");
|
|
memmove(to, found, end - found + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if not an LSB-compliant distribution */
|
|
for (uint i= 0; !have_distribution && i < array_elements(masks); i++)
|
|
{
|
|
glob_t found;
|
|
if (glob(masks[i], GLOB_NOSORT, NULL, &found) == 0)
|
|
{
|
|
int fd;
|
|
if ((fd= my_open(found.gl_pathv[0], O_RDONLY, MYF(0))) != -1)
|
|
{
|
|
/*
|
|
+5 and -8 below cut the file name part out of the
|
|
full pathname that corresponds to the mask as above.
|
|
*/
|
|
char *to= strmov(distribution, found.gl_pathv[0] + 5) - 8;
|
|
*to++= ':';
|
|
*to++= ' ';
|
|
|
|
size_t to_len= distribution + sizeof(distribution) - 1 - to;
|
|
size_t len= my_read(fd, (uchar*)to, to_len, MYF(0));
|
|
my_close(fd, MYF(0));
|
|
if (len != (size_t)-1)
|
|
{
|
|
to[len]= 0; // safety
|
|
char *end= strstr(to, "\n");
|
|
if (end)
|
|
*end= 0;
|
|
have_distribution= true;
|
|
}
|
|
}
|
|
}
|
|
globfree(&found);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Add the linux distribution and the kernel version
|
|
*/
|
|
int fill_linux_info(THD *thd, TABLE_LIST *tables)
|
|
{
|
|
#if defined(HAVE_SYS_UTSNAME_H) || defined(TARGET_OS_LINUX)
|
|
TABLE *table= tables->table;
|
|
CHARSET_INFO *cs= system_charset_info;
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UTSNAME_H
|
|
if (have_ubuf)
|
|
{
|
|
INSERT1("Uname_sysname", (ubuf.sysname, (uint) strlen(ubuf.sysname), cs));
|
|
INSERT1("Uname_release", (ubuf.release, (uint) strlen(ubuf.release), cs));
|
|
INSERT1("Uname_version", (ubuf.version, (uint) strlen(ubuf.version), cs));
|
|
INSERT1("Uname_machine", (ubuf.machine, (uint) strlen(ubuf.machine), cs));
|
|
}
|
|
#endif
|
|
|
|
#ifdef TARGET_OS_LINUX
|
|
if (have_distribution)
|
|
INSERT1("Uname_distribution", (distribution, strlen(distribution), cs));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Adds varios bits of information to the I_S.FEEDBACK
|
|
*/
|
|
int fill_misc_data(THD *thd, TABLE_LIST *tables)
|
|
{
|
|
TABLE *table= tables->table;
|
|
|
|
INSERT1("Cpu_count", (my_getncpus(), UNSIGNED));
|
|
INSERT1("Mem_total", (my_getphysmem(), UNSIGNED));
|
|
INSERT1("Now", (thd->query_start(), UNSIGNED));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fill_collation_statistics(THD *thd, TABLE_LIST *tables)
|
|
{
|
|
TABLE *table= tables->table;
|
|
for (uint id= 1; id < MY_ALL_CHARSETS_SIZE; id++)
|
|
{
|
|
ulonglong count;
|
|
if (my_collation_is_known_id(id) &&
|
|
(count= my_collation_statistics_get_use_count(id)))
|
|
{
|
|
char name[MY_CS_NAME_SIZE + 32];
|
|
size_t namelen= my_snprintf(name, sizeof(name),
|
|
"Collation used %s",
|
|
get_charset_name(id));
|
|
INSERT2(name, namelen, (count, UNSIGNED));
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
/**
|
|
calculates the server unique identifier
|
|
|
|
UID is a base64 encoded SHA1 hash of the MAC address of one of
|
|
the interfaces, and the tcp port that the server is listening on
|
|
*/
|
|
int calculate_server_uid(char *dest)
|
|
{
|
|
uchar rawbuf[2 + 6];
|
|
uchar shabuf[MY_SHA1_HASH_SIZE];
|
|
|
|
int2store(rawbuf, mysqld_port);
|
|
if (my_gethwaddr(rawbuf + 2))
|
|
{
|
|
sql_print_error("feedback plugin: failed to retrieve the MAC address");
|
|
return 1;
|
|
}
|
|
|
|
my_sha1((uint8*) shabuf, (char*) rawbuf, sizeof(rawbuf));
|
|
|
|
assert(my_base64_needed_encoded_length(sizeof(shabuf)) <= SERVER_UID_SIZE);
|
|
my_base64_encode(shabuf, sizeof(shabuf), dest);
|
|
|
|
return 0;
|
|
}
|
|
|
|
} // namespace feedback
|