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