diff options
Diffstat (limited to 'plugin/disks')
-rw-r--r-- | plugin/disks/CMakeLists.txt | 5 | ||||
-rw-r--r-- | plugin/disks/README.txt | 86 | ||||
-rw-r--r-- | plugin/disks/information_schema_disks.cc | 164 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/disks.result | 12 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/disks.test | 2 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/disks_notembedded.result | 22 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/disks_notembedded.test | 25 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/suite.opt | 1 | ||||
-rw-r--r-- | plugin/disks/mysql-test/disks/suite.pm | 10 |
9 files changed, 327 insertions, 0 deletions
diff --git a/plugin/disks/CMakeLists.txt b/plugin/disks/CMakeLists.txt new file mode 100644 index 00000000..446c64d0 --- /dev/null +++ b/plugin/disks/CMakeLists.txt @@ -0,0 +1,5 @@ +IF("${CMAKE_SYSTEM}" MATCHES "Linux") + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql) + MYSQL_ADD_PLUGIN(DISKS information_schema_disks.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED) +ENDIF() + diff --git a/plugin/disks/README.txt b/plugin/disks/README.txt new file mode 100644 index 00000000..b49db3c0 --- /dev/null +++ b/plugin/disks/README.txt @@ -0,0 +1,86 @@ +Information Schema Disks +------------------------ +This is a proof-of-concept information schema plugin that allows the +disk space situation to be monitored. When installed, it can be used +as follows: + + > select * from information_schema.disks; + +-----------+-----------------------+-----------+----------+-----------+ + | Disk | Path | Total | Used | Available | + +-----------+-----------------------+-----------+----------+-----------+ + | /dev/sda3 | / | 47929956 | 30666304 | 14805864 | + | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 | + | /dev/sda4 | /home | 174679768 | 80335392 | 85448120 | + | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Pictures | 961301832 | 83764 | 912363644 | + | /dev/sda3 | /var/lib/docker/aufs | 47929956 | 30666304 | 14805864 | + +-----------+-----------------------+-----------+----------+-----------+ + 9 rows in set (0.00 sec) + +- 'Disk' is the name of the disk itself. +- 'Path' is the mount point of the disk. +- 'Total' is the total space in KiB. +- 'Used' is the used amount of space in KiB, and +- 'Available' is the amount of space in KiB available to non-root users. + +Note that as the amount of space available to root may be more that what +is available to non-root users, 'available' + 'used' may be less than 'total'. + +All paths to which a particular disk has been mounted are reported. The +rationale is that someone might want to take different action e.g. depending +on which disk is relevant for a particular path. This leads to the same disk +being reported multiple times. An alternative to this would be to have two +tables; disks and mounts. + + > select * from information_schema.disks; + +-----------+-----------+----------+-----------+ + | Disk | Total | Used | Available | + +-----------+-----------+----------+-----------+ + | /dev/sda3 | 47929956 | 30666304 | 14805864 | + | /dev/sda1 | 191551 | 3461 | 188090 | + | /dev/sda4 | 174679768 | 80335392 | 85448120 | + | /dev/sdb1 | 961301832 | 83764 | 912363644 | + +-----------+-----------+----------+-----------+ + + > select * from information_schema.mounts; + +-----------------------+-----------+ + | Path | Disk | + +-----------------------+-----------+ + | / | /dev/sda3 | + | /boot/efi | /dev/sda1 | + | /home | /dev/sda4 | + | /mnt/hdd | /dev/sdb1 | + | /home/wikman/Music | /dev/sdb1 | + ... + + +Installation +------------ + +- Use "install plugin" or "install soname" command: + + MariaDB [(none)]> install plugin disks soname 'disks.so'; + + or + + MariaDB [(none)]> install soname 'disks.so'; + +Usage +----- +The plugin appears as the table 'disks' in 'information_schema'. + + MariaDB [(none)]> select * from information_schema.disks; + +-----------+-----------------------+-----------+----------+-----------+ + | Disk | Path | Total | Used | Available | + +-----------+-----------------------+-----------+----------+-----------+ + | /dev/sda3 | / | 47929956 | 30666308 | 14805860 | + | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 | + | /dev/sda4 | /home | 174679768 | 80348148 | 85435364 | + | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 | + | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 | + ... + diff --git a/plugin/disks/information_schema_disks.cc b/plugin/disks/information_schema_disks.cc new file mode 100644 index 00000000..042cfaff --- /dev/null +++ b/plugin/disks/information_schema_disks.cc @@ -0,0 +1,164 @@ +/* + Copyright (c) 2017, 2019, MariaDB + + 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 <my_global.h> +#include <sys/statvfs.h> +#include <sys/types.h> +#include <mntent.h> +#include <sql_class.h> +#include <sql_i_s.h> +#include <sql_acl.h> /* check_global_access() */ + +bool schema_table_store_record(THD *thd, TABLE *table); + + +struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION }; + + +namespace Show { + +ST_FIELD_INFO disks_table_fields[]= +{ + Column("Disk", Varchar(PATH_MAX), NOT_NULL), + Column("Path", Varchar(PATH_MAX), NOT_NULL), + Column("Total", SLonglong(32), NOT_NULL), // Total amount available + Column("Used", SLonglong(32), NOT_NULL), // Amount of space used + Column("Available", SLonglong(32), NOT_NULL), // Amount available to users other than root. + CEnd() +}; + + + +int disks_table_add_row(THD* pThd, + TABLE* pTable, + const char* zDisk, + const char* zPath, + const struct statvfs& info) +{ + // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html + // + // f_frsize Fundamental file system block size. + // f_blocks Total number of blocks on file system in units of f_frsize. + // f_bfree Total number of free blocks. + // f_bavail Number of free blocks available to non-privileged process. + + ulonglong total = ((ulonglong)info.f_frsize * info.f_blocks) / 1024; + ulonglong used = ((ulonglong)info.f_frsize * + (info.f_blocks - info.f_bfree)) / 1024; + ulonglong avail = ((ulonglong)info.f_frsize * info.f_bavail) / 1024; + + pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info); + pTable->field[1]->store(zPath, strlen(zPath), system_charset_info); + pTable->field[2]->store(total); + pTable->field[3]->store(used); + pTable->field[4]->store(avail); + + // 0 means success. + return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0; +} + +int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath) +{ + int rv = 0; + + struct statvfs info; + + if (statvfs(zPath, &info) == 0) // We ignore failures. + { + rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info); + } + + return rv; +} + +int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond) +{ + int rv = 1; + TABLE* pTable = pTables->table; + + if (check_global_access(pThd, FILE_ACL, true)) + return 0; + + FILE* pFile = setmntent("/etc/mtab", "r"); + + if (pFile) + { + const size_t BUFFER_SIZE = 4096; // 4K should be sufficient. + + char* pBuffer = new (std::nothrow) char [BUFFER_SIZE]; + + if (pBuffer) + { + rv = 0; + + struct mntent ent; + struct mntent* pEnt; + + while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE))) + { + // We only report the ones that refer to physical disks. + if (pEnt->mnt_fsname[0] == '/') + { + rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir); + } + } + + delete [] pBuffer; + } + else + { + rv = 1; + } + + endmntent(pFile); + } + + return rv; +} + +int disks_table_init(void *ptr) +{ + ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr; + + pSchema_table->fields_info = disks_table_fields; + pSchema_table->fill_table = disks_fill_table; + return 0; +} + +} // namespace Show + +extern "C" +{ + +maria_declare_plugin(disks) +{ + MYSQL_INFORMATION_SCHEMA_PLUGIN, + &disks_table_info, /* type-specific descriptor */ + "DISKS", /* table name */ + "Johan Wikman", /* author */ + "Disk space information", /* description */ + PLUGIN_LICENSE_GPL, /* license type */ + Show::disks_table_init, /* init function */ + NULL, /* deinit function */ + 0x0101, /* version = 1.1 */ + NULL, /* no status variables */ + NULL, /* no system variables */ + "1.1", /* String version representation */ + MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/ +} +mysql_declare_plugin_end; + +} diff --git a/plugin/disks/mysql-test/disks/disks.result b/plugin/disks/mysql-test/disks/disks.result new file mode 100644 index 00000000..0b4ee624 --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks.result @@ -0,0 +1,12 @@ +show create table information_schema.disks; +Table Create Table +DISKS CREATE TEMPORARY TABLE `DISKS` ( + `Disk` varchar(4096) NOT NULL DEFAULT '', + `Path` varchar(4096) NOT NULL DEFAULT '', + `Total` bigint(32) NOT NULL DEFAULT 0, + `Used` bigint(32) NOT NULL DEFAULT 0, + `Available` bigint(32) NOT NULL DEFAULT 0 +) ENGINE=MEMORY DEFAULT CHARSET=utf8 +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +sum(Total) > sum(Available) sum(Total)>sum(Used) +1 1 diff --git a/plugin/disks/mysql-test/disks/disks.test b/plugin/disks/mysql-test/disks/disks.test new file mode 100644 index 00000000..13a0762a --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks.test @@ -0,0 +1,2 @@ +show create table information_schema.disks; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.result b/plugin/disks/mysql-test/disks/disks_notembedded.result new file mode 100644 index 00000000..97429474 --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks_notembedded.result @@ -0,0 +1,22 @@ +# +# MDEV-18328: Make DISKS plugin check some privilege to access +# information_schema.DISKS table +# +CREATE USER user1@localhost; +GRANT SELECT ON *.* TO user1@localhost; +connect con1,localhost,user1,,; +connection con1; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +sum(Total) > sum(Available) sum(Total)>sum(Used) +NULL NULL +disconnect con1; +connection default; +GRANT FILE ON *.* TO user1@localhost; +connect con1,localhost,user1,,; +connection con1; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +sum(Total) > sum(Available) sum(Total)>sum(Used) +1 1 +connection default; +DROP USER user1@localhost; +# End of 10.1 tests diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.test b/plugin/disks/mysql-test/disks/disks_notembedded.test new file mode 100644 index 00000000..a0f6c2e5 --- /dev/null +++ b/plugin/disks/mysql-test/disks/disks_notembedded.test @@ -0,0 +1,25 @@ +source include/not_embedded.inc; + +--echo # +--echo # MDEV-18328: Make DISKS plugin check some privilege to access +--echo # information_schema.DISKS table +--echo # + +CREATE USER user1@localhost; +GRANT SELECT ON *.* TO user1@localhost; + +connect (con1,localhost,user1,,); +connection con1; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +disconnect con1; + +connection default; +GRANT FILE ON *.* TO user1@localhost; + +connect (con1,localhost,user1,,); +connection con1; +select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks; +connection default; +DROP USER user1@localhost; + +--echo # End of 10.1 tests diff --git a/plugin/disks/mysql-test/disks/suite.opt b/plugin/disks/mysql-test/disks/suite.opt new file mode 100644 index 00000000..afbbe2b0 --- /dev/null +++ b/plugin/disks/mysql-test/disks/suite.opt @@ -0,0 +1 @@ +--plugin-load-add=$DISKS_SO diff --git a/plugin/disks/mysql-test/disks/suite.pm b/plugin/disks/mysql-test/disks/suite.pm new file mode 100644 index 00000000..c64ef3b3 --- /dev/null +++ b/plugin/disks/mysql-test/disks/suite.pm @@ -0,0 +1,10 @@ +package My::Suite::Disks; + +@ISA = qw(My::Suite); + +return "No Disks plugin" unless $ENV{DISKS_SO}; + +sub is_default { 1 } + +bless { }; + |