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
check_procstate(struct procentry64 * procentry,int zbx_proc_stat)24 static int check_procstate(struct procentry64 *procentry, int zbx_proc_stat)
25 {
26 if (ZBX_PROC_STAT_ALL == zbx_proc_stat)
27 return SUCCEED;
28
29 switch (zbx_proc_stat)
30 {
31 case ZBX_PROC_STAT_RUN:
32 return SACTIVE == procentry->pi_state && 0 != procentry->pi_cpu ? SUCCEED : FAIL;
33 case ZBX_PROC_STAT_SLEEP:
34 return SACTIVE == procentry->pi_state && 0 == procentry->pi_cpu ? SUCCEED : FAIL;
35 case ZBX_PROC_STAT_ZOMB:
36 return SZOMB == procentry->pi_state ? SUCCEED : FAIL;
37 }
38
39 return FAIL;
40 }
41
check_procargs(struct procentry64 * procentry,const char * proccomm)42 static int check_procargs(struct procentry64 *procentry, const char *proccomm)
43 {
44 int i;
45 char procargs[MAX_BUFFER_LEN];
46
47 if (0 != getargs(procentry, (int)sizeof(*procentry), procargs, (int)sizeof(procargs)))
48 return FAIL;
49
50 for (i = 0; i < sizeof(procargs) - 1; i++)
51 {
52 if ('\0' == procargs[i])
53 {
54 if ('\0' == procargs[i + 1])
55 break;
56
57 procargs[i] = ' ';
58 }
59 }
60
61 if (i == sizeof(procargs) - 1)
62 procargs[i] = '\0';
63
64 return NULL != zbx_regexp_match(procargs, proccomm, NULL) ? SUCCEED : FAIL;
65 }
66
PROC_MEM(AGENT_REQUEST * request,AGENT_RESULT * result)67 int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result)
68 {
69 #define ZBX_VSIZE 0
70 #define ZBX_RSS 1
71 #define ZBX_PMEM 2
72 #define ZBX_SIZE 3
73 #define ZBX_DSIZE 4
74 #define ZBX_TSIZE 5
75 #define ZBX_SDSIZE 6
76 #define ZBX_DRSS 7
77 #define ZBX_TRSS 8
78
79 /* The pi_???_l2psize fields are described as: log2 of a proc's ??? pg sz */
80 /* Basically it's bits per page, so define 12 bits (4kb) for earlier AIX */
81 /* versions that do not support those fields. */
82 #ifdef _AIX61
83 # define ZBX_L2PSIZE(field) field
84 #else
85 # define ZBX_L2PSIZE(field) 12
86 #endif
87
88 char *param, *procname, *proccomm, *mem_type = NULL;
89 struct passwd *usrinfo;
90 struct procentry64 procentry;
91 pid_t pid = 0;
92 int do_task, mem_type_code, proccount = 0, invalid_user = 0;
93 zbx_uint64_t mem_size = 0, byte_value = 0;
94 double pct_size = 0.0, pct_value = 0.0;
95
96 if (5 < request->nparam)
97 {
98 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
99 return SYSINFO_RET_FAIL;
100 }
101
102 procname = get_rparam(request, 0);
103 param = get_rparam(request, 1);
104
105 if (NULL != param && '\0' != *param)
106 {
107 if (NULL == (usrinfo = getpwnam(param)))
108 invalid_user = 1;
109 }
110 else
111 usrinfo = NULL;
112
113 param = get_rparam(request, 2);
114
115 if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum"))
116 do_task = ZBX_DO_SUM;
117 else if (0 == strcmp(param, "avg"))
118 do_task = ZBX_DO_AVG;
119 else if (0 == strcmp(param, "max"))
120 do_task = ZBX_DO_MAX;
121 else if (0 == strcmp(param, "min"))
122 do_task = ZBX_DO_MIN;
123 else
124 {
125 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
126 return SYSINFO_RET_FAIL;
127 }
128
129 proccomm = get_rparam(request, 3);
130 mem_type = get_rparam(request, 4);
131
132 if (NULL == mem_type || '\0' == *mem_type || 0 == strcmp(mem_type, "vsize"))
133 {
134 mem_type_code = ZBX_VSIZE; /* virtual memory size */
135 }
136 else if (0 == strcmp(mem_type, "rss"))
137 {
138 mem_type_code = ZBX_RSS; /* resident set size */
139 }
140 else if (0 == strcmp(mem_type, "pmem"))
141 {
142 mem_type_code = ZBX_PMEM; /* percentage of real memory used by process */
143 }
144 else if (0 == strcmp(mem_type, "size"))
145 {
146 mem_type_code = ZBX_SIZE; /* size of process (code + data) */
147 }
148 else if (0 == strcmp(mem_type, "dsize"))
149 {
150 mem_type_code = ZBX_DSIZE; /* data size */
151 }
152 else if (0 == strcmp(mem_type, "tsize"))
153 {
154 mem_type_code = ZBX_TSIZE; /* text size */
155 }
156 else if (0 == strcmp(mem_type, "sdsize"))
157 {
158 mem_type_code = ZBX_SDSIZE; /* data size from shared library */
159 }
160 else if (0 == strcmp(mem_type, "drss"))
161 {
162 mem_type_code = ZBX_DRSS; /* data resident set size */
163 }
164 else if (0 == strcmp(mem_type, "trss"))
165 {
166 mem_type_code = ZBX_TRSS; /* text resident set size */
167 }
168 else
169 {
170 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter."));
171 return SYSINFO_RET_FAIL;
172 }
173
174 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
175 goto out;
176
177 while (0 < getprocs64(&procentry, (int)sizeof(struct procentry64), NULL, 0, &pid, 1))
178 {
179 if (NULL != procname && '\0' != *procname && 0 != strcmp(procname, procentry.pi_comm))
180 continue;
181
182 if (NULL != usrinfo && usrinfo->pw_uid != procentry.pi_uid)
183 continue;
184
185 if (NULL != proccomm && '\0' != *proccomm && SUCCEED != check_procargs(&procentry, proccomm))
186 continue;
187
188 switch (mem_type_code)
189 {
190 case ZBX_VSIZE:
191 /* historically default proc.mem[] on AIX */
192 byte_value = (zbx_uint64_t)procentry.pi_size << 12; /* number of pages to bytes */
193 break;
194 case ZBX_RSS:
195 /* try to be compatible with "ps -o rssize" */
196 byte_value = ((zbx_uint64_t)procentry.pi_drss << ZBX_L2PSIZE(procentry.pi_data_l2psize)) +
197 ((zbx_uint64_t)procentry.pi_trss << ZBX_L2PSIZE(procentry.pi_text_l2psize));
198 break;
199 case ZBX_PMEM:
200 /* try to be compatible with "ps -o pmem" */
201 pct_value = procentry.pi_prm;
202 break;
203 case ZBX_SIZE:
204 /* try to be compatible with "ps gvw" SIZE column */
205 byte_value = (zbx_uint64_t)procentry.pi_dvm << ZBX_L2PSIZE(procentry.pi_data_l2psize);
206 break;
207 case ZBX_DSIZE:
208 byte_value = procentry.pi_dsize;
209 break;
210 case ZBX_TSIZE:
211 /* try to be compatible with "ps gvw" TSIZ column */
212 byte_value = procentry.pi_tsize;
213 break;
214 case ZBX_SDSIZE:
215 byte_value = procentry.pi_sdsize;
216 break;
217 case ZBX_DRSS:
218 byte_value = (zbx_uint64_t)procentry.pi_drss << ZBX_L2PSIZE(procentry.pi_data_l2psize);
219 break;
220 case ZBX_TRSS:
221 byte_value = (zbx_uint64_t)procentry.pi_trss << ZBX_L2PSIZE(procentry.pi_text_l2psize);
222 break;
223 }
224
225 if (ZBX_PMEM != mem_type_code)
226 {
227 if (0 != proccount++)
228 {
229 if (ZBX_DO_MAX == do_task)
230 mem_size = MAX(mem_size, byte_value);
231 else if (ZBX_DO_MIN == do_task)
232 mem_size = MIN(mem_size, byte_value);
233 else
234 mem_size += byte_value;
235 }
236 else
237 mem_size = byte_value;
238 }
239 else
240 {
241 if (0 != proccount++)
242 {
243 if (ZBX_DO_MAX == do_task)
244 pct_size = MAX(pct_size, pct_value);
245 else if (ZBX_DO_MIN == do_task)
246 pct_size = MIN(pct_size, pct_value);
247 else
248 pct_size += pct_value;
249 }
250 else
251 pct_size = pct_value;
252 }
253 }
254 out:
255 if (ZBX_PMEM != mem_type_code)
256 {
257 if (ZBX_DO_AVG == do_task)
258 SET_DBL_RESULT(result, 0 == proccount ? 0.0 : (double)mem_size / (double)proccount);
259 else
260 SET_UI64_RESULT(result, mem_size);
261 }
262 else
263 {
264 if (ZBX_DO_AVG == do_task)
265 SET_DBL_RESULT(result, 0 == proccount ? 0.0 : pct_size / (double)proccount);
266 else
267 SET_DBL_RESULT(result, pct_size);
268 }
269
270 return SYSINFO_RET_OK;
271
272 #undef ZBX_L2PSIZE
273
274 #undef ZBX_SIZE
275 #undef ZBX_RSS
276 #undef ZBX_VSIZE
277 #undef ZBX_PMEM
278 #undef ZBX_TSIZE
279 #undef ZBX_DSIZE
280 #undef ZBX_SDSIZE
281 #undef ZBX_DRSS
282 #undef ZBX_TRSS
283 }
284
PROC_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)285 int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
286 {
287 char *param, *procname, *proccomm;
288 struct passwd *usrinfo;
289 struct procentry64 procentry;
290 pid_t pid = 0;
291 int proccount = 0, invalid_user = 0, zbx_proc_stat;
292
293 if (4 < request->nparam)
294 {
295 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
296 return SYSINFO_RET_FAIL;
297 }
298
299 procname = get_rparam(request, 0);
300 param = get_rparam(request, 1);
301
302 if (NULL != param && '\0' != *param)
303 {
304 if (NULL == (usrinfo = getpwnam(param)))
305 invalid_user = 1;
306 }
307 else
308 usrinfo = NULL;
309
310 param = get_rparam(request, 2);
311
312 if (NULL == param || '\0' == *param || 0 == strcmp(param, "all"))
313 zbx_proc_stat = ZBX_PROC_STAT_ALL;
314 else if (0 == strcmp(param, "run"))
315 zbx_proc_stat = ZBX_PROC_STAT_RUN;
316 else if (0 == strcmp(param, "sleep"))
317 zbx_proc_stat = ZBX_PROC_STAT_SLEEP;
318 else if (0 == strcmp(param, "zomb"))
319 zbx_proc_stat = ZBX_PROC_STAT_ZOMB;
320 else
321 {
322 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
323 return SYSINFO_RET_FAIL;
324 }
325
326 proccomm = get_rparam(request, 3);
327
328 if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */
329 goto out;
330
331 while (0 < getprocs64(&procentry, (int)sizeof(struct procentry64), NULL, 0, &pid, 1))
332 {
333 if (NULL != procname && '\0' != *procname && 0 != strcmp(procname, procentry.pi_comm))
334 continue;
335
336 if (NULL != usrinfo && usrinfo->pw_uid != procentry.pi_uid)
337 continue;
338
339 if (SUCCEED != check_procstate(&procentry, zbx_proc_stat))
340 continue;
341
342 if (NULL != proccomm && '\0' != *proccomm && SUCCEED != check_procargs(&procentry, proccomm))
343 continue;
344
345 proccount++;
346 }
347 out:
348 SET_UI64_RESULT(result, proccount);
349
350 return SYSINFO_RET_OK;
351 }
352