summaryrefslogtreecommitdiffstats
path: root/plugin/feedback/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/feedback/utils.cc')
-rw-r--r--plugin/feedback/utils.cc442
1 files changed, 442 insertions, 0 deletions
diff --git a/plugin/feedback/utils.cc b/plugin/feedback/utils.cc
new file mode 100644
index 00000000..c31422cc
--- /dev/null
+++ b/plugin/feedback/utils.cc
@@ -0,0 +1,442 @@
+/* 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_COLLATION_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