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