1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "sysinfo.h"
22 #include "zbxjson.h"
23 #include "log.h"
24 #include "zbxalgo.h"
25 #include "inodes.h"
26
get_fs_size_stat(const char * fs,zbx_uint64_t * total,zbx_uint64_t * free,zbx_uint64_t * used,double * pfree,double * pused,char ** error)27 static int get_fs_size_stat(const char *fs, zbx_uint64_t *total, zbx_uint64_t *free,
28 zbx_uint64_t *used, double *pfree, double *pused, char **error)
29 {
30 #ifdef HAVE_SYS_STATVFS_H
31 # ifdef HAVE_SYS_STATVFS64
32 # define ZBX_STATFS statvfs64
33 # else
34 # define ZBX_STATFS statvfs
35 # endif
36 # define ZBX_BSIZE f_frsize
37 #else
38 # define ZBX_STATFS statfs
39 # define ZBX_BSIZE f_bsize
40 #endif
41 struct ZBX_STATFS s;
42
43 if (0 != ZBX_STATFS(fs, &s))
44 {
45 *error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno));
46 zabbix_log(LOG_LEVEL_DEBUG,"%s failed with error: %s",__func__, *error);
47 return SYSINFO_RET_FAIL;
48 }
49
50 /* Available space could be negative (top bit set) if we hit disk space */
51 /* reserved for non-privileged users. Treat it as 0. */
52 if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail))
53 s.f_bavail = 0;
54
55 if (NULL != total)
56 *total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE;
57
58 if (NULL != free)
59 *free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE;
60
61 if (NULL != used)
62 *used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE;
63
64 if (NULL != pfree)
65 {
66 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
67 *pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
68 else
69 *pfree = 0;
70 }
71
72 if (NULL != pused)
73 {
74 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
75 *pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
76 else
77 *pused = 0;
78 }
79
80 return SYSINFO_RET_OK;
81 }
82
VFS_FS_USED(const char * fs,AGENT_RESULT * result)83 static int VFS_FS_USED(const char *fs, AGENT_RESULT *result)
84 {
85 zbx_uint64_t value;
86 char *error;
87
88 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, &value, NULL, NULL, &error))
89 {
90 SET_MSG_RESULT(result, error);
91 return SYSINFO_RET_FAIL;
92 }
93
94 SET_UI64_RESULT(result, value);
95
96 return SYSINFO_RET_OK;
97 }
98
VFS_FS_FREE(const char * fs,AGENT_RESULT * result)99 static int VFS_FS_FREE(const char *fs, AGENT_RESULT *result)
100 {
101 zbx_uint64_t value;
102 char *error;
103
104 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, &value, NULL, NULL, NULL, &error))
105 {
106 SET_MSG_RESULT(result, error);
107 return SYSINFO_RET_FAIL;
108 }
109
110 SET_UI64_RESULT(result, value);
111
112 return SYSINFO_RET_OK;
113 }
114
VFS_FS_TOTAL(const char * fs,AGENT_RESULT * result)115 static int VFS_FS_TOTAL(const char *fs, AGENT_RESULT *result)
116 {
117 zbx_uint64_t value;
118 char *error;
119
120 if (SYSINFO_RET_OK != get_fs_size_stat(fs, &value, NULL, NULL, NULL, NULL, &error))
121 {
122 SET_MSG_RESULT(result, error);
123 return SYSINFO_RET_FAIL;
124 }
125
126 SET_UI64_RESULT(result, value);
127
128 return SYSINFO_RET_OK;
129 }
130
VFS_FS_PFREE(const char * fs,AGENT_RESULT * result)131 static int VFS_FS_PFREE(const char *fs, AGENT_RESULT *result)
132 {
133 double value;
134 char *error;
135
136 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, &value, NULL, &error))
137 {
138 SET_MSG_RESULT(result, error);
139 return SYSINFO_RET_FAIL;
140 }
141
142 SET_DBL_RESULT(result, value);
143
144 return SYSINFO_RET_OK;
145 }
146
VFS_FS_PUSED(const char * fs,AGENT_RESULT * result)147 static int VFS_FS_PUSED(const char *fs, AGENT_RESULT *result)
148 {
149 double value;
150 char *error;
151
152 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, NULL, &value, &error))
153 {
154 SET_MSG_RESULT(result, error);
155 return SYSINFO_RET_FAIL;
156 }
157
158 SET_DBL_RESULT(result, value);
159
160 return SYSINFO_RET_OK;
161 }
162
vfs_fs_size(AGENT_REQUEST * request,AGENT_RESULT * result)163 static int vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result)
164 {
165 char *fsname, *mode;
166
167 if (2 < request->nparam)
168 {
169 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
170 return SYSINFO_RET_FAIL;
171 }
172
173 fsname = get_rparam(request, 0);
174 mode = get_rparam(request, 1);
175
176 if (NULL == fsname || '\0' == *fsname)
177 {
178 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
179 return SYSINFO_RET_FAIL;
180 }
181
182 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total")) /* default parameter */
183 return VFS_FS_TOTAL(fsname, result);
184 if (0 == strcmp(mode, "free"))
185 return VFS_FS_FREE(fsname, result);
186 if (0 == strcmp(mode, "pfree"))
187 return VFS_FS_PFREE(fsname, result);
188 if (0 == strcmp(mode, "used"))
189 return VFS_FS_USED(fsname, result);
190 if (0 == strcmp(mode, "pused"))
191 return VFS_FS_PUSED(fsname, result);
192
193 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
194
195 return SYSINFO_RET_FAIL;
196 }
197
VFS_FS_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)198 int VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
199 {
200 return zbx_execute_threaded_metric(vfs_fs_size, request, result);
201 }
202
VFS_FS_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)203 int VFS_FS_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
204 {
205 struct mnttab mt;
206 FILE *f;
207 struct zbx_json j;
208
209 /* opening the mounted filesystems file */
210 if (NULL == (f = fopen("/etc/mnttab", "r")))
211 {
212 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /etc/mnttab: %s", zbx_strerror(errno)));
213 return SYSINFO_RET_FAIL;
214 }
215
216 zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
217
218 zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
219
220 /* fill mnttab structure from file */
221 while (-1 != getmntent(f, &mt))
222 {
223 zbx_json_addobject(&j, NULL);
224 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSNAME, mt.mnt_mountp, ZBX_JSON_TYPE_STRING);
225 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSTYPE, mt.mnt_fstype, ZBX_JSON_TYPE_STRING);
226 zbx_json_close(&j);
227 }
228
229 zbx_fclose(f);
230
231 zbx_json_close(&j);
232
233 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
234
235 zbx_json_free(&j);
236
237 return SYSINFO_RET_OK;
238 }
239
vfs_fs_get(AGENT_REQUEST * request,AGENT_RESULT * result)240 static int vfs_fs_get(AGENT_REQUEST *request, AGENT_RESULT *result)
241 {
242 struct mnttab mt;
243 FILE *f;
244 struct zbx_json j;
245 zbx_uint64_t total, not_used, used;
246 zbx_uint64_t itotal, inot_used, iused;
247 double pfree, pused;
248 double ipfree, ipused;
249 char *error;
250 zbx_vector_ptr_t mntpoints;
251 zbx_mpoint_t *mntpoint;
252 int ret = SYSINFO_RET_FAIL;
253 char *mpoint;
254
255 /* opening the mounted filesystems file */
256 if (NULL == (f = fopen("/etc/mnttab", "r")))
257 {
258 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /etc/mnttab: %s", zbx_strerror(errno)));
259 return SYSINFO_RET_FAIL;
260 }
261
262 zbx_vector_ptr_create(&mntpoints);
263
264 /* fill mnttab structure from file */
265 while (-1 != getmntent(f, &mt))
266 {
267 mpoint = mt.mnt_mountp;
268 if (SYSINFO_RET_OK != get_fs_size_stat(mpoint, &total, ¬_used, &used, &pfree, &pused,&error))
269 {
270 zbx_free(error);
271 continue;
272 }
273 if (SYSINFO_RET_OK != get_fs_inode_stat(mpoint, &itotal, &inot_used, &iused, &ipfree, &ipused, "pused",
274 &error))
275 {
276 zbx_free(error);
277 continue;
278 }
279
280 mntpoint = (zbx_mpoint_t *)zbx_malloc(NULL, sizeof(zbx_mpoint_t));
281 zbx_strlcpy(mntpoint->fsname, mpoint, MAX_STRING_LEN);
282 zbx_strlcpy(mntpoint->fstype, mt.mnt_fstype, MAX_STRING_LEN);
283 mntpoint->bytes.total = total;
284 mntpoint->bytes.used = used;
285 mntpoint->bytes.not_used = not_used;
286 mntpoint->bytes.pfree = pfree;
287 mntpoint->bytes.pused = pused;
288 mntpoint->inodes.total = itotal;
289 mntpoint->inodes.used = iused;
290 mntpoint->inodes.not_used = inot_used;
291 mntpoint->inodes.pfree = ipfree;
292 mntpoint->inodes.pused = ipused;
293
294 zbx_vector_ptr_append(&mntpoints, mntpoint);
295 }
296 zbx_fclose(f);
297
298 if (NULL == (f = fopen("/etc/mnttab", "r")))
299 {
300 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /etc/mnttab: %s", zbx_strerror(errno)));
301 goto out;
302 }
303
304 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
305
306 /* fill mnttab structure from file */
307 while (-1 != getmntent(f, &mt))
308 {
309 int idx;
310 mpoint = mt.mnt_mountp;
311
312 if (FAIL != (idx = zbx_vector_ptr_search(&mntpoints, mpoint, ZBX_DEFAULT_STR_COMPARE_FUNC)))
313 {
314 mntpoint = (zbx_mpoint_t *)mntpoints.values[idx];
315 zbx_json_addobject(&j, NULL);
316 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSNAME, mntpoint->fsname, ZBX_JSON_TYPE_STRING);
317 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSTYPE, mntpoint->fstype, ZBX_JSON_TYPE_STRING);
318 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_BYTES);
319 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->bytes.total);
320 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->bytes.not_used);
321 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->bytes.used);
322 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->bytes.pfree);
323 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->bytes.pused);
324 zbx_json_close(&j);
325 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_INODES);
326 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->inodes.total);
327 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->inodes.not_used);
328 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->inodes.used);
329 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->inodes.pfree);
330 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->inodes.pused);
331 zbx_json_close(&j);
332 zbx_json_close(&j);
333 }
334 }
335 zbx_fclose(f);
336
337 zbx_json_close(&j);
338
339 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
340
341 zbx_json_free(&j);
342 ret = SYSINFO_RET_OK;
343 out:
344 zbx_vector_ptr_clear_ext(&mntpoints, (zbx_clean_func_t)zbx_mpoints_free);
345 zbx_vector_ptr_destroy(&mntpoints);
346
347 return ret;
348 }
VFS_FS_GET(AGENT_REQUEST * request,AGENT_RESULT * result)349 int VFS_FS_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
350 {
351 return zbx_execute_threaded_metric(vfs_fs_get, request, result);
352
353 }
354
355