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