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 "log.h"
23 
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)24 static int	get_fs_size_stat(const char *fs, zbx_uint64_t *total, zbx_uint64_t *free,
25 		zbx_uint64_t *used, double *pfree, double *pused, char **error)
26 {
27 #ifdef HAVE_SYS_STATVFS_H
28 #	define ZBX_STATFS	statvfs
29 #	define ZBX_BSIZE	f_frsize
30 #else
31 #	define ZBX_STATFS	statfs
32 #	define ZBX_BSIZE	f_bsize
33 #endif
34 	struct ZBX_STATFS	s;
35 
36 	if (0 != ZBX_STATFS(fs, &s))
37 	{
38 		*error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno));
39 		return SYSINFO_RET_FAIL;
40 	}
41 
42 	/* Available space could be negative (top bit set) if we hit disk space */
43 	/* reserved for non-privileged users. Treat it as 0.                    */
44 	if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail))
45 		s.f_bavail = 0;
46 
47 	if (NULL != total)
48 		*total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE;
49 
50 	if (NULL != free)
51 		*free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE;
52 
53 	if (NULL != used)
54 		*used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE;
55 
56 	if (NULL != pfree)
57 	{
58 		if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
59 			*pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
60 		else
61 			*pfree = 0;
62 	}
63 
64 	if (NULL != pused)
65 	{
66 		if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
67 			*pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
68 		else
69 			*pused = 0;
70 	}
71 
72 	return SYSINFO_RET_OK;
73 }
74 
VFS_FS_USED(const char * fs,AGENT_RESULT * result)75 static int	VFS_FS_USED(const char *fs, AGENT_RESULT *result)
76 {
77 	zbx_uint64_t	value;
78 	char		*error;
79 
80 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, &value, NULL, NULL, &error))
81 	{
82 		SET_MSG_RESULT(result, error);
83 		return SYSINFO_RET_FAIL;
84 	}
85 
86 	SET_UI64_RESULT(result, value);
87 
88 	return SYSINFO_RET_OK;
89 }
90 
VFS_FS_FREE(const char * fs,AGENT_RESULT * result)91 static int	VFS_FS_FREE(const char *fs, AGENT_RESULT *result)
92 {
93 	zbx_uint64_t	value;
94 	char		*error;
95 
96 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, &value, NULL, NULL, NULL, &error))
97 	{
98 		SET_MSG_RESULT(result, error);
99 		return SYSINFO_RET_FAIL;
100 	}
101 
102 	SET_UI64_RESULT(result, value);
103 
104 	return SYSINFO_RET_OK;
105 }
106 
VFS_FS_TOTAL(const char * fs,AGENT_RESULT * result)107 static int	VFS_FS_TOTAL(const char *fs, AGENT_RESULT *result)
108 {
109 	zbx_uint64_t	value;
110 	char		*error;
111 
112 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, &value, NULL, NULL, NULL, NULL, &error))
113 	{
114 		SET_MSG_RESULT(result, error);
115 		return SYSINFO_RET_FAIL;
116 	}
117 
118 	SET_UI64_RESULT(result, value);
119 
120 	return SYSINFO_RET_OK;
121 }
122 
VFS_FS_PFREE(const char * fs,AGENT_RESULT * result)123 static int	VFS_FS_PFREE(const char *fs, AGENT_RESULT *result)
124 {
125 	double	value;
126 	char	*error;
127 
128 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, &value, NULL, &error))
129 	{
130 		SET_MSG_RESULT(result, error);
131 		return SYSINFO_RET_FAIL;
132 	}
133 
134 	SET_DBL_RESULT(result, value);
135 
136 	return SYSINFO_RET_OK;
137 }
138 
VFS_FS_PUSED(const char * fs,AGENT_RESULT * result)139 static int	VFS_FS_PUSED(const char *fs, AGENT_RESULT *result)
140 {
141 	double	value;
142 	char	*error;
143 
144 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, NULL, &value, &error))
145 	{
146 		SET_MSG_RESULT(result, error);
147 		return SYSINFO_RET_FAIL;
148 	}
149 
150 	SET_DBL_RESULT(result, value);
151 
152 	return SYSINFO_RET_OK;
153 }
154 
vfs_fs_size(AGENT_REQUEST * request,AGENT_RESULT * result)155 static int	vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result)
156 {
157 	char	*fsname, *mode;
158 
159 	if (2 < request->nparam)
160 	{
161 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
162 		return SYSINFO_RET_FAIL;
163 	}
164 
165 	fsname = get_rparam(request, 0);
166 	mode = get_rparam(request, 1);
167 
168 	if (NULL == fsname || '\0' == *fsname)
169 	{
170 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
171 		return SYSINFO_RET_FAIL;
172 	}
173 
174 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total"))	/* default parameter */
175 		return VFS_FS_TOTAL(fsname, result);
176 	if (0 == strcmp(mode, "free"))
177 		return VFS_FS_FREE(fsname, result);
178 	if (0 == strcmp(mode, "pfree"))
179 		return VFS_FS_PFREE(fsname, result);
180 	if (0 == strcmp(mode, "used"))
181 		return VFS_FS_USED(fsname, result);
182 	if (0 == strcmp(mode, "pused"))
183 		return VFS_FS_PUSED(fsname, result);
184 
185 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
186 
187 	return SYSINFO_RET_FAIL;
188 }
189 
VFS_FS_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)190 int	VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
191 {
192 	return zbx_execute_threaded_metric(vfs_fs_size, request, result);
193 }
194