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