1 /*
2    Copyright (c) 2017, MariaDB
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA */
16 
17 #include <my_global.h>
18 #include <sys/statvfs.h>
19 #include <sys/types.h>
20 #include <mntent.h>
21 #include <sql_class.h>
22 #include <table.h>
23 #include <sql_acl.h>                            /* check_global_access() */
24 
25 bool schema_table_store_record(THD *thd, TABLE *table);
26 
27 namespace
28 {
29 
30 struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
31 
32 ST_FIELD_INFO disks_table_fields[]=
33 {
34     { "Disk",      PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 },
35     { "Path",      PATH_MAX, MYSQL_TYPE_STRING, 0, 0 ,0, 0 },
36     { "Total",           32, MYSQL_TYPE_LONGLONG,   0, 0 ,0 ,0 }, // Total amount available
37     { "Used",            32, MYSQL_TYPE_LONGLONG,   0, 0 ,0 ,0 }, // Amount of space used
38     { "Available",       32, MYSQL_TYPE_LONGLONG,   0, 0 ,0 ,0 }, // Amount available to users other than root.
39     { 0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0 }
40 };
41 
disks_table_add_row(THD * pThd,TABLE * pTable,const char * zDisk,const char * zPath,const struct statvfs & info)42 int disks_table_add_row(THD* pThd,
43                         TABLE* pTable,
44                         const char* zDisk,
45                         const char* zPath,
46                         const struct statvfs& info)
47 {
48     // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html
49     //
50     // f_frsize   Fundamental file system block size.
51     // f_blocks   Total number of blocks on file system in units of f_frsize.
52     // f_bfree    Total number of free blocks.
53     // f_bavail   Number of free blocks available to non-privileged process.
54 
55     ulonglong total = ((ulonglong)info.f_frsize * info.f_blocks) / 1024;
56     ulonglong used  = ((ulonglong)info.f_frsize *
57                             (info.f_blocks - info.f_bfree)) / 1024;
58     ulonglong avail = ((ulonglong)info.f_frsize * info.f_bavail) / 1024;
59 
60     pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info);
61     pTable->field[1]->store(zPath, strlen(zPath), system_charset_info);
62     pTable->field[2]->store(total);
63     pTable->field[3]->store(used);
64     pTable->field[4]->store(avail);
65 
66     // 0 means success.
67     return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0;
68 }
69 
disks_table_add_row(THD * pThd,TABLE * pTable,const char * zDisk,const char * zPath)70 int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath)
71 {
72     int rv = 0;
73 
74     struct statvfs info;
75 
76     if (statvfs(zPath, &info) == 0) // We ignore failures.
77     {
78         rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info);
79     }
80 
81     return rv;
82 }
83 
disks_fill_table(THD * pThd,TABLE_LIST * pTables,Item * pCond)84 int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond)
85 {
86     int rv = 1;
87     TABLE* pTable = pTables->table;
88 
89     if (check_global_access(pThd, FILE_ACL, true))
90       return 0;
91 
92     FILE* pFile = setmntent("/etc/mtab", "r");
93 
94     if (pFile)
95     {
96         const size_t BUFFER_SIZE = 4096; // 4K should be sufficient.
97 
98         char* pBuffer = new (std::nothrow) char [BUFFER_SIZE];
99 
100         if (pBuffer)
101         {
102             rv = 0;
103 
104             struct mntent ent;
105             struct mntent* pEnt;
106 
107             while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE)))
108             {
109                 // We only report the ones that refer to physical disks.
110                 if (pEnt->mnt_fsname[0] == '/')
111                 {
112                     rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir);
113                 }
114             }
115 
116             delete [] pBuffer;
117         }
118         else
119         {
120             rv = 1;
121         }
122 
123         endmntent(pFile);
124     }
125 
126     return rv;
127 }
128 
disks_table_init(void * ptr)129 int disks_table_init(void *ptr)
130 {
131     ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr;
132 
133     pSchema_table->fields_info = disks_table_fields;
134     pSchema_table->fill_table = disks_fill_table;
135     return 0;
136 }
137 
138 }
139 
140 extern "C"
141 {
142 
maria_declare_plugin(disks)143 maria_declare_plugin(disks)
144 {
145     MYSQL_INFORMATION_SCHEMA_PLUGIN,
146     &disks_table_info,                 /* type-specific descriptor */
147     "DISKS",                           /* table name */
148     "Johan Wikman",                    /* author */
149     "Disk space information",          /* description */
150     PLUGIN_LICENSE_GPL,                /* license type */
151     disks_table_init,                  /* init function */
152     NULL,                              /* deinit function */
153     0x0101,                            /* version = 1.1 */
154     NULL,                              /* no status variables */
155     NULL,                              /* no system variables */
156     "1.1",                             /* String version representation */
157     MariaDB_PLUGIN_MATURITY_STABLE     /* Maturity (see include/mysql/plugin.h)*/
158 }
159 mysql_declare_plugin_end;
160 
161 }
162