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