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 "stats.h"
23 #include "log.h"
24 
SYSTEM_CPU_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)25 int	SYSTEM_CPU_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
26 {
27 	char	*tmp;
28 	int	name;
29 	long	ncpu;
30 
31 	if (1 < request->nparam)
32 	{
33 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
34 		return SYSINFO_RET_FAIL;
35 	}
36 
37 	tmp = get_rparam(request, 0);
38 
39 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "online"))
40 		name = _SC_NPROCESSORS_ONLN;
41 	else if (0 == strcmp(tmp, "max"))
42 		name = _SC_NPROCESSORS_CONF;
43 	else
44 	{
45 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
46 		return SYSINFO_RET_FAIL;
47 	}
48 
49 	if (-1 == (ncpu = sysconf(name)))
50 	{
51 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain number of CPUs."));
52 		return SYSINFO_RET_FAIL;
53 	}
54 
55 	SET_UI64_RESULT(result, ncpu);
56 
57 	return SYSINFO_RET_OK;
58 }
59 
SYSTEM_CPU_UTIL(AGENT_REQUEST * request,AGENT_RESULT * result)60 int	SYSTEM_CPU_UTIL(AGENT_REQUEST *request, AGENT_RESULT *result)
61 {
62 	char	*tmp;
63 	int	cpu_num, state, mode;
64 
65 	if (3 < request->nparam)
66 	{
67 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
68 		return SYSINFO_RET_FAIL;
69 	}
70 
71 	tmp = get_rparam(request, 0);
72 
73 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "all"))
74 		cpu_num = ZBX_CPUNUM_ALL;
75 	else if (SUCCEED != is_uint31_1(tmp, &cpu_num))
76 	{
77 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
78 		return SYSINFO_RET_FAIL;
79 	}
80 
81 	tmp = get_rparam(request, 1);
82 
83 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "user"))
84 		state = ZBX_CPU_STATE_USER;
85 	else if (0 == strcmp(tmp, "iowait"))
86 		state = ZBX_CPU_STATE_IOWAIT;
87 	else if (0 == strcmp(tmp, "system"))
88 		state = ZBX_CPU_STATE_SYSTEM;
89 	else if (0 == strcmp(tmp, "idle"))
90 		state = ZBX_CPU_STATE_IDLE;
91 	else
92 	{
93 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
94 		return SYSINFO_RET_FAIL;
95 	}
96 
97 	tmp = get_rparam(request, 2);
98 
99 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "avg1"))
100 		mode = ZBX_AVG1;
101 	else if (0 == strcmp(tmp, "avg5"))
102 		mode = ZBX_AVG5;
103 	else if (0 == strcmp(tmp, "avg15"))
104 		mode = ZBX_AVG15;
105 	else
106 	{
107 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
108 		return SYSINFO_RET_FAIL;
109 	}
110 
111 	return get_cpustat(result, cpu_num, state, mode);
112 }
113 
114 #if defined(HAVE_KSTAT_H) && !defined(HAVE_GETLOADAVG)
get_kstat_system_misc(char * key,int * value,char ** error)115 static int	get_kstat_system_misc(char *key, int *value, char **error)
116 {
117 	kstat_ctl_t	*kc;
118 	kstat_t		*ksp;
119 	kstat_named_t	*kn = NULL;
120 	int		ret = FAIL;
121 
122 	if (NULL == (kc = kstat_open()))
123 	{
124 		*error = zbx_dsprintf(NULL, "Cannot open kernel statistics facility: %s", zbx_strerror(errno));
125 		return ret;
126 	}
127 
128 	if (NULL == (ksp = kstat_lookup(kc, "unix", 0, "system_misc")))
129 	{
130 		*error = zbx_dsprintf(NULL, "Cannot look up in kernel statistics facility: %s", zbx_strerror(errno));
131 		goto close;
132 	}
133 
134 	if (-1 == kstat_read(kc, ksp, NULL))
135 	{
136 		*error = zbx_dsprintf(NULL, "Cannot read from kernel statistics facility: %s", zbx_strerror(errno));
137 		goto close;
138 	}
139 
140 	if (NULL == (kn = (kstat_named_t *)kstat_data_lookup(ksp, key)))
141 	{
142 		*error = zbx_dsprintf(NULL, "Cannot look up data in kernel statistics facility: %s",
143 				zbx_strerror(errno));
144 		goto close;
145 	}
146 
147 	*value = get_kstat_numeric_value(kn);
148 
149 	ret = SUCCEED;
150 close:
151 	kstat_close(kc);
152 
153 	return ret;
154 }
155 #endif
156 
SYSTEM_CPU_LOAD(AGENT_REQUEST * request,AGENT_RESULT * result)157 int	SYSTEM_CPU_LOAD(AGENT_REQUEST *request, AGENT_RESULT *result)
158 {
159 	char	*tmp;
160 	double	value;
161 	int	per_cpu = 1, cpu_num;
162 #if defined(HAVE_GETLOADAVG)
163 	int	mode;
164 	double	load[ZBX_AVG_COUNT];
165 #elif defined(HAVE_KSTAT_H)
166 	char	*key, *error;
167 	int	load;
168 #endif
169 	if (2 < request->nparam)
170 	{
171 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
172 		return SYSINFO_RET_FAIL;
173 	}
174 
175 	tmp = get_rparam(request, 0);
176 
177 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "all"))
178 		per_cpu = 0;
179 	else if (0 != strcmp(tmp, "percpu"))
180 	{
181 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter."));
182 		return SYSINFO_RET_FAIL;
183 	}
184 
185 #if defined(HAVE_GETLOADAVG)
186 	tmp = get_rparam(request, 1);
187 
188 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "avg1"))
189 		mode = ZBX_AVG1;
190 	else if (0 == strcmp(tmp, "avg5"))
191 		mode = ZBX_AVG5;
192 	else if (0 == strcmp(tmp, "avg15"))
193 		mode = ZBX_AVG15;
194 	else
195 	{
196 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
197 		return SYSINFO_RET_FAIL;
198 	}
199 
200 	if (mode >= getloadavg(load, 3))
201 	{
202 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain load average: %s", zbx_strerror(errno)));
203 		return SYSINFO_RET_FAIL;
204 	}
205 
206 	value = load[mode];
207 #elif defined(HAVE_KSTAT_H)
208 	tmp = get_rparam(request, 1);
209 
210 	if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "avg1"))
211 		key = "avenrun_1min";
212 	else if (0 == strcmp(tmp, "avg5"))
213 		key = "avenrun_5min";
214 	else if (0 == strcmp(tmp, "avg15"))
215 		key = "avenrun_15min";
216 	else
217 	{
218 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
219 		return SYSINFO_RET_FAIL;
220 	}
221 
222 	if (FAIL == get_kstat_system_misc(key, &load, &error))
223 	{
224 		SET_MSG_RESULT(result, error);
225 		return SYSINFO_RET_FAIL;
226 	}
227 
228 	value = (double)load / FSCALE;
229 #else
230 	SET_MSG_RESULT(result, zbx_strdup(NULL, "Agent was compiled without support for CPU load information."));
231 	return SYSINFO_RET_FAIL;
232 #endif
233 	if (1 == per_cpu)
234 	{
235 		if (0 >= (cpu_num = sysconf(_SC_NPROCESSORS_ONLN)))
236 		{
237 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain number of CPUs."));
238 			return SYSINFO_RET_FAIL;
239 		}
240 		value /= cpu_num;
241 	}
242 
243 	SET_DBL_RESULT(result, value);
244 
245 	return SYSINFO_RET_OK;
246 }
247 
SYSTEM_CPU_SWITCHES(AGENT_REQUEST * request,AGENT_RESULT * result)248 int	SYSTEM_CPU_SWITCHES(AGENT_REQUEST *request, AGENT_RESULT *result)
249 {
250 	kstat_ctl_t	*kc;
251 	kstat_t		*k;
252 	cpu_stat_t	*cpu;
253 	int		cpu_count = 0;
254 	double		swt_count = 0.0;
255 
256 	if (NULL == (kc = kstat_open()))
257 	{
258 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open kernel statistics facility: %s",
259 				zbx_strerror(errno)));
260 		return SYSINFO_RET_FAIL;
261 	}
262 
263 	k = kc->kc_chain;
264 
265 	while (NULL != k)
266 	{
267 		if (0 == strncmp(k->ks_name, "cpu_stat", 8) && -1 != kstat_read(kc, k, NULL))
268 		{
269 			cpu = (cpu_stat_t *)k->ks_data;
270 			swt_count += (double)cpu->cpu_sysinfo.pswitch;
271 			cpu_count += 1;
272 		}
273 
274 		k = k->ks_next;
275 	}
276 
277 	kstat_close(kc);
278 
279 	if (0 == cpu_count)
280 	{
281 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find CPU information."));
282 		return SYSINFO_RET_FAIL;
283 	}
284 
285 	SET_UI64_RESULT(result, swt_count);
286 
287 	return SYSINFO_RET_OK;
288 }
289 
SYSTEM_CPU_INTR(AGENT_REQUEST * request,AGENT_RESULT * result)290 int	SYSTEM_CPU_INTR(AGENT_REQUEST *request, AGENT_RESULT *result)
291 {
292 	kstat_ctl_t	*kc;
293 	kstat_t		*k;
294 	cpu_stat_t	*cpu;
295 	int		cpu_count = 0;
296 	double		intr_count = 0.0;
297 
298 	if (NULL == (kc = kstat_open()))
299 	{
300 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open kernel statistics facility: %s",
301 				zbx_strerror(errno)));
302 		return SYSINFO_RET_FAIL;
303 	}
304 
305 	k = kc->kc_chain;
306 
307 	while (NULL != k)
308 	{
309 		if (0 == strncmp(k->ks_name, "cpu_stat", 8) && -1 != kstat_read(kc, k, NULL))
310 		{
311 			cpu = (cpu_stat_t *)k->ks_data;
312 			intr_count += (double)cpu->cpu_sysinfo.intr;
313 			cpu_count += 1;
314 		}
315 
316 		k = k->ks_next;
317 	}
318 
319 	kstat_close(kc);
320 
321 	if (0 == cpu_count)
322 	{
323 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find CPU information."));
324 		return SYSINFO_RET_FAIL;
325 	}
326 
327 	SET_UI64_RESULT(result, intr_count);
328 
329 	return SYSINFO_RET_OK;
330 }
331