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 # define ZBX_STATFS statvfs
32 # define ZBX_BSIZE f_frsize
33 #else
34 # define ZBX_STATFS statfs
35 # define ZBX_BSIZE f_bsize
36 #endif
37 struct ZBX_STATFS s;
38
39 if (0 != ZBX_STATFS(fs, &s))
40 {
41 *error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno));
42 zabbix_log(LOG_LEVEL_DEBUG,"%s failed with error: %s",__func__, *error);
43 return SYSINFO_RET_FAIL;
44 }
45
46 /* Available space could be negative (top bit set) if we hit disk space */
47 /* reserved for non-privileged users. Treat it as 0. */
48 if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail))
49 s.f_bavail = 0;
50
51 if (NULL != total)
52 *total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE;
53
54 if (NULL != free)
55 *free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE;
56
57 if (NULL != used)
58 *used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE;
59
60 if (NULL != pfree)
61 {
62 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
63 *pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
64 else
65 *pfree = 0;
66 }
67
68 if (NULL != pused)
69 {
70 if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
71 *pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
72 else
73 *pused = 0;
74 }
75
76 return SYSINFO_RET_OK;
77 }
78
VFS_FS_USED(const char * fs,AGENT_RESULT * result)79 static int VFS_FS_USED(const char *fs, AGENT_RESULT *result)
80 {
81 zbx_uint64_t value;
82 char *error;
83
84 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, &value, NULL, NULL, &error))
85 {
86 SET_MSG_RESULT(result, error);
87 return SYSINFO_RET_FAIL;
88 }
89
90 SET_UI64_RESULT(result, value);
91
92 return SYSINFO_RET_OK;
93 }
94
VFS_FS_FREE(const char * fs,AGENT_RESULT * result)95 static int VFS_FS_FREE(const char *fs, AGENT_RESULT *result)
96 {
97 zbx_uint64_t value;
98 char *error;
99
100 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, &value, NULL, NULL, NULL, &error))
101 {
102 SET_MSG_RESULT(result, error);
103 return SYSINFO_RET_FAIL;
104 }
105
106 SET_UI64_RESULT(result, value);
107
108 return SYSINFO_RET_OK;
109 }
110
VFS_FS_TOTAL(const char * fs,AGENT_RESULT * result)111 static int VFS_FS_TOTAL(const char *fs, AGENT_RESULT *result)
112 {
113 zbx_uint64_t value;
114 char *error;
115
116 if (SYSINFO_RET_OK != get_fs_size_stat(fs, &value, NULL, NULL, NULL, NULL, &error))
117 {
118 SET_MSG_RESULT(result, error);
119 return SYSINFO_RET_FAIL;
120 }
121
122 SET_UI64_RESULT(result, value);
123
124 return SYSINFO_RET_OK;
125 }
126
VFS_FS_PFREE(const char * fs,AGENT_RESULT * result)127 static int VFS_FS_PFREE(const char *fs, AGENT_RESULT *result)
128 {
129 double value;
130 char *error;
131
132 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, &value, NULL, &error))
133 {
134 SET_MSG_RESULT(result, error);
135 return SYSINFO_RET_FAIL;
136 }
137
138 SET_DBL_RESULT(result, value);
139
140 return SYSINFO_RET_OK;
141 }
142
VFS_FS_PUSED(const char * fs,AGENT_RESULT * result)143 static int VFS_FS_PUSED(const char *fs, AGENT_RESULT *result)
144 {
145 double value;
146 char *error;
147
148 if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, NULL, &value, &error))
149 {
150 SET_MSG_RESULT(result, error);
151 return SYSINFO_RET_FAIL;
152 }
153
154 SET_DBL_RESULT(result, value);
155
156 return SYSINFO_RET_OK;
157 }
158
vfs_fs_size(AGENT_REQUEST * request,AGENT_RESULT * result)159 static int vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result)
160 {
161 char *fsname, *mode;
162
163 if (2 < request->nparam)
164 {
165 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
166 return SYSINFO_RET_FAIL;
167 }
168
169 fsname = get_rparam(request, 0);
170 mode = get_rparam(request, 1);
171
172 if (NULL == fsname || '\0' == *fsname)
173 {
174 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
175 return SYSINFO_RET_FAIL;
176 }
177
178 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total")) /* default parameter */
179 return VFS_FS_TOTAL(fsname, result);
180 if (0 == strcmp(mode, "free"))
181 return VFS_FS_FREE(fsname, result);
182 if (0 == strcmp(mode, "pfree"))
183 return VFS_FS_PFREE(fsname, result);
184 if (0 == strcmp(mode, "used"))
185 return VFS_FS_USED(fsname, result);
186 if (0 == strcmp(mode, "pused"))
187 return VFS_FS_PUSED(fsname, result);
188
189 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
190
191 return SYSINFO_RET_FAIL;
192 }
193
VFS_FS_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)194 int VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
195 {
196 return zbx_execute_threaded_metric(vfs_fs_size, request, result);
197 }
198
VFS_FS_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)199 int VFS_FS_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
200 {
201 int i, rc;
202 struct statfs *mntbuf;
203 struct zbx_json j;
204
205 if (0 == (rc = getmntinfo(&mntbuf, MNT_WAIT)))
206 {
207 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
208 return SYSINFO_RET_FAIL;
209 }
210
211 zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
212
213 zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
214
215 for (i = 0; i < rc; i++)
216 {
217 zbx_json_addobject(&j, NULL);
218 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSNAME, mntbuf[i].f_mntonname, ZBX_JSON_TYPE_STRING);
219 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSTYPE, mntbuf[i].f_fstypename, ZBX_JSON_TYPE_STRING);
220 zbx_json_close(&j);
221 }
222
223 zbx_json_close(&j);
224
225 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
226
227 zbx_json_free(&j);
228
229 return SYSINFO_RET_OK;
230 }
231
vfs_fs_get(AGENT_REQUEST * request,AGENT_RESULT * result)232 static int vfs_fs_get(AGENT_REQUEST *request, AGENT_RESULT *result)
233 {
234 int i, rc;
235 struct statfs *mntbuf;
236 struct zbx_json j;
237 zbx_uint64_t total, not_used, used;
238 zbx_uint64_t itotal, inot_used, iused;
239 double pfree, pused;
240 double ipfree, ipused;
241 char *error;
242 zbx_vector_ptr_t mntpoints;
243 zbx_mpoint_t *mntpoint;
244 int ret = SYSINFO_RET_FAIL;
245 char *mpoint;
246
247 if (0 == (rc = getmntinfo(&mntbuf, MNT_WAIT)))
248 {
249 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
250 return SYSINFO_RET_FAIL;
251 }
252
253 zbx_vector_ptr_create(&mntpoints);
254
255 for (i = 0; i < rc; i++)
256 {
257 mpoint = mntbuf[i].f_mntonname;
258 if (SYSINFO_RET_OK != get_fs_size_stat(mpoint, &total, ¬_used, &used, &pfree, &pused,&error))
259 {
260 zbx_free(error);
261 continue;
262 }
263 if (SYSINFO_RET_OK != get_fs_inode_stat(mpoint, &itotal, &inot_used, &iused, &ipfree, &ipused, "pused",
264 &error))
265 {
266 zbx_free(error);
267 continue;
268 }
269
270 mntpoint = (zbx_mpoint_t *)zbx_malloc(NULL, sizeof(zbx_mpoint_t));
271 zbx_strlcpy(mntpoint->fsname, mpoint, MAX_STRING_LEN);
272 zbx_strlcpy(mntpoint->fstype, mntbuf[i].f_fstypename, MAX_STRING_LEN);
273 mntpoint->bytes.total = total;
274 mntpoint->bytes.used = used;
275 mntpoint->bytes.not_used = not_used;
276 mntpoint->bytes.pfree = pfree;
277 mntpoint->bytes.pused = pused;
278 mntpoint->inodes.total = itotal;
279 mntpoint->inodes.used = iused;
280 mntpoint->inodes.not_used = inot_used;
281 mntpoint->inodes.pfree = ipfree;
282 mntpoint->inodes.pused = ipused;
283
284 zbx_vector_ptr_append(&mntpoints, mntpoint);
285 }
286
287 if (0 == (rc = getmntinfo(&mntbuf, MNT_WAIT)))
288 {
289 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
290 goto out;
291 }
292 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
293
294 for (i = 0; i < rc; i++)
295 {
296 int idx;
297 mpoint = mntbuf[i].f_mntonname;
298
299 if (FAIL != (idx = zbx_vector_ptr_search(&mntpoints, mpoint, ZBX_DEFAULT_STR_COMPARE_FUNC)))
300 {
301 mntpoint = (zbx_mpoint_t *)mntpoints.values[idx];
302 zbx_json_addobject(&j, NULL);
303 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSNAME, mntpoint->fsname, ZBX_JSON_TYPE_STRING);
304 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSTYPE, mntpoint->fstype, ZBX_JSON_TYPE_STRING);
305 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_BYTES);
306 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->bytes.total);
307 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->bytes.not_used);
308 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->bytes.used);
309 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->bytes.pfree);
310 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->bytes.pused);
311 zbx_json_close(&j);
312 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_INODES);
313 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->inodes.total);
314 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->inodes.not_used);
315 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->inodes.used);
316 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->inodes.pfree);
317 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->inodes.pused);
318 zbx_json_close(&j);
319 zbx_json_close(&j);
320 }
321 }
322
323 zbx_json_close(&j);
324
325 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
326
327 zbx_json_free(&j);
328 ret = SYSINFO_RET_OK;
329 out:
330 zbx_vector_ptr_clear_ext(&mntpoints, (zbx_clean_func_t)zbx_mpoints_free);
331 zbx_vector_ptr_destroy(&mntpoints);
332
333 return ret;
334 }
335
VFS_FS_GET(AGENT_REQUEST * request,AGENT_RESULT * result)336 int VFS_FS_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
337 {
338 return zbx_execute_threaded_metric(vfs_fs_get, request, result);
339
340 }
341