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 <sys/procfs.h>
21 #include "common.h"
22 #include "sysinfo.h"
23 #include "zbxregexp.h"
24 #include "log.h"
25 
PROC_MEM(AGENT_REQUEST * request,AGENT_RESULT * result)26 int	PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result)
27 {
28 	DIR		*dir;
29 	int		proc;
30 	struct dirent	*entries;
31 	zbx_stat_t	buf;
32 	struct passwd	*usrinfo;
33 	struct prpsinfo	psinfo;
34 	char		filename[MAX_STRING_LEN];
35 	char		*procname, *proccomm, *param;
36 	double		memsize = -1;
37 	int		pgsize = getpagesize();
38 	int		proccount = 0, invalid_user = 0, do_task;
39 	pid_t		curr_pid = getpid();
40 
41 	if (4 < request->nparam)
42 	{
43 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
44 		return SYSINFO_RET_FAIL;
45 	}
46 
47 	procname = get_rparam(request, 0);
48 	param = get_rparam(request, 1);
49 
50 	if (NULL != param && '\0' != *param)
51 	{
52 		if (NULL == (usrinfo = getpwnam(param)))
53 			invalid_user = 1;
54 	}
55 	else
56 		usrinfo = NULL;
57 
58 	param = get_rparam(request, 2);
59 
60 	if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum"))	/* default parameter */
61 		do_task = ZBX_DO_SUM;
62 	else if (0 == strcmp(param, "avg"))
63 		do_task = ZBX_DO_AVG;
64 	else if (0 == strcmp(param, "max"))
65 		do_task = ZBX_DO_MAX;
66 	else if (0 == strcmp(param, "min"))
67 		do_task = ZBX_DO_MIN;
68 	else
69 	{
70 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
71 		return SYSINFO_RET_FAIL;
72 	}
73 
74 	proccomm = get_rparam(request, 3);
75 
76 	if (1 == invalid_user)	/* handle 0 for non-existent user after all parameters have been parsed and validated */
77 		goto out;
78 
79 	if (NULL == (dir = opendir("/proc")))
80 	{
81 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc: %s", zbx_strerror(errno)));
82 		return SYSINFO_RET_FAIL;
83 	}
84 
85 	while (NULL != (entries = readdir(dir)))
86 	{
87 		strscpy(filename, "/proc/");
88 		zbx_strlcat(filename, entries->d_name, MAX_STRING_LEN);
89 
90 		if (0 == zbx_stat(filename, &buf))
91 		{
92 			proc = open(filename, O_RDONLY);
93 			if (-1 == proc)
94 				goto lbl_skip_procces;
95 
96 			if (-1 == ioctl(proc, PIOCPSINFO, &psinfo))
97 				goto lbl_skip_procces;
98 
99 			/* Self process information. It leads to incorrect results for proc.mem[zabbix_agentd]. */
100 			if (psinfo.pr_pid == curr_pid)
101 				goto lbl_skip_procces;
102 
103 			if (NULL != procname && '\0' != *procname)
104 				if (0 == strcmp(procname, psinfo.pr_fname))
105 					goto lbl_skip_procces;
106 
107 			if (NULL != usrinfo)
108 				if (usrinfo->pw_uid != psinfo.pr_uid)
109 					goto lbl_skip_procces;
110 
111 			if (NULL != proccomm && '\0' != *proccomm)
112 				if (NULL == zbx_regexp_match(psinfo.pr_psargs, proccomm, NULL))
113 					goto lbl_skip_procces;
114 
115 			proccount++;
116 
117 			if (0 > memsize) /* first initialization */
118 			{
119 				memsize = (double)(psinfo.pr_rssize * pgsize);
120 			}
121 			else
122 			{
123 				if (ZBX_DO_MAX == do_task)
124 					memsize = MAX(memsize, (double)(psinfo.pr_rssize * pgsize));
125 				else if (ZBX_DO_MIN == do_task)
126 					memsize = MIN(memsize, (double)(psinfo.pr_rssize * pgsize));
127 				else	/* SUM */
128 					memsize += (double)(psinfo.pr_rssize * pgsize);
129 			}
130 lbl_skip_procces:
131 			if (-1 != proc)
132 				close(proc);
133 		}
134 	}
135 
136 	closedir(dir);
137 
138 	if (0 > memsize)
139 	{
140 		/* incorrect process name */
141 		memsize = 0;
142 	}
143 out:
144 	if (ZBX_DO_AVG == do_task)
145 		SET_DBL_RESULT(result, 0 == proccount ? 0 : memsize / (double)proccount);
146 	else
147 		SET_UI64_RESULT(result, memsize);
148 
149 	return SYSINFO_RET_OK;
150 }
151 
PROC_NUM(AGENT_REQUEST * request,AGENT_RESULT * result)152 int	PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result)
153 {
154 	DIR		*dir;
155 	int		proc;
156 	struct  dirent	*entries;
157 	zbx_stat_t	buf;
158 	struct passwd	*usrinfo;
159 	struct prpsinfo	psinfo;
160 	char		filename[MAX_STRING_LEN];
161 	char		*procname, *proccomm, *param;
162 	int		proccount = 0, invalid_user = 0, zbx_proc_stat;
163 	pid_t		curr_pid = getpid();
164 
165 	if (4 < request->nparam)
166 	{
167 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
168 		return SYSINFO_RET_FAIL;
169 	}
170 
171 	procname = get_rparam(request, 0);
172 	param = get_rparam(request, 1);
173 
174 	if (NULL != param && '\0' != *param)
175 	{
176 		if (NULL == (usrinfo = getpwnam(param)))
177 			invalid_user = 1;
178 	}
179 	else
180 		usrinfo = NULL;
181 
182 	param = get_rparam(request, 2);
183 
184 	if (NULL == param || '\0' == *param || 0 == strcmp(param, "all"))
185 		zbx_proc_stat = -1;
186 	else if (0 == strcmp(param, "run"))
187 		zbx_proc_stat = PR_SRUN;
188 	else if (0 == strcmp(param, "sleep"))
189 		zbx_proc_stat = PR_SSLEEP;
190 	else if (0 == strcmp(param, "zomb"))
191 		zbx_proc_stat = PR_SZOMB;
192 	else
193 	{
194 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
195 		return SYSINFO_RET_FAIL;
196 	}
197 
198 	proccomm = get_rparam(request, 3);
199 
200 	if (1 == invalid_user)	/* handle 0 for non-existent user after all parameters have been parsed and validated */
201 		goto out;
202 
203 	if (NULL == (dir = opendir("/proc")))
204 	{
205 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc: %s", zbx_strerror(errno)));
206 		return SYSINFO_RET_FAIL;
207 	}
208 
209 	while (NULL != (entries = readdir(dir)))
210 	{
211 		strscpy(filename, "/proc/");
212 		zbx_strlcat(filename, entries->d_name,MAX_STRING_LEN);
213 
214 		if (0 == zbx_stat(filename, &buf))
215 		{
216 			proc = open(filename, O_RDONLY);
217 			if (-1 == proc)
218 				goto lbl_skip_procces;
219 
220 			if (-1 == ioctl(proc, PIOCPSINFO, &psinfo))
221 				goto lbl_skip_procces;
222 
223 			/* Self process information. It leads to incorrect results for proc.num[zabbix_agentd]. */
224 			if (psinfo.pr_pid == curr_pid)
225 				goto lbl_skip_procces;
226 
227 			if (NULL != procname && '\0' != *procname)
228 				if (0 != strcmp(procname, psinfo.pr_fname))
229 					goto lbl_skip_procces;
230 
231 			if (NULL != usrinfo)
232 				if (usrinfo->pw_uid != psinfo.pr_uid)
233 					goto lbl_skip_procces;
234 
235 			if (-1 != zbx_proc_stat)
236 				if (psinfo.pr_sname != zbx_proc_stat)
237 					goto lbl_skip_procces;
238 
239 			if (NULL != proccomm && '\0' != *proccomm)
240 				if (NULL == zbx_regexp_match(psinfo.pr_psargs, proccomm, NULL))
241 					goto lbl_skip_procces;
242 
243 			proccount++;
244 lbl_skip_procces:
245 			if (-1 != proc)
246 				close(proc);
247 		}
248 	}
249 
250 	closedir(dir);
251 out:
252 	SET_UI64_RESULT(result, proccount);
253 
254 	return SYSINFO_RET_OK;
255 }
256