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 
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)25 static int	get_fs_size_stat(const char *fs, zbx_uint64_t *total, zbx_uint64_t *free,
26 		zbx_uint64_t *used, double *pfree, double *pused, char **error)
27 {
28 #ifdef HAVE_SYS_STATVFS_H
29 #	ifdef HAVE_SYS_STATVFS64
30 #		define ZBX_STATFS	statvfs64
31 #	else
32 #		define ZBX_STATFS	statvfs
33 #	endif
34 #	define ZBX_BSIZE	f_frsize
35 #else
36 #	define ZBX_STATFS	statfs
37 #	define ZBX_BSIZE	f_bsize
38 #endif
39 	struct ZBX_STATFS	s;
40 
41 	if (0 != ZBX_STATFS(fs, &s))
42 	{
43 		*error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno));
44 		return SYSINFO_RET_FAIL;
45 	}
46 
47 	/* Available space could be negative (top bit set) if we hit disk space */
48 	/* reserved for non-privileged users. Treat it as 0.                    */
49 	if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail))
50 		s.f_bavail = 0;
51 
52 	if (NULL != total)
53 		*total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE;
54 
55 	if (NULL != free)
56 		*free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE;
57 
58 	if (NULL != used)
59 		*used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE;
60 
61 	if (NULL != pfree)
62 	{
63 		if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
64 			*pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
65 		else
66 			*pfree = 0;
67 	}
68 
69 	if (NULL != pused)
70 	{
71 		if (0 != s.f_blocks - s.f_bfree + s.f_bavail)
72 			*pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail);
73 		else
74 			*pused = 0;
75 	}
76 
77 	return SYSINFO_RET_OK;
78 }
79 
VFS_FS_USED(const char * fs,AGENT_RESULT * result)80 static int	VFS_FS_USED(const char *fs, AGENT_RESULT *result)
81 {
82 	zbx_uint64_t	value;
83 	char		*error;
84 
85 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, &value, NULL, NULL, &error))
86 	{
87 		SET_MSG_RESULT(result, error);
88 		return SYSINFO_RET_FAIL;
89 	}
90 
91 	SET_UI64_RESULT(result, value);
92 
93 	return SYSINFO_RET_OK;
94 }
95 
VFS_FS_FREE(const char * fs,AGENT_RESULT * result)96 static int	VFS_FS_FREE(const char *fs, AGENT_RESULT *result)
97 {
98 	zbx_uint64_t	value;
99 	char		*error;
100 
101 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, &value, NULL, NULL, NULL, &error))
102 	{
103 		SET_MSG_RESULT(result, error);
104 		return SYSINFO_RET_FAIL;
105 	}
106 
107 	SET_UI64_RESULT(result, value);
108 
109 	return SYSINFO_RET_OK;
110 }
111 
VFS_FS_TOTAL(const char * fs,AGENT_RESULT * result)112 static int	VFS_FS_TOTAL(const char *fs, AGENT_RESULT *result)
113 {
114 	zbx_uint64_t	value;
115 	char		*error;
116 
117 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, &value, NULL, NULL, NULL, NULL, &error))
118 	{
119 		SET_MSG_RESULT(result, error);
120 		return SYSINFO_RET_FAIL;
121 	}
122 
123 	SET_UI64_RESULT(result, value);
124 
125 	return SYSINFO_RET_OK;
126 }
127 
VFS_FS_PFREE(const char * fs,AGENT_RESULT * result)128 static int	VFS_FS_PFREE(const char *fs, AGENT_RESULT *result)
129 {
130 	double	value;
131 	char	*error;
132 
133 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, &value, NULL, &error))
134 	{
135 		SET_MSG_RESULT(result, error);
136 		return SYSINFO_RET_FAIL;
137 	}
138 
139 	SET_DBL_RESULT(result, value);
140 
141 	return SYSINFO_RET_OK;
142 }
143 
VFS_FS_PUSED(const char * fs,AGENT_RESULT * result)144 static int	VFS_FS_PUSED(const char *fs, AGENT_RESULT *result)
145 {
146 	double	value;
147 	char	*error;
148 
149 	if (SYSINFO_RET_OK != get_fs_size_stat(fs, NULL, NULL, NULL, NULL, &value, &error))
150 	{
151 		SET_MSG_RESULT(result, error);
152 		return SYSINFO_RET_FAIL;
153 	}
154 
155 	SET_DBL_RESULT(result, value);
156 
157 	return SYSINFO_RET_OK;
158 }
159 
vfs_fs_size(AGENT_REQUEST * request,AGENT_RESULT * result)160 static int	vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result)
161 {
162 	char	*fsname, *mode;
163 
164 	if (2 < request->nparam)
165 	{
166 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
167 		return SYSINFO_RET_FAIL;
168 	}
169 
170 	fsname = get_rparam(request, 0);
171 	mode = get_rparam(request, 1);
172 
173 	if (NULL == fsname || '\0' == *fsname)
174 	{
175 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
176 		return SYSINFO_RET_FAIL;
177 	}
178 
179 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total"))	/* default parameter */
180 		return VFS_FS_TOTAL(fsname, result);
181 	if (0 == strcmp(mode, "free"))
182 		return VFS_FS_FREE(fsname, result);
183 	if (0 == strcmp(mode, "pfree"))
184 		return VFS_FS_PFREE(fsname, result);
185 	if (0 == strcmp(mode, "used"))
186 		return VFS_FS_USED(fsname, result);
187 	if (0 == strcmp(mode, "pused"))
188 		return VFS_FS_PUSED(fsname, result);
189 
190 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
191 
192 	return SYSINFO_RET_FAIL;
193 }
194 
VFS_FS_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)195 int	VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
196 {
197 	return zbx_execute_threaded_metric(vfs_fs_size, request, result);
198 }
199 
VFS_FS_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)200 int	VFS_FS_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
201 {
202 	struct mnttab	mt;
203 	FILE		*f;
204 	struct zbx_json	j;
205 
206 	/* opening the mounted filesystems file */
207 	if (NULL == (f = fopen("/etc/mnttab", "r")))
208 	{
209 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /etc/mnttab: %s", zbx_strerror(errno)));
210 		return SYSINFO_RET_FAIL;
211 	}
212 
213 	zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
214 
215 	zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
216 
217 	/* fill mnttab structure from file */
218 	while (-1 != getmntent(f, &mt))
219 	{
220 		zbx_json_addobject(&j, NULL);
221 		zbx_json_addstring(&j, "{#FSNAME}", mt.mnt_mountp, ZBX_JSON_TYPE_STRING);
222 		zbx_json_addstring(&j, "{#FSTYPE}", mt.mnt_fstype, ZBX_JSON_TYPE_STRING);
223 		zbx_json_close(&j);
224 	}
225 
226 	zbx_fclose(f);
227 
228 	zbx_json_close(&j);
229 
230 	SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer));
231 
232 	zbx_json_free(&j);
233 
234 	return SYSINFO_RET_OK;
235 }
236