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 "proc.h"
23 #include "log.h"
24 
VM_MEMORY_TOTAL(AGENT_RESULT * result)25 static int	VM_MEMORY_TOTAL(AGENT_RESULT *result)
26 {
27 	struct sysinfo	info;
28 
29 	if (0 != sysinfo(&info))
30 	{
31 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
32 		return SYSINFO_RET_FAIL;
33 	}
34 
35 	SET_UI64_RESULT(result, (zbx_uint64_t)info.totalram * info.mem_unit);
36 
37 	return SYSINFO_RET_OK;
38 }
39 
VM_MEMORY_FREE(AGENT_RESULT * result)40 static int	VM_MEMORY_FREE(AGENT_RESULT *result)
41 {
42 	struct sysinfo	info;
43 
44 	if (0 != sysinfo(&info))
45 	{
46 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
47 		return SYSINFO_RET_FAIL;
48 	}
49 
50 	SET_UI64_RESULT(result, (zbx_uint64_t)info.freeram * info.mem_unit);
51 
52 	return SYSINFO_RET_OK;
53 }
54 
VM_MEMORY_BUFFERS(AGENT_RESULT * result)55 static int	VM_MEMORY_BUFFERS(AGENT_RESULT *result)
56 {
57 	struct sysinfo	info;
58 
59 	if (0 != sysinfo(&info))
60 	{
61 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
62 		return SYSINFO_RET_FAIL;
63 	}
64 
65 	SET_UI64_RESULT(result, (zbx_uint64_t)info.bufferram * info.mem_unit);
66 
67 	return SYSINFO_RET_OK;
68 }
69 
VM_MEMORY_CACHED(AGENT_RESULT * result)70 static int	VM_MEMORY_CACHED(AGENT_RESULT *result)
71 {
72 	FILE		*f;
73 	zbx_uint64_t	value;
74 	int		res;
75 
76 	if (NULL == (f = fopen("/proc/meminfo", "r")))
77 	{
78 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/meminfo: %s", zbx_strerror(errno)));
79 		return SYSINFO_RET_FAIL;
80 	}
81 
82 	if (FAIL == (res = byte_value_from_proc_file(f, "Cached:", NULL, &value)))
83 	{
84 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain the value of Cached from /proc/meminfo."));
85 		goto close;
86 	}
87 
88 	if (NOTSUPPORTED == res)
89 		value = 0;
90 close:
91 	zbx_fclose(f);
92 
93 	SET_UI64_RESULT(result, value);
94 
95 	return SYSINFO_RET_OK;
96 }
97 
VM_MEMORY_USED(AGENT_RESULT * result)98 static int	VM_MEMORY_USED(AGENT_RESULT *result)
99 {
100 	struct sysinfo	info;
101 
102 	if (0 != sysinfo(&info))
103 	{
104 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
105 		return SYSINFO_RET_FAIL;
106 	}
107 
108 	SET_UI64_RESULT(result, (zbx_uint64_t)(info.totalram - info.freeram) * info.mem_unit);
109 
110 	return SYSINFO_RET_OK;
111 }
112 
VM_MEMORY_PUSED(AGENT_RESULT * result)113 static int	VM_MEMORY_PUSED(AGENT_RESULT *result)
114 {
115 	struct sysinfo	info;
116 
117 	if (0 != sysinfo(&info))
118 	{
119 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
120 		return SYSINFO_RET_FAIL;
121 	}
122 
123 	if (0 == info.totalram)
124 	{
125 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot calculate percentage because total is zero."));
126 		return SYSINFO_RET_FAIL;
127 	}
128 
129 	SET_DBL_RESULT(result, (info.totalram - info.freeram) / (double)info.totalram * 100);
130 
131 	return SYSINFO_RET_OK;
132 }
133 
VM_MEMORY_AVAILABLE(AGENT_RESULT * result)134 static int	VM_MEMORY_AVAILABLE(AGENT_RESULT *result)
135 {
136 	FILE		*f;
137 	zbx_uint64_t	value;
138 	struct sysinfo	info;
139 	int		res, ret = SYSINFO_RET_FAIL;
140 
141 	/* try MemAvailable (present since Linux 3.14), falling back to a calculation based on sysinfo() and Cached */
142 
143 	if (NULL == (f = fopen("/proc/meminfo", "r")))
144 	{
145 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/meminfo: %s", zbx_strerror(errno)));
146 		return SYSINFO_RET_FAIL;
147 	}
148 
149 	if (FAIL == (res = byte_value_from_proc_file(f, "MemAvailable:", "Cached:", &value)))
150 	{
151 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain the value of MemAvailable from /proc/meminfo."));
152 		goto close;
153 	}
154 
155 	if (SUCCEED == res)
156 	{
157 		SET_UI64_RESULT(result, value);
158 		ret = SYSINFO_RET_OK;
159 		goto close;
160 	}
161 
162 	if (FAIL == (res = byte_value_from_proc_file(f, "Cached:", NULL, &value)))
163 	{
164 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain the value of Cached from /proc/meminfo."));
165 		goto close;
166 	}
167 
168 	if (NOTSUPPORTED == res)
169 		value = 0;
170 
171 	if (0 != sysinfo(&info))
172 	{
173 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
174 		goto close;
175 	}
176 
177 	SET_UI64_RESULT(result, (zbx_uint64_t)(info.freeram + info.bufferram) * info.mem_unit + value);
178 	ret = SYSINFO_RET_OK;
179 close:
180 	zbx_fclose(f);
181 
182 	return ret;
183 }
184 
VM_MEMORY_PAVAILABLE(AGENT_RESULT * result)185 static int	VM_MEMORY_PAVAILABLE(AGENT_RESULT *result)
186 {
187 	struct sysinfo	info;
188 	AGENT_RESULT	result_tmp;
189 	zbx_uint64_t	available, total;
190 	int		ret = SYSINFO_RET_FAIL;
191 
192 	if (0 != sysinfo(&info))
193 	{
194 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
195 		return SYSINFO_RET_FAIL;
196 	}
197 
198 	init_result(&result_tmp);
199 
200 	ret = VM_MEMORY_AVAILABLE(&result_tmp);
201 
202 	if (SYSINFO_RET_FAIL == ret)
203 	{
204 		SET_MSG_RESULT(result, zbx_strdup(NULL, result_tmp.msg));
205 		goto clean;
206 	}
207 
208 	available = result_tmp.ui64;
209 	total = (zbx_uint64_t)info.totalram * info.mem_unit;
210 
211 	if (0 == total)
212 	{
213 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot calculate percentage because total is zero."));
214 		ret = SYSINFO_RET_FAIL;
215 		goto clean;
216 	}
217 
218 	SET_DBL_RESULT(result, available / (double)total * 100);
219 clean:
220 	free_result(&result_tmp);
221 
222 	return ret;
223 }
224 
VM_MEMORY_SHARED(AGENT_RESULT * result)225 static int	VM_MEMORY_SHARED(AGENT_RESULT *result)
226 {
227 #ifdef KERNEL_2_4
228 	struct sysinfo	info;
229 
230 	if (0 != sysinfo(&info))
231 	{
232 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)));
233 		return SYSINFO_RET_FAIL;
234 	}
235 
236 	SET_UI64_RESULT(result, (zbx_uint64_t)info.sharedram * info.mem_unit);
237 
238 	return SYSINFO_RET_OK;
239 #else
240 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Supported for Linux 2.4 only."));
241 	return SYSINFO_RET_FAIL;
242 #endif
243 }
244 
VM_MEMORY_SIZE(AGENT_REQUEST * request,AGENT_RESULT * result)245 int	VM_MEMORY_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result)
246 {
247 	char	*mode;
248 	int	ret = SYSINFO_RET_FAIL;
249 
250 	if (1 < request->nparam)
251 	{
252 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
253 		return SYSINFO_RET_FAIL;
254 	}
255 
256 	mode = get_rparam(request, 0);
257 
258 	if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total"))
259 		ret = VM_MEMORY_TOTAL(result);
260 	else if (0 == strcmp(mode, "free"))
261 		ret = VM_MEMORY_FREE(result);
262 	else if (0 == strcmp(mode, "buffers"))
263 		ret = VM_MEMORY_BUFFERS(result);
264 	else if (0 == strcmp(mode, "cached"))
265 		ret = VM_MEMORY_CACHED(result);
266 	else if (0 == strcmp(mode, "used"))
267 		ret = VM_MEMORY_USED(result);
268 	else if (0 == strcmp(mode, "pused"))
269 		ret = VM_MEMORY_PUSED(result);
270 	else if (0 == strcmp(mode, "available"))
271 		ret = VM_MEMORY_AVAILABLE(result);
272 	else if (0 == strcmp(mode, "pavailable"))
273 		ret = VM_MEMORY_PAVAILABLE(result);
274 	else if (0 == strcmp(mode, "shared"))
275 		ret = VM_MEMORY_SHARED(result);
276 	else
277 	{
278 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
279 		ret = SYSINFO_RET_FAIL;
280 	}
281 
282 	return ret;
283 }
284