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