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 	struct mntent	*mt;
202 	FILE		*f;
203 	struct zbx_json	j;
204 
205 	/* opening the mounted filesystems file */
206 	if (NULL == (f = setmntent(MNT_MNTTAB, "r")))
207 	{
208 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
209 		return SYSINFO_RET_FAIL;
210 	}
211 
212 	zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
213 
214 	/* fill mnttab structure from file */
215 	while (NULL != (mt = getmntent(f)))
216 	{
217 		zbx_json_addobject(&j, NULL);
218 		zbx_json_addstring(&j, ZBX_LLD_MACRO_FSNAME, mt->mnt_dir, ZBX_JSON_TYPE_STRING);
219 		zbx_json_addstring(&j, ZBX_LLD_MACRO_FSTYPE, mt->mnt_type, ZBX_JSON_TYPE_STRING);
220 		zbx_json_close(&j);
221 	}
222 
223 	endmntent(f);
224 
225 	zbx_json_close(&j);
226 
227 	SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
228 
229 	zbx_json_free(&j);
230 
231 	return SYSINFO_RET_OK;
232 }
233 
vfs_fs_get(AGENT_REQUEST * request,AGENT_RESULT * result)234 static int	vfs_fs_get(AGENT_REQUEST *request, AGENT_RESULT *result)
235 {
236 	struct mntent		*mt;
237 	FILE			*f;
238 	struct zbx_json		j;
239 	zbx_uint64_t		total, not_used, used;
240 	zbx_uint64_t		itotal, inot_used, iused;
241 	double			pfree, pused;
242 	double			ipfree, ipused;
243 	char 			*error;
244 	zbx_vector_ptr_t	mntpoints;
245 	zbx_mpoint_t		*mntpoint;
246 	char 			*mpoint;
247 	int			ret = SYSINFO_RET_FAIL;
248 
249 	/* opening the mounted filesystems file */
250 	if (NULL == (f = setmntent(MNT_MNTTAB, "r")))
251 	{
252 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
253 		return SYSINFO_RET_FAIL;
254 	}
255 
256 	zbx_vector_ptr_create(&mntpoints);
257 
258 	/* fill mnttab structure from file */
259 	while (NULL != (mt = getmntent(f)))
260 	{
261 		mpoint = mt->mnt_dir;
262 		if (SYSINFO_RET_OK != get_fs_size_stat(mpoint, &total, &not_used, &used, &pfree, &pused, &error))
263 		{
264 			zbx_free(error);
265 			continue;
266 		}
267 		if (SYSINFO_RET_OK != get_fs_inode_stat(mpoint, &itotal, &inot_used, &iused, &ipfree, &ipused, "pused",
268 				&error))
269 		{
270 			zbx_free(error);
271 			continue;
272 		}
273 
274 		mntpoint = (zbx_mpoint_t *)zbx_malloc(NULL, sizeof(zbx_mpoint_t));
275 		zbx_strlcpy(mntpoint->fsname, mpoint, MAX_STRING_LEN);
276 		zbx_strlcpy(mntpoint->fstype, mt->mnt_type, MAX_STRING_LEN);
277 		mntpoint->bytes.total = total;
278 		mntpoint->bytes.used = used;
279 		mntpoint->bytes.not_used = not_used;
280 		mntpoint->bytes.pfree = pfree;
281 		mntpoint->bytes.pused = pused;
282 		mntpoint->inodes.total = itotal;
283 		mntpoint->inodes.used = iused;
284 		mntpoint->inodes.not_used = inot_used;
285 		mntpoint->inodes.pfree = ipfree;
286 		mntpoint->inodes.pused = ipused;
287 
288 		zbx_vector_ptr_append(&mntpoints, mntpoint);
289 	}
290 
291 	endmntent(f);
292 
293 	if (NULL == (f = setmntent(MNT_MNTTAB, "r")))
294 	{
295 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
296 		goto out;
297 	}
298 
299 	zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
300 
301 	while (NULL != (mt = getmntent(f)))
302 	{
303 		int idx;
304 
305 		mpoint = mt->mnt_dir;
306 
307 		if (FAIL != (idx = zbx_vector_ptr_search(&mntpoints, mpoint, ZBX_DEFAULT_STR_COMPARE_FUNC)))
308 		{
309 			mntpoint = (zbx_mpoint_t *)mntpoints.values[idx];
310 			zbx_json_addobject(&j, NULL);
311 			zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSNAME, mntpoint->fsname, ZBX_JSON_TYPE_STRING);
312 			zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSTYPE, mntpoint->fstype, ZBX_JSON_TYPE_STRING);
313 			zbx_json_addobject(&j, ZBX_SYSINFO_TAG_BYTES);
314 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->bytes.total);
315 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->bytes.not_used);
316 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->bytes.used);
317 			zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->bytes.pfree);
318 			zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->bytes.pused);
319 			zbx_json_close(&j);
320 			zbx_json_addobject(&j, ZBX_SYSINFO_TAG_INODES);
321 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->inodes.total);
322 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->inodes.not_used);
323 			zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->inodes.used);
324 			zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->inodes.pfree);
325 			zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->inodes.pused);
326 			zbx_json_close(&j);
327 			zbx_json_close(&j);
328 		}
329 	}
330 
331 	endmntent(f);
332 
333 	zbx_json_close(&j);
334 
335 	SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
336 
337 	zbx_json_free(&j);
338 
339 	ret = SYSINFO_RET_OK;
340 out:
341 	zbx_vector_ptr_clear_ext(&mntpoints, (zbx_clean_func_t)zbx_mpoints_free);
342 	zbx_vector_ptr_destroy(&mntpoints);
343 
344 	return ret;
345 }
346 
VFS_FS_GET(AGENT_REQUEST * request,AGENT_RESULT * result)347 int	VFS_FS_GET(AGENT_REQUEST *request, AGENT_RESULT *result)
348 {
349 	return zbx_execute_threaded_metric(vfs_fs_get, request, result);
350 
351 }
352 
353