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