1 /*
2    Copyright (c) 2017, 2019, 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 <sql_i_s.h>
23 #include <sql_acl.h>                            /* check_global_access() */
24 
25 bool schema_table_store_record(THD *thd, TABLE *table);
26 
27 
28 struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
29 
30 
31 namespace Show {
32 
33 ST_FIELD_INFO disks_table_fields[]=
34 {
35   Column("Disk",      Varchar(PATH_MAX), NOT_NULL),
36   Column("Path",      Varchar(PATH_MAX), NOT_NULL),
37   Column("Total",     SLonglong(32),     NOT_NULL), // Total amount available
38   Column("Used",      SLonglong(32),     NOT_NULL), // Amount of space used
39   Column("Available", SLonglong(32),     NOT_NULL), // Amount available to users other than root.
40   CEnd()
41 };
42 
43 
44 
disks_table_add_row(THD * pThd,TABLE * pTable,const char * zDisk,const char * zPath,const struct statvfs & info)45 int disks_table_add_row(THD* pThd,
46                         TABLE* pTable,
47                         const char* zDisk,
48                         const char* zPath,
49                         const struct statvfs& info)
50 {
51     // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html
52     //
53     // f_frsize   Fundamental file system block size.
54     // f_blocks   Total number of blocks on file system in units of f_frsize.
55     // f_bfree    Total number of free blocks.
56     // f_bavail   Number of free blocks available to non-privileged process.
57 
58     ulonglong total = ((ulonglong)info.f_frsize * info.f_blocks) / 1024;
59     ulonglong used  = ((ulonglong)info.f_frsize *
60                             (info.f_blocks - info.f_bfree)) / 1024;
61     ulonglong avail = ((ulonglong)info.f_frsize * info.f_bavail) / 1024;
62 
63     pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info);
64     pTable->field[1]->store(zPath, strlen(zPath), system_charset_info);
65     pTable->field[2]->store(total);
66     pTable->field[3]->store(used);
67     pTable->field[4]->store(avail);
68 
69     // 0 means success.
70     return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0;
71 }
72 
disks_table_add_row(THD * pThd,TABLE * pTable,const char * zDisk,const char * zPath)73 int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath)
74 {
75     int rv = 0;
76 
77     struct statvfs info;
78 
79     if (statvfs(zPath, &info) == 0) // We ignore failures.
80     {
81         rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info);
82     }
83 
84     return rv;
85 }
86 
disks_fill_table(THD * pThd,TABLE_LIST * pTables,Item * pCond)87 int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond)
88 {
89     int rv = 1;
90     TABLE* pTable = pTables->table;
91 
92     if (check_global_access(pThd, FILE_ACL, true))
93       return 0;
94 
95     FILE* pFile = setmntent("/etc/mtab", "r");
96 
97     if (pFile)
98     {
99         const size_t BUFFER_SIZE = 4096; // 4K should be sufficient.
100 
101         char* pBuffer = new (std::nothrow) char [BUFFER_SIZE];
102 
103         if (pBuffer)
104         {
105             rv = 0;
106 
107             struct mntent ent;
108             struct mntent* pEnt;
109 
110             while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE)))
111             {
112                 // We only report the ones that refer to physical disks.
113                 if (pEnt->mnt_fsname[0] == '/')
114                 {
115                     rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir);
116                 }
117             }
118 
119             delete [] pBuffer;
120         }
121         else
122         {
123             rv = 1;
124         }
125 
126         endmntent(pFile);
127     }
128 
129     return rv;
130 }
131 
disks_table_init(void * ptr)132 int disks_table_init(void *ptr)
133 {
134     ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr;
135 
136     pSchema_table->fields_info = disks_table_fields;
137     pSchema_table->fill_table = disks_fill_table;
138     return 0;
139 }
140 
141 } // namespace Show
142 
143 extern "C"
144 {
145 
maria_declare_plugin(disks)146 maria_declare_plugin(disks)
147 {
148     MYSQL_INFORMATION_SCHEMA_PLUGIN,
149     &disks_table_info,                 /* type-specific descriptor */
150     "DISKS",                           /* table name */
151     "Johan Wikman",                    /* author */
152     "Disk space information",          /* description */
153     PLUGIN_LICENSE_GPL,                /* license type */
154     Show::disks_table_init,            /* init function */
155     NULL,                              /* deinit function */
156     0x0101,                            /* version = 1.1 */
157     NULL,                              /* no status variables */
158     NULL,                              /* no system variables */
159     "1.1",                             /* String version representation */
160     MariaDB_PLUGIN_MATURITY_STABLE     /* Maturity (see include/mysql/plugin.h)*/
161 }
162 mysql_declare_plugin_end;
163 
164 }
165