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