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 #if (__FreeBSD_version) < 500000
26 # define ZBX_COMMLEN MAXCOMLEN
27 # define ZBX_PROC_PID kp_proc.p_pid
28 # define ZBX_PROC_COMM kp_proc.p_comm
29 # define ZBX_PROC_STAT kp_proc.p_stat
30 # define ZBX_PROC_TSIZE kp_eproc.e_vm.vm_tsize
31 # define ZBX_PROC_DSIZE kp_eproc.e_vm.vm_dsize
32 # define ZBX_PROC_SSIZE kp_eproc.e_vm.vm_ssize
33 # define ZBX_PROC_RSSIZE kp_eproc.e_vm.vm_rssize
34 # define ZBX_PROC_VSIZE kp_eproc.e_vm.vm_map.size
35 #else
36 # define ZBX_COMMLEN COMMLEN
37 # define ZBX_PROC_PID ki_pid
38 # define ZBX_PROC_COMM ki_comm
39 # define ZBX_PROC_STAT ki_stat
40 # define ZBX_PROC_TSIZE ki_tsize
41 # define ZBX_PROC_DSIZE ki_dsize
42 # define ZBX_PROC_SSIZE ki_ssize
43 # define ZBX_PROC_RSSIZE ki_rssize
44 # define ZBX_PROC_VSIZE ki_size
45 #endif
46
47 #if (__FreeBSD_version) < 500000
48 # define ZBX_PROC_FLAG kp_proc.p_flag
49 # define ZBX_PROC_MASK P_INMEM
50 #elif (__FreeBSD_version) < 700000
51 # define ZBX_PROC_FLAG ki_sflag
52 # define ZBX_PROC_MASK PS_INMEM
53 #else
54 # define ZBX_PROC_TDFLAG ki_tdflags
55 # define ZBX_PROC_FLAG ki_flag
56 # define ZBX_PROC_MASK P_INMEM
57 #endif
58
get_commandline(struct kinfo_proc * proc)59 static char *get_commandline(struct kinfo_proc *proc)
60 {
61 int mib[4], i;
62 size_t sz;
63 static char *args = NULL;
64 static int args_alloc = 0;
65
66 mib[0] = CTL_KERN;
67 mib[1] = KERN_PROC;
68 mib[2] = KERN_PROC_ARGS;
69 mib[3] = proc->ZBX_PROC_PID;
70
71 if (-1 == sysctl(mib, 4, NULL, &sz, NULL, 0))
72 return NULL;
73
74 if (NULL == args)
75 {
76 args = zbx_malloc(args, sz);
77 args_alloc = sz;
78 }
79 else if (sz > args_alloc)
80 {
81 args = zbx_realloc(args, sz);
82 args_alloc = sz;
83 }
84
85 if (-1 == sysctl(mib, 4, args, &sz, NULL, 0))
86 return NULL;
87
88 for (i = 0; i < (int)(sz - 1); i++)
89 if (args[i] == '\0')
90 args[i] = ' ';
91
92 if (sz == 0)
93 zbx_strlcpy(args, proc->ZBX_PROC_COMM, args_alloc);
94
95 return args;
96 }
97
PROC_MEM(AGENT_REQUEST * request,AGENT_RESULT * result)98 int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result)
99 {
100 #define ZBX_SIZE 1
101 #define ZBX_RSS 2
102 #define ZBX_VSIZE 3
103 #define ZBX_PMEM 4
104 #define ZBX_TSIZE 5
105 #define ZBX_DSIZE 6
106 #define ZBX_SSIZE 7
107
108 char *procname, *proccomm, *param, *args, *mem_type = NULL;
109 int do_task, pagesize, count, i, proccount = 0, invalid_user = 0, mem_type_code, mib[4];
110 unsigned int mibs;
111 zbx_uint64_t mem_size = 0, byte_value = 0;
112 double pct_size = 0.0, pct_value = 0.0;
113 #if (__FreeBSD_version) < 500000
114 int mem_pages;
115 #else
116 unsigned long mem_pages;
117 #endif
118 size_t sz;
119
120 struct kinfo_proc *proc = NULL;
121 struct passwd *usrinfo;
122
123 if (5 < request->nparam)
124 {
125 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
126 return SYSINFO_RET_FAIL;
127 }
128
129 procname = get_rparam(request, 0);
130 param = get_rparam(request, 1);
131
132 if (NULL != param && '\0' != *param)
133 {
134 errno = 0;
135
136 if (NULL == (usrinfo = getpwnam(param)))
137 {
138 if (0 != errno)
139 {
140 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
141 zbx_strerror(errno)));
142 return SYSINFO_RET_FAIL;
143 }
144
145 invalid_user = 1;
146 }
147 }
148 else
149 usrinfo = NULL;
150
151 param = get_rparam(request, 2);
152
153 if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum"))
154 do_task = ZBX_DO_SUM;
155 else if (0 == strcmp(param, "avg"))
156 do_task = ZBX_DO_AVG;
157 else if (0 == strcmp(param, "max"))
158 do_task = ZBX_DO_MAX;
159 else if (0 == strcmp(param, "min"))
160 do_task = ZBX_DO_MIN;
161 else
162 {
163 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
164 return SYSINFO_RET_FAIL;
165 }
166
167 proccomm = get_rparam(request, 3);
168 mem_type = get_rparam(request, 4);
169
170 if (NULL == mem_type || '\0' == *mem_type || 0 == strcmp(mem_type, "size"))
171 {
172 mem_type_code = ZBX_SIZE; /* size of process (code + data + stack) */
173 }
174 else if (0 == strcmp(mem_type, "rss"))
175 {
176 mem_type_code = ZBX_RSS; /* resident set size */
177 }
178 else if (0 == strcmp(mem_type, "vsize"))
179 {
180 mem_type_code = ZBX_VSIZE; /* virtual size */
181 }
182 else if (0 == strcmp(mem_type, "pmem"))
183 {
184 mem_type_code = ZBX_PMEM; /* percentage of real memory used by process */
185 }
186 else if (0 == strcmp(mem_type, "tsize"))
187 {
188 mem_type_code = ZBX_TSIZE; /* text size */
189 }
190 else if (0 == strcmp(mem_type, "dsize"))
191 {
192 mem_type_code = ZBX_DSIZE; /* data size */
193 }
194 else if (0 == strcmp(mem_type, "ssize"))
195 {
196 mem_type_code = ZBX_SSIZE; /* stack size */
197 }
198 else
199 {
200 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter."));
201 return SYSINFO_RET_FAIL;
202 }
203
204 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
205 goto out;
206
207 pagesize = getpagesize();
208
209 mib[0] = CTL_KERN;
210 mib[1] = KERN_PROC;
211 if (NULL != usrinfo)
212 {
213 mib[2] = KERN_PROC_UID;
214 mib[3] = usrinfo->pw_uid;
215 mibs = 4;
216 }
217 else
218 {
219 #if (__FreeBSD_version) < 500000
220 mib[2] = KERN_PROC_ALL;
221 #else
222 mib[2] = KERN_PROC_PROC;
223 #endif
224 mib[3] = 0;
225 mibs = 3;
226 }
227
228 if (ZBX_PMEM == mem_type_code)
229 {
230 sz = sizeof(mem_pages);
231
232 if (0 != sysctlbyname("hw.availpages", &mem_pages, &sz, NULL, (size_t)0))
233 {
234 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain number of physical pages: %s",
235 zbx_strerror(errno)));
236 return SYSINFO_RET_FAIL;
237 }
238 }
239
240 sz = 0;
241 if (0 != sysctl(mib, mibs, NULL, &sz, NULL, (size_t)0))
242 {
243 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
244 zbx_strerror(errno)));
245 return SYSINFO_RET_FAIL;
246 }
247
248 proc = (struct kinfo_proc *)zbx_malloc(proc, sz);
249 if (0 != sysctl(mib, mibs, proc, &sz, NULL, (size_t)0))
250 {
251 zbx_free(proc);
252 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
253 zbx_strerror(errno)));
254 return SYSINFO_RET_FAIL;
255 }
256
257 count = sz / sizeof(struct kinfo_proc);
258
259 for (i = 0; i < count; i++)
260 {
261 if (NULL != procname && '\0' != *procname && 0 != strcmp(procname, proc[i].ZBX_PROC_COMM))
262 continue;
263
264 if (NULL != proccomm && '\0' != *proccomm)
265 {
266 if (NULL == (args = get_commandline(&proc[i])))
267 continue;
268
269 if (NULL == zbx_regexp_match(args, proccomm, NULL))
270 continue;
271 }
272
273 switch (mem_type_code)
274 {
275 case ZBX_SIZE:
276 byte_value = (proc[i].ZBX_PROC_TSIZE + proc[i].ZBX_PROC_DSIZE + proc[i].ZBX_PROC_SSIZE)
277 * pagesize;
278 break;
279 case ZBX_RSS:
280 byte_value = proc[i].ZBX_PROC_RSSIZE * pagesize;
281 break;
282 case ZBX_VSIZE:
283 byte_value = proc[i].ZBX_PROC_VSIZE;
284 break;
285 case ZBX_PMEM:
286 if (0 != (proc[i].ZBX_PROC_FLAG & ZBX_PROC_MASK))
287 #if (__FreeBSD_version) < 500000
288 pct_value = ((float)(proc[i].ZBX_PROC_RSSIZE + UPAGES) / mem_pages) * 100.0;
289 #else
290 pct_value = ((float)proc[i].ZBX_PROC_RSSIZE / mem_pages) * 100.0;
291 #endif
292 else
293 pct_value = 0.0;
294 break;
295 case ZBX_TSIZE:
296 byte_value = proc[i].ZBX_PROC_TSIZE * pagesize;
297 break;
298 case ZBX_DSIZE:
299 byte_value = proc[i].ZBX_PROC_DSIZE * pagesize;
300 break;
301 case ZBX_SSIZE:
302 byte_value = proc[i].ZBX_PROC_SSIZE * pagesize;
303 break;
304 }
305
306 if (ZBX_PMEM != mem_type_code)
307 {
308 if (0 != proccount++)
309 {
310 if (ZBX_DO_MAX == do_task)
311 mem_size = MAX(mem_size, byte_value);
312 else if (ZBX_DO_MIN == do_task)
313 mem_size = MIN(mem_size, byte_value);
314 else
315 mem_size += byte_value;
316 }
317 else
318 mem_size = byte_value;
319 }
320 else
321 {
322 if (0 != proccount++)
323 {
324 if (ZBX_DO_MAX == do_task)
325 pct_size = MAX(pct_size, pct_value);
326 else if (ZBX_DO_MIN == do_task)
327 pct_size = MIN(pct_size, pct_value);
328 else
329 pct_size += pct_value;
330 }
331 else
332 pct_size = pct_value;
333 }
334 }
335
336 zbx_free(proc);
337 out:
338 if (ZBX_PMEM != mem_type_code)
339 {
340 if (ZBX_DO_AVG == do_task)
341 SET_DBL_RESULT(result, 0 == proccount ? 0.0 : (double)mem_size / (double)proccount);
342 else
343 SET_UI64_RESULT(result, mem_size);
344 }
345 else
346 {
347 if (ZBX_DO_AVG == do_task)
348 SET_DBL_RESULT(result, 0 == proccount ? 0.0 : pct_size / (double)proccount);
349 else
350 SET_DBL_RESULT(result, pct_size);
351 }
352
353 return SYSINFO_RET_OK;
354
355 #undef ZBX_SIZE
356 #undef ZBX_RSS
357 #undef ZBX_VSIZE
358 #undef ZBX_PMEM
359 #undef ZBX_TSIZE
360 #undef ZBX_DSIZE
361 #undef ZBX_SSIZE
362 }
363
PROC_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)364 int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
365 {
366 char *procname, *proccomm, *param, *args;
367 int proccount = 0, invalid_user = 0, zbx_proc_stat;
368 int count, i, proc_ok, stat_ok, comm_ok, mib[4], mibs;
369 size_t sz;
370 struct kinfo_proc *proc = NULL;
371 struct passwd *usrinfo;
372
373 if (4 < request->nparam)
374 {
375 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
376 return SYSINFO_RET_FAIL;
377 }
378
379 procname = get_rparam(request, 0);
380 param = get_rparam(request, 1);
381
382 if (NULL != param && '\0' != *param)
383 {
384 errno = 0;
385
386 if (NULL == (usrinfo = getpwnam(param)))
387 {
388 if (0 != errno)
389 {
390 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
391 zbx_strerror(errno)));
392 return SYSINFO_RET_FAIL;
393 }
394
395 invalid_user = 1;
396 }
397 }
398 else
399 usrinfo = NULL;
400
401 param = get_rparam(request, 2);
402
403 if (NULL == param || '\0' == *param || 0 == strcmp(param, "all"))
404 zbx_proc_stat = ZBX_PROC_STAT_ALL;
405 else if (0 == strcmp(param, "run"))
406 zbx_proc_stat = ZBX_PROC_STAT_RUN;
407 else if (0 == strcmp(param, "sleep"))
408 zbx_proc_stat = ZBX_PROC_STAT_SLEEP;
409 else if (0 == strcmp(param, "zomb"))
410 zbx_proc_stat = ZBX_PROC_STAT_ZOMB;
411 else if (0 == strcmp(param, "disk"))
412 zbx_proc_stat = ZBX_PROC_STAT_DISK;
413 else if (0 == strcmp(param, "trace"))
414 zbx_proc_stat = ZBX_PROC_STAT_TRACE;
415 else
416 {
417 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
418 return SYSINFO_RET_FAIL;
419 }
420
421 proccomm = get_rparam(request, 3);
422
423 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
424 goto out;
425
426 mib[0] = CTL_KERN;
427 mib[1] = KERN_PROC;
428 if (NULL != usrinfo)
429 {
430 mib[2] = KERN_PROC_UID;
431 mib[3] = usrinfo->pw_uid;
432 mibs = 4;
433 }
434 else
435 {
436 #if (__FreeBSD_version) > 500000
437 mib[2] = KERN_PROC_PROC;
438 #else
439 mib[2] = KERN_PROC_ALL;
440 #endif
441 mib[3] = 0;
442 mibs = 3;
443 }
444
445 sz = 0;
446 if (0 != sysctl(mib, mibs, NULL, &sz, NULL, 0))
447 {
448 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s",
449 zbx_strerror(errno)));
450 return SYSINFO_RET_FAIL;
451 }
452
453 proc = (struct kinfo_proc *)zbx_malloc(proc, sz);
454 if (0 != sysctl(mib, mibs, proc, &sz, NULL, 0))
455 {
456 zbx_free(proc);
457 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s",
458 zbx_strerror(errno)));
459 return SYSINFO_RET_FAIL;
460 }
461
462 count = sz / sizeof(struct kinfo_proc);
463
464 for (i = 0; i < count; i++)
465 {
466 proc_ok = 0;
467 stat_ok = 0;
468 comm_ok = 0;
469
470 if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, proc[i].ZBX_PROC_COMM))
471 proc_ok = 1;
472
473 if (zbx_proc_stat != ZBX_PROC_STAT_ALL)
474 {
475 switch (zbx_proc_stat) {
476 case ZBX_PROC_STAT_RUN:
477 if (SRUN == proc[i].ZBX_PROC_STAT)
478 stat_ok = 1;
479 break;
480 case ZBX_PROC_STAT_SLEEP:
481 if (SSLEEP == proc[i].ZBX_PROC_STAT && 0 != (proc[i].ZBX_PROC_TDFLAG & TDF_SINTR))
482 stat_ok = 1;
483 break;
484 case ZBX_PROC_STAT_ZOMB:
485 if (SZOMB == proc[i].ZBX_PROC_STAT)
486 stat_ok = 1;
487 break;
488 case ZBX_PROC_STAT_DISK:
489 if (SSLEEP == proc[i].ZBX_PROC_STAT && 0 == (proc[i].ZBX_PROC_TDFLAG & TDF_SINTR))
490 stat_ok = 1;
491 break;
492 case ZBX_PROC_STAT_TRACE:
493 if (SSTOP == proc[i].ZBX_PROC_STAT)
494 stat_ok = 1;
495 break;
496 }
497 }
498 else
499 stat_ok = 1;
500
501 if (NULL != proccomm && '\0' != *proccomm)
502 {
503 if (NULL != (args = get_commandline(&proc[i])))
504 if (NULL != zbx_regexp_match(args, proccomm, NULL))
505 comm_ok = 1;
506 }
507 else
508 comm_ok = 1;
509
510 if (proc_ok && stat_ok && comm_ok)
511 proccount++;
512 }
513 zbx_free(proc);
514 out:
515 SET_UI64_RESULT(result, proccount);
516
517 return SYSINFO_RET_OK;
518 }
519