mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			415 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			415 lines
		
	
	
	
		
			11 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;
 | |
| };
 | |
| } // namespace feedback
 | 
