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