4f7afad75456ce45ceaf3186dd94ba5ed978c476
[public/netxms.git] / src / agent / subagents / sunos / process.cpp
1 /*
2 ** NetXMS subagent for SunOS/Solaris
3 ** Copyright (C) 2004 Victor Kirhenshtein
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** $module: process.cpp
20 **
21 **/
22
23 #include "sunos_subagent.h"
24 #include <procfs.h>
25
26
27 //
28 // Constants
29 //
30
31 #define INFOTYPE_MIN 0
32 #define INFOTYPE_MAX 1
33 #define INFOTYPE_AVG 2
34 #define INFOTYPE_SUM 3
35
36
37 //
38 // Filter function for scandir() in ProcRead()
39 //
40
41 static int ProcFilter(const struct dirent *pEnt)
42 {
43 char *pTmp;
44
45 if (pEnt == NULL)
46 {
47 return 0; // ignore file
48 }
49
50 pTmp = (char *)pEnt->d_name;
51 while (*pTmp != 0)
52 {
53 if (*pTmp < '0' || *pTmp > '9')
54 {
55 return 0; // skip
56 }
57 pTmp++;
58 }
59
60 return 1;
61 }
62
63
64 //
65 // Read process list from /proc filesystem
66 // Returns only processes with names matched to pszPattern
67 // (currently with strcmp) ot, if pszPattern is NULL, all
68 // processes in the system.
69 //
70
71 static int ProcRead(PROC_ENT **pEnt, char *pszPattern)
72 {
73 struct dirent **pNameList;
74 int nCount, nFound;
75
76 nFound = -1;
77 if (pEnt != NULL)
78 *pEnt = NULL;
79
80 nCount = scandir("/proc", &pNameList, &ProcFilter, alphasort);
81 if (nCount >= 0)
82 {
83 nFound = 0;
84
85 if (nCount > 0 && pEnt != NULL)
86 {
87 *pEnt = (PROC_ENT *)malloc(sizeof(PROC_ENT) * (nCount + 1));
88
89 if (*pEnt == NULL)
90 {
91 nFound = -1;
92 // cleanup
93 while(nCount--)
94 {
95 free(pNameList[nCount]);
96 }
97 }
98 else
99 {
100 memset(*pEnt, 0, sizeof(PROC_ENT) * (nCount + 1));
101 }
102 }
103
104 while(nCount--)
105 {
106 char szFileName[256];
107 int hFile;
108
109 snprintf(szFileName, sizeof(szFileName),
110 "/proc/%s/psinfo", pNameList[nCount]->d_name);
111 hFile = open(szFileName, O_RDONLY);
112 if (hFile != -1)
113 {
114 psinfo_t psi;
115
116 if (read(hFile, &psi, sizeof(psinfo_t)) == sizeof(psinfo_t))
117 {
118 if ((pszPattern == NULL) || (!strcmp(psi.pr_fname, CHECK_NULL_EX(pszPattern))))
119 {
120 if (pEnt != NULL)
121 {
122 (*pEnt)[nFound].nPid = strtoul(pNameList[nCount]->d_name, NULL, 10);
123 strncpy((*pEnt)[nFound].szProcName, psi.pr_fname,
124 sizeof((*pEnt)[nFound].szProcName));
125 }
126 nFound++;
127 }
128 }
129 close(hFile);
130 }
131 free(pNameList[nCount]);
132 }
133 free(pNameList);
134 }
135
136 return nFound;
137 }
138
139
140 //
141 // Process list
142 //
143
144 LONG H_ProcessList(char *pszParam, char *pArg, NETXMS_VALUES_LIST *pValue)
145 {
146 LONG nRet = SYSINFO_RC_SUCCESS;
147 PROC_ENT *pList;
148 int i, nProc;
149 char szBuffer[256];
150
151 nProc = ProcRead(&pList, NULL);
152 if (nProc != -1)
153 {
154 for(i = 0; i < nProc; i++)
155 {
156 snprintf(szBuffer, sizeof(szBuffer), "%d %s", pList[i].nPid,
157 pList[i].szProcName);
158 NxAddResultString(pValue, szBuffer);
159 }
160 }
161 else
162 {
163 nRet = SYSINFO_RC_ERROR;
164 }
165 safe_free(pList);
166
167 return nRet;
168 }
169
170
171 //
172 // Handler for Process.Count(*) parameter
173 //
174
175 LONG H_ProcessCount(char *pszParam, char *pArg, char *pValue)
176 {
177 int nRet = SYSINFO_RC_ERROR;
178 char szArg[128] = "";
179 int nCount;
180
181 NxGetParameterArg(pszParam, 1, szArg, sizeof(szArg));
182 nCount = ProcRead(NULL, szArg);
183 if (nCount >= 0)
184 {
185 ret_int(pValue, nCount);
186 nRet = SYSINFO_RC_SUCCESS;
187 }
188
189 return nRet;
190 }
191
192
193 //
194 // Handler for System.ProcessCount parameter
195 //
196
197 LONG H_SysProcCount(char *pszParam, char *pArg, char *pValue)
198 {
199 return ReadKStatValue("unix", 0, "system_misc", "nproc", pValue);
200 }
201
202
203 //
204 // Read process information file from /proc file system
205 //
206
207 static BOOL ReadProcFile(pid_t nPid, char *pszFile, void *pData, size_t nDataLen)
208 {
209 char szFileName[256];
210 int hFile;
211 BOOL bResult = FALSE;
212
213 snprintf(szFileName, sizeof(szFileName), "/proc/%d/%s", nPid, pszFile);
214 hFile = open(szFileName, O_RDONLY);
215 if (hFile != -1)
216 {
217 psinfo_t psi;
218
219 if (read(hFile, pData, nDataLen) == nDataLen)
220 {
221 bResult = TRUE;
222 }
223 close(hFile);
224 }
225 return bResult;
226 }
227
228
229 //
230 // Get specific process attribute
231 //
232
233 static QWORD GetProcessAttribute(pid_t nPid, int nAttr, int nType,
234 int nCount, QWORD *pqwValue)
235 {
236 QWORD qwValue;
237 char szFileName[MAX_PATH];
238 prusage_t usage;
239 pstatus_t status;
240 BOOL bResult = TRUE;
241
242 // Get value for current process instance
243 switch(nAttr)
244 {
245 case PROCINFO_VMSIZE:
246 break;
247 case PROCINFO_WKSET:
248 break;
249 case PROCINFO_PF:
250 if (ReadProcFile(nPid, "usage", &usage, sizeof(prusage_t)))
251 {
252 qwValue = usage.pr_minf + usage.pr_majf;
253 }
254 else
255 {
256 bResult = FALSE;
257 }
258 break;
259 case PROCINFO_KTIME:
260 if (ReadProcFile(nPid, "status", &status, sizeof(pstatus_t)))
261 {
262 qwValue = status.pr_stime.tv_sec * 1000 +
263 status.pr_stime.tv_nsec / 1000000;
264 }
265 else
266 {
267 bResult = FALSE;
268 }
269 break;
270 case PROCINFO_UTIME:
271 if (ReadProcFile(nPid, "status", &status, sizeof(pstatus_t)))
272 {
273 qwValue = status.pr_utime.tv_sec * 1000 +
274 status.pr_utime.tv_nsec / 1000000;
275 }
276 else
277 {
278 bResult = FALSE;
279 }
280 break;
281 case PROCINFO_IO_READ_B:
282 break;
283 case PROCINFO_IO_READ_OP:
284 break;
285 case PROCINFO_IO_WRITE_B:
286 break;
287 case PROCINFO_IO_WRITE_OP:
288 break;
289 default:
290 bResult = FALSE;
291 break;
292 }
293
294 // Recalculate final value according to selected type
295 if (nCount == 0) // First instance
296 {
297 *pqwValue = qwValue;
298 }
299 else
300 {
301 switch(nType)
302 {
303 case INFOTYPE_MIN:
304 *pqwValue = min(*pqwValue, qwValue);
305 break;
306 case INFOTYPE_MAX:
307 *pqwValue = max(*pqwValue, qwValue);
308 break;
309 case INFOTYPE_AVG:
310 *pqwValue = (*pqwValue * nCount + qwValue) / (nCount + 1);
311 break;
312 case INFOTYPE_SUM:
313 *pqwValue = *pqwValue + qwValue;
314 break;
315 default:
316 bResult = FALSE;
317 break;
318 }
319 }
320 return bResult;
321 }
322
323
324 //
325 // Handler for Process.XXX parameters
326 //
327
328 LONG H_ProcessInfo(char *pszParam, char *pArg, char *pValue)
329 {
330 int nRet = SYSINFO_RC_ERROR;
331 char szBuffer[256] = "";
332 int i, nCount, nType;
333 PROC_ENT *pList;
334 QWORD qwValue;
335 static char *pszTypeList[]={ "min", "max", "avg", "sum", NULL };
336
337 // Get parameter type arguments
338 NxGetParameterArg(pszParam, 2, szBuffer, sizeof(szBuffer));
339 if (szBuffer[0] == 0) // Omited type
340 {
341 nType = INFOTYPE_SUM;
342 }
343 else
344 {
345 for(nType = 0; pszTypeList[nType] != NULL; nType++)
346 if (!stricmp(pszTypeList[nType], szBuffer))
347 break;
348 if (pszTypeList[nType] == NULL)
349 return SYSINFO_RC_UNSUPPORTED; // Unsupported type
350 }
351
352 NxGetParameterArg(pszParam, 1, szBuffer, sizeof(szBuffer));
353 nCount = ProcRead(&pList, szBuffer);
354 if (nCount > 0)
355 {
356 for(i = 0, qwValue = 0; i < nCount; i++)
357 if (!GetProcessAttribute(pList[i].nPid, (int)pArg, nType, i, &qwValue))
358 break;
359 if (i == nCount)
360 {
361 ret_uint64(pValue, qwValue);
362 nRet = SYSINFO_RC_SUCCESS;
363 }
364 }
365
366 return nRet;
367 }