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