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 static kvm_t *kd = NULL;
28
proc_argv(pid_t pid)29 static char *proc_argv(pid_t pid)
30 {
31 size_t sz = 0;
32 int mib[4], ret;
33 int i, len;
34 static char *argv = NULL;
35 static size_t argv_alloc = 0;
36
37 mib[0] = CTL_KERN;
38 mib[1] = KERN_PROC_ARGS;
39 mib[2] = (int)pid;
40 mib[3] = KERN_PROC_ARGV;
41
42 if (0 != sysctl(mib, 4, NULL, &sz, NULL, 0))
43 return NULL;
44
45 if (argv_alloc < sz)
46 {
47 argv_alloc = sz;
48 if (NULL == argv)
49 argv = zbx_malloc(argv, argv_alloc);
50 else
51 argv = zbx_realloc(argv, argv_alloc);
52 }
53
54 sz = argv_alloc;
55 if (0 != sysctl(mib, 4, argv, &sz, NULL, 0))
56 return NULL;
57
58 for (i = 0; i < (int)(sz - 1); i++ )
59 if (argv[i] == '\0')
60 argv[i] = ' ';
61
62 return argv;
63 }
64
PROC_MEM(AGENT_REQUEST * request,AGENT_RESULT * result)65 int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result)
66 {
67 char *procname, *proccomm, *param, *args;
68 int do_task, pagesize, count, i, proccount = 0, invalid_user = 0, proc_ok, comm_ok, op, arg;
69 double value = 0.0, memsize = 0;
70 struct kinfo_proc2 *proc, *pproc;
71 struct passwd *usrinfo;
72
73 if (4 < request->nparam)
74 {
75 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
76 return SYSINFO_RET_FAIL;
77 }
78
79 procname = get_rparam(request, 0);
80 param = get_rparam(request, 1);
81
82 if (NULL != param && '\0' != *param)
83 {
84 errno = 0;
85
86 if (NULL == (usrinfo = getpwnam(param)))
87 {
88 if (0 != errno)
89 {
90 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
91 zbx_strerror(errno)));
92 return SYSINFO_RET_FAIL;
93 }
94
95 invalid_user = 1;
96 }
97 }
98 else
99 usrinfo = NULL;
100
101 param = get_rparam(request, 2);
102
103 if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum"))
104 do_task = ZBX_DO_SUM;
105 else if (0 == strcmp(param, "avg"))
106 do_task = ZBX_DO_AVG;
107 else if (0 == strcmp(param, "max"))
108 do_task = ZBX_DO_MAX;
109 else if (0 == strcmp(param, "min"))
110 do_task = ZBX_DO_MIN;
111 else
112 {
113 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
114 return SYSINFO_RET_FAIL;
115 }
116
117 proccomm = get_rparam(request, 3);
118
119 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
120 goto out;
121
122 pagesize = getpagesize();
123
124 if (NULL == kd && NULL == (kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL)))
125 {
126 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain a descriptor to access kernel virtual memory."));
127 return SYSINFO_RET_FAIL;
128 }
129
130 if (NULL != usrinfo)
131 {
132 op = KERN_PROC_UID;
133 arg = (int)usrinfo->pw_uid;
134 }
135 else
136 {
137 op = KERN_PROC_ALL;
138 arg = 0;
139 }
140
141 if (NULL == (proc = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &count)))
142 {
143 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain process information."));
144 return SYSINFO_RET_FAIL;
145 }
146
147 for (pproc = proc, i = 0; i < count; pproc++, i++)
148 {
149 proc_ok = 0;
150 comm_ok = 0;
151
152 if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, pproc->p_comm))
153 proc_ok = 1;
154
155 if (NULL != proccomm && '\0' != *proccomm)
156 {
157 if (NULL != (args = proc_argv(pproc->p_pid)))
158 {
159 if (NULL != zbx_regexp_match(args, proccomm, NULL))
160 comm_ok = 1;
161 }
162 }
163 else
164 comm_ok = 1;
165
166 if (proc_ok && comm_ok)
167 {
168 value = pproc->p_vm_tsize + pproc->p_vm_dsize + pproc->p_vm_ssize;
169 value *= pagesize;
170
171 if (0 == proccount++)
172 memsize = value;
173 else
174 {
175 if (ZBX_DO_MAX == do_task)
176 memsize = MAX(memsize, value);
177 else if (ZBX_DO_MIN == do_task)
178 memsize = MIN(memsize, value);
179 else
180 memsize += value;
181 }
182 }
183 }
184 out:
185 if (ZBX_DO_AVG == do_task)
186 SET_DBL_RESULT(result, 0 == proccount ? 0 : memsize / proccount);
187 else
188 SET_UI64_RESULT(result, memsize);
189
190 return SYSINFO_RET_OK;
191 }
192
PROC_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)193 int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
194 {
195 char *procname, *proccomm, *param, *args;
196 int proccount = 0, invalid_user = 0, zbx_proc_stat;
197 int count, i, proc_ok, stat_ok, comm_ok, op, arg;
198 struct kinfo_proc2 *proc, *pproc;
199 struct passwd *usrinfo;
200
201 if (4 < request->nparam)
202 {
203 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
204 return SYSINFO_RET_FAIL;
205 }
206
207 procname = get_rparam(request, 0);
208 param = get_rparam(request, 1);
209
210 if (NULL != param && '\0' != *param)
211 {
212 errno = 0;
213
214 if (NULL == (usrinfo = getpwnam(param)))
215 {
216 if (0 != errno)
217 {
218 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s",
219 zbx_strerror(errno)));
220 return SYSINFO_RET_FAIL;
221 }
222
223 invalid_user = 1;
224 }
225 }
226 else
227 usrinfo = NULL;
228
229 param = get_rparam(request, 2);
230
231 if (NULL == param || '\0' == *param || 0 == strcmp(param, "all"))
232 zbx_proc_stat = ZBX_PROC_STAT_ALL;
233 else if (0 == strcmp(param, "run"))
234 zbx_proc_stat = ZBX_PROC_STAT_RUN;
235 else if (0 == strcmp(param, "sleep"))
236 zbx_proc_stat = ZBX_PROC_STAT_SLEEP;
237 else if (0 == strcmp(param, "zomb"))
238 zbx_proc_stat = ZBX_PROC_STAT_ZOMB;
239 else if (0 == strcmp(param, "disk"))
240 zbx_proc_stat = ZBX_PROC_STAT_DISK;
241 else if (0 == strcmp(param, "trace"))
242 zbx_proc_stat = ZBX_PROC_STAT_TRACE;
243 else
244 {
245 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
246 return SYSINFO_RET_FAIL;
247 }
248
249 proccomm = get_rparam(request, 3);
250
251 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
252 goto out;
253
254 if (NULL == kd && NULL == (kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL)))
255 {
256 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain a descriptor to access kernel virtual memory."));
257 return SYSINFO_RET_FAIL;
258 }
259
260 if (NULL != usrinfo)
261 {
262 op = KERN_PROC_UID;
263 arg = (int)usrinfo->pw_uid;
264 }
265 else
266 {
267 op = KERN_PROC_ALL;
268 arg = 0;
269 }
270
271 if (NULL == (proc = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &count)))
272 {
273 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain process information."));
274 return SYSINFO_RET_FAIL;
275 }
276
277 for (pproc = proc, i = 0; i < count; pproc++, i++)
278 {
279 proc_ok = 0;
280 stat_ok = 0;
281 comm_ok = 0;
282
283 if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, pproc->p_comm))
284 proc_ok = 1;
285
286 if (ZBX_PROC_STAT_ALL != zbx_proc_stat)
287 {
288 switch (zbx_proc_stat)
289 {
290 case ZBX_PROC_STAT_RUN:
291 if (LSRUN == pproc->p_stat || LSONPROC == pproc->p_stat)
292 stat_ok = 1;
293 break;
294 case ZBX_PROC_STAT_SLEEP:
295 if (LSSLEEP == pproc->p_stat && 0 != (pproc->p_flag & L_SINTR))
296 stat_ok = 1;
297 break;
298 case ZBX_PROC_STAT_ZOMB:
299 if (0 != P_ZOMBIE(pproc))
300 stat_ok = 1;
301 break;
302 case ZBX_PROC_STAT_DISK:
303 if (LSSLEEP == pproc->p_stat && 0 == (pproc->p_flag & L_SINTR))
304 stat_ok = 1;
305 break;
306 case ZBX_PROC_STAT_TRACE:
307 if (LSSTOP == pproc->p_stat)
308 stat_ok = 1;
309 break;
310 }
311 }
312 else
313 stat_ok = 1;
314
315 if (NULL != proccomm && '\0' != *proccomm)
316 {
317 if (NULL != (args = proc_argv(pproc->p_pid)))
318 {
319 if (NULL != zbx_regexp_match(args, proccomm, NULL))
320 comm_ok = 1;
321 }
322 }
323 else
324 comm_ok = 1;
325
326 if (proc_ok && stat_ok && comm_ok)
327 proccount++;
328 }
329 out:
330 SET_UI64_RESULT(result, proccount);
331
332 return SYSINFO_RET_OK;
333 }
334