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 # ifdef HAVE_SYS_STATFS64
39 # define ZBX_STATFS statfs64
40 # else
41 # define ZBX_STATFS statfs
42 # endif
43 # define ZBX_BSIZE f_bsize
44 #endif
45 struct ZBX_STATFS s;
46
47 if (0 != ZBX_STATFS(fs, &s))
48 {
49 *error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno));
50 zabbix_log(LOG_LEVEL_DEBUG,"%s failed with error: %s",__func__, *error);
51 return SYSINFO_RET_FAIL;
52 }
53
54 /* Available space could be negative (top bit set) if we hit disk space */
55 /* reserved for non-privileged users. Treat it as 0. */
56 if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail))
57 s.f_bavail = 0;
58
59 if (NULL != total)
60 *total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE;
61
62 if (NULL != free)
63 *free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE;
64
65 if (NULL != used)
66 *used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE;
67
68 if (NULL != pfree)
69 {
70 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
71 *pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
72 else
73 *pfree = 0;
74 }
75
76 if (NULL != pused)
77 {
78 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
79 *pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
80 else
81 *pused = 0;
82 }
83
84 return SYSINFO_RET_OK;
85 }
86
VFS_FS_USED(const char * fs,AGENT_RESULT * result)87 static int VFS_FS_USED(const char *fs, AGENT_RESULT *result)
88 {
89 zbx_uint64_t value;
90 char *error;
91
92 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, &value, NULL, NULL, &error))
93 {
94 SET_MSG_RESULT(result, error);
95 return SYSINFO_RET_FAIL;
96 }
97
98 SET_UI64_RESULT(result, value);
99
100 return SYSINFO_RET_OK;
101 }
102
VFS_FS_FREE(const char * fs,AGENT_RESULT * result)103 static int VFS_FS_FREE(const char *fs, AGENT_RESULT *result)
104 {
105 zbx_uint64_t value;
106 char *error;
107
108 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, &value, NULL, NULL, NULL, &error))
109 {
110 SET_MSG_RESULT(result, error);
111 return SYSINFO_RET_FAIL;
112 }
113
114 SET_UI64_RESULT(result, value);
115
116 return SYSINFO_RET_OK;
117 }
118
VFS_FS_TOTAL(const char * fs,AGENT_RESULT * result)119 static int VFS_FS_TOTAL(const char *fs, AGENT_RESULT *result)
120 {
121 zbx_uint64_t value;
122 char *error;
123
124 if (SYSINFO_RET_OK != get_fs_size_stat(fs, &value, NULL, NULL, NULL, NULL, &error))
125 {
126 SET_MSG_RESULT(result, error);
127 return SYSINFO_RET_FAIL;
128 }
129
130 SET_UI64_RESULT(result, value);
131
132 return SYSINFO_RET_OK;
133 }
134
VFS_FS_PFREE(const char * fs,AGENT_RESULT * result)135 static int VFS_FS_PFREE(const char *fs, AGENT_RESULT *result)
136 {
137 double value;
138 char *error;
139
140 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, &value, NULL, &error))
141 {
142 SET_MSG_RESULT(result, error);
143 return SYSINFO_RET_FAIL;
144 }
145
146 SET_DBL_RESULT(result, value);
147
148 return SYSINFO_RET_OK;
149 }
150
VFS_FS_PUSED(const char * fs,AGENT_RESULT * result)151 static int VFS_FS_PUSED(const char *fs, AGENT_RESULT *result)
152 {
153 double value;
154 char *error;
155
156 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, NULL, &value, &error))
157 {
158 SET_MSG_RESULT(result, error);
159 return SYSINFO_RET_FAIL;
160 }
161
162 SET_DBL_RESULT(result, value);
163
164 return SYSINFO_RET_OK;
165 }
166
vfs_fs_size(AGENT_REQUEST * request,AGENT_RESULT * result)167 static int vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result)
168 {
169 char *fsname, *mode;
170
171 if (2 < request->nparam)
172 {
173 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
174 return SYSINFO_RET_FAIL;
175 }
176
177 fsname = get_rparam(request, 0);
178 mode = get_rparam(request, 1);
179
180 if (NULL == fsname || '\0' == *fsname)
181 {
182 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
183 return SYSINFO_RET_FAIL;
184 }
185
186 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total")) /* default parameter */
187 return VFS_FS_TOTAL(fsname, result);
188 if (0 == strcmp(mode, "free"))
189 return VFS_FS_FREE(fsname, result);
190 if (0 == strcmp(mode, "pfree"))
191 return VFS_FS_PFREE(fsname, result);
192 if (0 == strcmp(mode, "used"))
193 return VFS_FS_USED(fsname, result);
194 if (0 == strcmp(mode, "pused"))
195 return VFS_FS_PUSED(fsname, result);
196
197 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
198
199 return SYSINFO_RET_FAIL;
200 }
201
VFS_FS_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)202 int VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
203 {
204 return zbx_execute_threaded_metric(vfs_fs_size, request, result);
205 }
206
zbx_get_vfs_name_by_type(int type)207 static const char *zbx_get_vfs_name_by_type(int type)
208 {
209 extern struct vfs_ent *getvfsbytype(int type);
210
211 struct vfs_ent *vfs;
212 static char **vfs_names = NULL;
213 static size_t vfs_names_alloc = 0;
214
215 if (type + 1 > vfs_names_alloc)
216 {
217 size_t num = type + 1;
218
219 vfs_names = zbx_realloc(vfs_names, sizeof(char *) * num);
220 memset(vfs_names + vfs_names_alloc, 0, sizeof(char *) * (num - vfs_names_alloc));
221 vfs_names_alloc = num;
222 }
223
224 if (NULL == vfs_names)
225 return "unknown";
226
227 if (NULL == vfs_names[type] && NULL != (vfs = getvfsbytype(type)))
228 vfs_names[type] = zbx_strdup(vfs_names[type], vfs->vfsent_name);
229
230 return NULL != vfs_names[type] ? vfs_names[type] : "unknown";
231 }
232
VFS_FS_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)233 int VFS_FS_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
234 {
235 int rc, sz, i, ret = SYSINFO_RET_FAIL;
236 struct vmount *vms = NULL, *vm;
237 struct zbx_json j;
238
239 /* check how many bytes to allocate for the mounted filesystems */
240 if (-1 == (rc = mntctl(MCTL_QUERY, sizeof(sz), (char *)&sz)))
241 {
242 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
243 return SYSINFO_RET_FAIL;
244 }
245
246 sz *= 2;
247 vms = zbx_malloc(vms, (size_t)sz);
248
249 /* get the list of mounted filesystems */
250 /* return code is number of filesystems returned */
251 if (-1 == (rc = mntctl(MCTL_QUERY, sz, (char *)vms)))
252 {
253 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
254 goto error;
255 }
256
257 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
258
259 for (i = 0, vm = vms; i < rc; i++)
260 {
261 zbx_json_addobject(&j, NULL);
262 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSNAME, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
263 ZBX_JSON_TYPE_STRING);
264 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSTYPE, zbx_get_vfs_name_by_type(vm->vmt_gfstype),
265 ZBX_JSON_TYPE_STRING);
266 zbx_json_close(&j);
267
268 /* go to the next vmount structure */
269 vm = (struct vmount *)((char *)vm + vm->vmt_length);
270 }
271
272 zbx_json_close(&j);
273
274 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
275
276 zbx_json_free(&j);
277
278 ret = SYSINFO_RET_OK;
279 error:
280 zbx_free(vms);
281
282 return ret;
283 }
284
vfs_fs_get(AGENT_REQUEST * request,AGENT_RESULT * result)285 static int vfs_fs_get(AGENT_REQUEST *request, AGENT_RESULT *result)
286 {
287 int rc, sz, i, ret = SYSINFO_RET_FAIL;
288 struct vmount *vms = NULL, *vm;
289 struct zbx_json j;
290 zbx_uint64_t total, not_used, used;
291 zbx_uint64_t itotal, inot_used, iused;
292 double pfree, pused;
293 double ipfree, ipused;
294 char *error;
295 zbx_vector_ptr_t mntpoints;
296 zbx_mpoint_t *mntpoint;
297 char *mpoint;
298
299 /* check how many bytes to allocate for the mounted filesystems */
300 if (-1 == (rc = mntctl(MCTL_QUERY, sizeof(sz), (char *)&sz)))
301 {
302 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
303 return SYSINFO_RET_FAIL;
304 }
305
306 zbx_vector_ptr_create(&mntpoints);
307
308 sz *= 2;
309 vms = zbx_malloc(vms, (size_t)sz);
310
311 /* get the list of mounted filesystems */
312 /* return code is number of filesystems returned */
313 if (-1 == (rc = mntctl(MCTL_QUERY, sz, (char *)vms)))
314 {
315 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
316 goto out;
317 }
318 for (i = 0, vm = vms; i < rc; i++)
319 {
320 mpoint = (char *)vm + vm->vmt_data[VMT_STUB].vmt_off;
321
322 if (SYSINFO_RET_OK != get_fs_size_stat(mpoint, &total, ¬_used, &used, &pfree, &pused, &error))
323 {
324 zbx_free(error);
325 continue;
326 }
327 if (SYSINFO_RET_OK != get_fs_inode_stat(mpoint, &itotal, &inot_used, &iused, &ipfree, &ipused, "pused",
328 &error))
329 {
330 zbx_free(error);
331 continue;
332 }
333
334 mntpoint = (zbx_mpoint_t *)zbx_malloc(NULL, sizeof(zbx_mpoint_t));
335 zbx_strlcpy(mntpoint->fsname, mpoint, MAX_STRING_LEN);
336 zbx_strlcpy(mntpoint->fstype, zbx_get_vfs_name_by_type(vm->vmt_gfstype), MAX_STRING_LEN);
337 mntpoint->bytes.total = total;
338 mntpoint->bytes.used = used;
339 mntpoint->bytes.not_used = not_used;
340 mntpoint->bytes.pfree = pfree;
341 mntpoint->bytes.pused = pused;
342 mntpoint->inodes.total = itotal;
343 mntpoint->inodes.used = iused;
344 mntpoint->inodes.not_used = inot_used;
345 mntpoint->inodes.pfree = ipfree;
346 mntpoint->inodes.pused = ipused;
347
348 zbx_vector_ptr_append(&mntpoints, mntpoint);
349
350 /* go to the next vmount structure */
351 vm = (struct vmount *)((char *)vm + vm->vmt_length);
352 }
353
354 if (-1 == (rc = mntctl(MCTL_QUERY, sz, (char *)vms)))
355 {
356 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
357 goto out;
358 }
359
360 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
361
362 for (i = 0, vm = vms; i < rc; i++)
363 {
364 int idx;
365
366 mpoint = (char *)vm + vm->vmt_data[VMT_STUB].vmt_off;
367
368 if (FAIL != (idx = zbx_vector_ptr_search(&mntpoints, mpoint, ZBX_DEFAULT_STR_COMPARE_FUNC)))
369 {
370 mntpoint = (zbx_mpoint_t *)mntpoints.values[idx];
371 zbx_json_addobject(&j, NULL);
372 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSNAME, mntpoint->fsname, ZBX_JSON_TYPE_STRING);
373 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSTYPE, mntpoint->fstype, ZBX_JSON_TYPE_STRING);
374 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_BYTES);
375 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->bytes.total);
376 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->bytes.not_used);
377 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->bytes.used);
378 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->bytes.pfree);
379 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->bytes.pused);
380 zbx_json_close(&j);
381 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_INODES);
382 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->inodes.total);
383 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->inodes.not_used);
384 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->inodes.used);
385 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->inodes.pfree);
386 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->inodes.pused);
387 zbx_json_close(&j);
388 zbx_json_close(&j);
389 }
390
391 /* go to the next vmount structure */
392 vm = (struct vmount *)((char *)vm + vm->vmt_length);
393 }
394
395 zbx_json_close(&j);
396
397 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
398
399 zbx_json_free(&j);
400
401 ret = SYSINFO_RET_OK;
402 out:
403 zbx_free(vms);
404 zbx_vector_ptr_clear_ext(&mntpoints, (zbx_clean_func_t)zbx_mpoints_free);
405 zbx_vector_ptr_destroy(&mntpoints);
406
407 return ret;
408 }
409
VFS_FS_GET(AGENT_REQUEST * request,AGENT_RESULT * result)410 int VFS_FS_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
411 {
412 return zbx_execute_threaded_metric(vfs_fs_get, request, result);
413
414 }
415