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 "zbxregexp.h"
23 #include "log.h"
24 
25 #include <sys/sysctl.h>
26 
27 #define ARGS_START_SIZE 64
28 
29 /* in OpenBSD 5.1 KERN_PROC2 became KERN_PROC and structure kinfo_proc2 became kinfo_proc */
30 #if OpenBSD >= 201205		/* OpenBSD 5.1 version as year and month */
31 #	ifndef KERN_PROC2
32 #		define KERN_PROC2	KERN_PROC
33 #	endif
34 #	ifndef kinfo_proc2
35 #		define kinfo_proc2	kinfo_proc
36 #	endif
37 #endif
38 
39 #ifdef KERN_PROC2
40 #	define ZBX_P_COMM	p_comm
41 #	define ZBX_P_PID	p_pid
42 #	define ZBX_P_STAT	p_stat
43 #	define ZBX_P_VM_TSIZE	p_vm_tsize
44 #	define ZBX_P_VM_DSIZE	p_vm_dsize
45 #	define ZBX_P_VM_SSIZE	p_vm_ssize
46 #else
47 #	define ZBX_P_COMM	kp_proc.p_comm
48 #	define ZBX_P_PID	kp_proc.p_pid
49 #	define ZBX_P_STAT	kp_proc.p_stat
50 #	define ZBX_P_VM_TSIZE	kp_eproc.e_vm.vm_tsize
51 #	define ZBX_P_VM_DSIZE	kp_eproc.e_vm.vm_dsize
52 #	define ZBX_P_VM_SSIZE	kp_eproc.e_vm.vm_ssize
53 #endif
54 
proc_argv(pid_t pid,char *** argv,size_t * argv_alloc,int * argc)55 static int	proc_argv(pid_t pid, char ***argv, size_t *argv_alloc, int *argc)
56 {
57 	size_t	sz;
58 	int	mib[4];
59 
60 	if (NULL == *argv)
61 	{
62 		*argv_alloc = ARGS_START_SIZE;
63 		*argv = zbx_malloc(*argv, *argv_alloc);
64 	}
65 
66 	mib[0] = CTL_KERN;
67 	mib[1] = KERN_PROC_ARGS;
68 	mib[2] = (int)pid;
69 	mib[3] = KERN_PROC_ARGV;
70 retry:
71 	sz = *argv_alloc;
72 	if (0 != sysctl(mib, 4, *argv, &sz, NULL, 0))
73 	{
74 		if (errno == ENOMEM)
75 		{
76 			*argv_alloc *= 2;
77 			*argv = zbx_realloc(*argv, *argv_alloc);
78 			goto retry;
79 		}
80 		return FAIL;
81 	}
82 
83 	mib[3] = KERN_PROC_NARGV;
84 
85 	sz = sizeof(int);
86 	if (0 != sysctl(mib, 4, argc, &sz, NULL, 0))
87 		return FAIL;
88 
89 	return SUCCEED;
90 }
91 
collect_args(char ** argv,int argc,char ** args,size_t * args_alloc)92 static void	collect_args(char **argv, int argc, char **args, size_t *args_alloc)
93 {
94 	int	i;
95 	size_t	args_offset = 0;
96 
97 	if (0 == *args_alloc)
98 	{
99 		*args_alloc = ARGS_START_SIZE;
100 		*args = zbx_malloc(*args, *args_alloc);
101 	}
102 
103 	for (i = 0; i < argc; i++)
104 		zbx_snprintf_alloc(args, args_alloc, &args_offset, "%s ", argv[i]);
105 
106 	if (0 != args_offset)
107 		args_offset--; /* ' ' */
108 	(*args)[args_offset] = '\0';
109 }
110 
PROC_MEM(AGENT_REQUEST * request,AGENT_RESULT * result)111 int     PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result)
112 {
113 	char			*procname, *proccomm, *param;
114 	int			do_task, pagesize, count, i, proccount = 0, invalid_user = 0, proc_ok, comm_ok;
115 	double			value = 0.0, memsize = 0;
116 	size_t			sz;
117 	struct passwd		*usrinfo;
118 #ifdef KERN_PROC2
119 	int			mib[6];
120 	struct kinfo_proc2	*proc = NULL;
121 #else
122 	int			mib[4];
123 	struct kinfo_proc	*proc = NULL;
124 #endif
125 	char			**argv = NULL, *args = NULL;
126 	size_t			argv_alloc = 0, args_alloc = 0;
127 	int			argc;
128 
129 	if (4 < request->nparam)
130 	{
131 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
132 		return SYSINFO_RET_FAIL;
133 	}
134 
135 	procname = get_rparam(request, 0);
136 	param = get_rparam(request, 1);
137 
138 	if (NULL != param && '\0' != *param)
139 	{
140 		errno = 0;
141 
142 		if (NULL == (usrinfo = getpwnam(param)))
143 		{
144 			if (0 != errno)
145 			{
146 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
147 						zbx_strerror(errno)));
148 				return SYSINFO_RET_FAIL;
149 			}
150 
151 			invalid_user = 1;
152 		}
153 	}
154 	else
155 		usrinfo = NULL;
156 
157 	param = get_rparam(request, 2);
158 
159 	if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum"))
160 		do_task = ZBX_DO_SUM;
161 	else if (0 == strcmp(param, "avg"))
162 		do_task = ZBX_DO_AVG;
163 	else if (0 == strcmp(param, "max"))
164 		do_task = ZBX_DO_MAX;
165 	else if (0 == strcmp(param, "min"))
166 		do_task = ZBX_DO_MIN;
167 	else
168 	{
169 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
170 		return SYSINFO_RET_FAIL;
171 	}
172 
173 	proccomm = get_rparam(request, 3);
174 
175 	if (1 == invalid_user)	/* handle 0 for non-existent user after all parameters have been parsed and validated */
176 		goto out;
177 
178 	pagesize = getpagesize();
179 
180 	mib[0] = CTL_KERN;
181 	if (NULL != usrinfo)
182 	{
183 		mib[2] = KERN_PROC_UID;
184 		mib[3] = usrinfo->pw_uid;
185 	}
186 	else
187 	{
188 		mib[2] = KERN_PROC_ALL;
189 		mib[3] = 0;
190 	}
191 
192 #ifdef KERN_PROC2
193 	mib[1] = KERN_PROC2;
194 	mib[4] = sizeof(struct kinfo_proc2);
195 	mib[5] = 0;
196 
197 	sz = 0;
198 	if (0 != sysctl(mib, 6, NULL, &sz, NULL, 0))
199 	{
200 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
201 				zbx_strerror(errno)));
202 		return SYSINFO_RET_FAIL;
203 	}
204 
205 	proc = (struct kinfo_proc2 *)zbx_malloc(proc, sz);
206 	mib[5] = (int)(sz / sizeof(struct kinfo_proc2));
207 	if (0 != sysctl(mib, 6, proc, &sz, NULL, 0))
208 	{
209 		zbx_free(proc);
210 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
211 				zbx_strerror(errno)));
212 		return SYSINFO_RET_FAIL;
213 	}
214 
215 	count = sz / sizeof(struct kinfo_proc2);
216 #else
217 	mib[1] = KERN_PROC;
218 
219 	sz = 0;
220 	if (0 != sysctl(mib, 4, NULL, &sz, NULL, 0))
221 	{
222 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
223 				zbx_strerror(errno)));
224 		return SYSINFO_RET_FAIL;
225 	}
226 
227 	proc = (struct kinfo_proc *)zbx_malloc(proc, sz);
228 	if (0 != sysctl(mib, 4, proc, &sz, NULL, 0))
229 	{
230 		zbx_free(proc);
231 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
232 				zbx_strerror(errno)));
233 		return SYSINFO_RET_FAIL;
234 	}
235 
236 	count = sz / sizeof(struct kinfo_proc);
237 #endif
238 	for (i = 0; i < count; i++)
239 	{
240 		proc_ok = 0;
241 		comm_ok = 0;
242 
243 		if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, proc[i].ZBX_P_COMM))
244 			proc_ok = 1;
245 
246 		if (NULL != proccomm && '\0' != *proccomm)
247 		{
248 			if (SUCCEED == proc_argv(proc[i].ZBX_P_PID, &argv, &argv_alloc, &argc))
249 			{
250 				collect_args(argv, argc, &args, &args_alloc);
251 				if (NULL != zbx_regexp_match(args, proccomm, NULL))
252 					comm_ok = 1;
253 			}
254 		}
255 		else
256 			comm_ok = 1;
257 
258 		if (proc_ok && comm_ok)
259 		{
260 			value = proc[i].ZBX_P_VM_TSIZE + proc[i].ZBX_P_VM_DSIZE + proc[i].ZBX_P_VM_SSIZE;
261 			value *= pagesize;
262 
263 			if (0 == proccount++)
264 				memsize = value;
265 			else
266 			{
267 				if (ZBX_DO_MAX == do_task)
268 					memsize = MAX(memsize, value);
269 				else if (ZBX_DO_MIN == do_task)
270 					memsize = MIN(memsize, value);
271 				else
272 					memsize += value;
273 			}
274 		}
275 	}
276 	zbx_free(proc);
277 	zbx_free(argv);
278 	zbx_free(args);
279 out:
280 	if (ZBX_DO_AVG == do_task)
281 		SET_DBL_RESULT(result, 0 == proccount ? 0 : memsize / proccount);
282 	else
283 		SET_UI64_RESULT(result, memsize);
284 
285 	return SYSINFO_RET_OK;
286 }
287 
PROC_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)288 int	PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
289 {
290 	char			*procname, *proccomm, *param;
291 	int			proccount = 0, invalid_user = 0, zbx_proc_stat, count, i, proc_ok, stat_ok, comm_ok;
292 	size_t			sz;
293 	struct passwd		*usrinfo;
294 #ifdef KERN_PROC2
295 	int			mib[6];
296 	struct kinfo_proc2	*proc = NULL;
297 #else
298 	int			mib[4];
299 	struct kinfo_proc	*proc = NULL;
300 #endif
301 	char			**argv = NULL, *args = NULL;
302 	size_t			argv_alloc = 0, args_alloc = 0;
303 	int			argc;
304 
305 	if (4 < request->nparam)
306 	{
307 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
308 		return SYSINFO_RET_FAIL;
309 	}
310 
311 	procname = get_rparam(request, 0);
312 	param = get_rparam(request, 1);
313 
314 	if (NULL != param && '\0' != *param)
315 	{
316 		errno = 0;
317 
318 		if (NULL == (usrinfo = getpwnam(param)))
319 		{
320 			if (0 != errno)
321 			{
322 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
323 						zbx_strerror(errno)));
324 				return SYSINFO_RET_FAIL;
325 			}
326 
327 			invalid_user = 1;
328 		}
329 	}
330 	else
331 		usrinfo = NULL;
332 
333 	param = get_rparam(request, 2);
334 
335 	if (NULL == param || '\0' == *param || 0 == strcmp(param, "all"))
336 		zbx_proc_stat = ZBX_PROC_STAT_ALL;
337 	else if (0 == strcmp(param, "run"))
338 		zbx_proc_stat = ZBX_PROC_STAT_RUN;
339 	else if (0 == strcmp(param, "sleep"))
340 		zbx_proc_stat = ZBX_PROC_STAT_SLEEP;
341 	else if (0 == strcmp(param, "zomb"))
342 		zbx_proc_stat = ZBX_PROC_STAT_ZOMB;
343 	else
344 	{
345 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
346 		return SYSINFO_RET_FAIL;
347 	}
348 
349 	proccomm = get_rparam(request, 3);
350 
351 	if (1 == invalid_user)	/* handle 0 for non-existent user after all parameters have been parsed and validated */
352 		goto out;
353 
354 	mib[0] = CTL_KERN;
355 	if (NULL != usrinfo)
356 	{
357 		mib[2] = KERN_PROC_UID;
358 		mib[3] = usrinfo->pw_uid;
359 	}
360 	else
361 	{
362 		mib[2] = KERN_PROC_ALL;
363 		mib[3] = 0;
364 	}
365 
366 #ifdef KERN_PROC2
367 	mib[1] = KERN_PROC2;
368 	mib[4] = sizeof(struct kinfo_proc2);
369 	mib[5] = 0;
370 
371 	sz = 0;
372 	if (0 != sysctl(mib, 6, NULL, &sz, NULL, 0))
373 	{
374 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
375 				zbx_strerror(errno)));
376 		return SYSINFO_RET_FAIL;
377 	}
378 
379 	proc = (struct kinfo_proc2 *)zbx_malloc(proc, sz);
380 	mib[5] = (int)(sz / sizeof(struct kinfo_proc2));
381 	if (0 != sysctl(mib, 6, proc, &sz, NULL, 0))
382 	{
383 		zbx_free(proc);
384 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
385 				zbx_strerror(errno)));
386 		return SYSINFO_RET_FAIL;
387 	}
388 
389 	count = sz / sizeof(struct kinfo_proc2);
390 #else
391 	mib[1] = KERN_PROC;
392 
393 	sz = 0;
394 	if (0 != sysctl(mib, 4, NULL, &sz, NULL, 0))
395 	{
396 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
397 				zbx_strerror(errno)));
398 		return SYSINFO_RET_FAIL;
399 	}
400 
401 	proc = (struct kinfo_proc *)zbx_malloc(proc, sz);
402 	if (0 != sysctl(mib, 4, proc, &sz, NULL, 0))
403 	{
404 		zbx_free(proc);
405 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
406 				zbx_strerror(errno)));
407 		return SYSINFO_RET_FAIL;
408 	}
409 
410 	count = sz / sizeof(struct kinfo_proc);
411 #endif
412 
413 	for (i = 0; i < count; i++)
414 	{
415 		proc_ok = 0;
416 		stat_ok = 0;
417 		comm_ok = 0;
418 
419 		if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, proc[i].ZBX_P_COMM))
420 			proc_ok = 1;
421 
422 		if (ZBX_PROC_STAT_ALL != zbx_proc_stat)
423 		{
424 			switch (zbx_proc_stat)
425 			{
426 				case ZBX_PROC_STAT_RUN:
427 					if (SRUN == proc[i].ZBX_P_STAT || SONPROC == proc[i].ZBX_P_STAT)
428 						stat_ok = 1;
429 					break;
430 				case ZBX_PROC_STAT_SLEEP:
431 					if (SSLEEP == proc[i].ZBX_P_STAT)
432 						stat_ok = 1;
433 					break;
434 				case ZBX_PROC_STAT_ZOMB:
435 					if (SZOMB == proc[i].ZBX_P_STAT || SDEAD == proc[i].ZBX_P_STAT)
436 						stat_ok = 1;
437 					break;
438 			}
439 		}
440 		else
441 			stat_ok = 1;
442 
443 		if (NULL != proccomm && '\0' != *proccomm)
444 		{
445 			if (SUCCEED == proc_argv(proc[i].ZBX_P_PID, &argv, &argv_alloc, &argc))
446 			{
447 				collect_args(argv, argc, &args, &args_alloc);
448 				if (NULL != zbx_regexp_match(args, proccomm, NULL))
449 					comm_ok = 1;
450 			}
451 		}
452 		else
453 			comm_ok = 1;
454 
455 		if (proc_ok && stat_ok && comm_ok)
456 			proccount++;
457 	}
458 	zbx_free(proc);
459 	zbx_free(argv);
460 	zbx_free(args);
461 out:
462 	SET_UI64_RESULT(result, proccount);
463 
464 	return SYSINFO_RET_OK;
465 }
466