Potential crash fixed
[public/netxms.git] / src / agent / subagents / hpux / proc.cpp
1 /*
2 ** NetXMS subagent for HP-UX
3 ** Copyright (C) 2006 Alex Kirhenshtein
4 ** Copyright (C) 2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 */
21
22 #include <nms_common.h>
23 #include <nms_agent.h>
24 #include <sys/pstat.h>
25 #include <time.h>
26 #include "system.h"
27 #include "hpux.h"
28
29
30 //
31 // Possible consolidation types of per-process information
32 //
33
34 #define INFOTYPE_MIN 0
35 #define INFOTYPE_MAX 1
36 #define INFOTYPE_AVG 2
37 #define INFOTYPE_SUM 3
38
39
40 //
41 // Process cache
42 //
43
44 #define EXPIRATION 3
45
46 static struct pst_status *m_processList = NULL;
47 static time_t m_processListUpdated = 0;
48 static int m_processCount = 0;
49
50 //
51 // Handler for System.ProcessCount parameter
52 //
53
54 LONG H_SysProcessCount(const char *pszParam, const char *pArg, char *pValue)
55 {
56 struct pst_dynamic pd;
57 LONG nRet = SYSINFO_RC_ERROR;
58
59 if (pstat_getdynamic(&pd, sizeof(struct pst_dynamic), 1, 0) == 1)
60 {
61 nRet = SYSINFO_RC_SUCCESS;
62 ret_int(pValue, (LONG)pd.psd_activeprocs);
63 }
64 return nRet;
65 }
66
67
68 //
69 // Get process list
70 //
71
72 static struct pst_status *GetProcessList(int *pnNumProcs)
73 {
74 int nSize = 0, nCount;
75 struct pst_status *pBuffer = NULL;
76 time_t now;
77
78 if (m_processList != NULL)
79 {
80 now = time(NULL);
81 if (now < m_processListUpdated + EXPIRATION)
82 {
83 *pnNumProcs = m_processCount;
84 return m_processList;
85 }
86 else
87 {
88 free(m_processList);
89 m_processList = NULL;
90 }
91 }
92
93 do
94 {
95 nSize += 1000;
96 pBuffer = (pst_status *)realloc(pBuffer, sizeof(struct pst_status) * nSize);
97 nCount = pstat_getproc(pBuffer, sizeof(struct pst_status), nSize, 0);
98 } while(nCount == nSize);
99
100 if (nCount <= 0)
101 {
102 free(pBuffer);
103 pBuffer = NULL;
104 }
105 else
106 {
107 *pnNumProcs = nCount;
108 }
109
110 m_processList = pBuffer;
111 m_processCount = nCount;
112 m_processListUpdated = now;
113
114 return pBuffer;
115 }
116
117
118 //
119 // Handler for System.ThreadCount parameter
120 //
121
122 LONG H_SysThreadCount(const char *pszParam, const char *pArg, char *pValue)
123 {
124 LONG nRet;
125 struct pst_status *pList;
126 int i, nProcCount, nThreadCount;
127
128 pList = GetProcessList(&nProcCount);
129 if (pList != NULL)
130 {
131 for(i = 0, nThreadCount = 0; i < nProcCount; i++)
132 {
133 nThreadCount += pList[i].pst_nlwps;
134 }
135 ret_uint(pValue, nThreadCount);
136 nRet = SYSINFO_RC_SUCCESS;
137 }
138 else
139 {
140 nRet = SYSINFO_RC_ERROR;
141 }
142
143 return nRet;
144 }
145
146
147 //
148 // Handler for Process.Count(*) parameter
149 //
150
151 LONG H_ProcessCount(const char *pszParam, const char *pArg, char *pValue)
152 {
153 struct pst_status *pst;
154 int i, nCount, nTotal;
155 char szArg[256];
156 LONG nRet = SYSINFO_RC_ERROR;
157
158 if (!AgentGetParameterArg(pszParam, 1, szArg, sizeof(szArg)))
159 return SYSINFO_RC_UNSUPPORTED;
160
161 pst = GetProcessList(&nCount);
162 if (pst != NULL)
163 {
164 for (i = 0, nTotal = 0; i < nCount; i++)
165 {
166 if (!strcasecmp(pst[i].pst_ucomm, szArg))
167 nTotal++;
168 }
169 ret_int(pValue, nTotal);
170 nRet = SYSINFO_RC_SUCCESS;
171 }
172
173 return nRet;
174 }
175
176
177 //
178 // Handler for Process.xxx() parameters
179 // Parameter has the following syntax:
180 // Process.XXX(<process>,<type>,<cmdline>)
181 // where
182 // XXX - requested process attribute (see documentation for list of valid attributes)
183 // <process> - process name (same as in Process.Count() parameter)
184 // <type> - representation type (meaningful when more than one process with the same
185 // name exists). Valid values are:
186 // min - minimal value among all processes named <process>
187 // max - maximal value among all processes named <process>
188 // avg - average value for all processes named <process>
189 // sum - sum of values for all processes named <process>
190 // <cmdline> - command line
191 //
192
193 LONG H_ProcessInfo(const char *pszParam, const char *pArg, char *pValue)
194 {
195 int nRet = SYSINFO_RC_SUCCESS;
196 char szBuffer[256] = "";
197 int i, nProcCount, nType, nCount;
198 struct pst_status *pList;
199 QWORD qwValue, qwCurrVal;
200 static const char *pszTypeList[]={ "min", "max", "avg", "sum", NULL };
201
202 // Get parameter type arguments
203 AgentGetParameterArg(pszParam, 2, szBuffer, sizeof(szBuffer));
204 if (szBuffer[0] == 0) // Omited type
205 {
206 nType = INFOTYPE_SUM;
207 }
208 else
209 {
210 for(nType = 0; pszTypeList[nType] != NULL; nType++)
211 if (!stricmp(pszTypeList[nType], szBuffer))
212 break;
213 if (pszTypeList[nType] == NULL)
214 return SYSINFO_RC_UNSUPPORTED; // Unsupported type
215 }
216
217 AgentGetParameterArg(pszParam, 1, szBuffer, sizeof(szBuffer));
218
219 pList = GetProcessList(&nProcCount);
220 if (pList != NULL)
221 {
222 for(i = 0, qwValue = 0, nCount = 0; i < nProcCount; i++)
223 {
224 if (!strcmp(pList[i].pst_ucomm, szBuffer))
225 {
226 switch(CAST_FROM_POINTER(pArg, int))
227 {
228 case PROCINFO_CPUTIME:
229 qwCurrVal = (pList[i].pst_stime + pList[i].pst_utime) * 1000;
230 break;
231 // case PROCINFO_IO_READ_B:
232 case PROCINFO_IO_READ_OP:
233 qwCurrVal = pList[i].pst_inblock;
234 break;
235 // case PROCINFO_IO_WRITE_B:
236 case PROCINFO_IO_WRITE_OP:
237 qwCurrVal = pList[i].pst_oublock;
238 break;
239 case PROCINFO_KTIME:
240 qwCurrVal = pList[i].pst_stime * 1000;
241 break;
242 case PROCINFO_PF:
243 qwCurrVal = pList[i].pst_minorfaults + pList[i].pst_majorfaults;
244 break;
245 case PROCINFO_THREADS:
246 qwCurrVal = pList[i].pst_nlwps;
247 break;
248 case PROCINFO_UTIME:
249 qwCurrVal = pList[i].pst_utime * 1000;
250 break;
251 case PROCINFO_VMSIZE:
252 qwCurrVal = (pList[i].pst_vtsize /* text */
253 + pList[i].pst_vdsize /* data */
254 + pList[i].pst_vssize /* stack */
255 + pList[i].pst_vshmsize /* shared memory */
256 + pList[i].pst_vmmsize /* mem-mapped files */
257 + pList[i].pst_vusize /* U-Area & K-Stack */
258 + pList[i].pst_viosize) /* I/O dev mapping */
259 * getpagesize();
260 break;
261 case PROCINFO_WKSET:
262 qwCurrVal = pList[i].pst_rssize * getpagesize();
263 break;
264 default:
265 nRet = SYSINFO_RC_UNSUPPORTED;
266 break;
267 }
268
269 if (nCount == 0)
270 {
271 qwValue = qwCurrVal;
272 }
273 else
274 {
275 switch(nType)
276 {
277 case INFOTYPE_MIN:
278 qwValue = min(qwValue, qwCurrVal);
279 break;
280 case INFOTYPE_MAX:
281 qwValue = max(qwValue, qwCurrVal);
282 break;
283 case INFOTYPE_AVG:
284 qwValue = (qwValue * nCount + qwCurrVal) / (nCount + 1);
285 break;
286 case INFOTYPE_SUM:
287 qwValue += qwCurrVal;
288 break;
289 }
290 }
291 nCount++;
292 }
293 }
294 ret_uint64(pValue, qwValue);
295 }
296 else
297 {
298 nRet = SYSINFO_RC_ERROR;
299 }
300
301 return nRet;
302 }
303
304
305 //
306 // Handler for System.ProcessList enum
307 //
308
309 LONG H_ProcessList(const char *pszParam, const char *pArg, StringList *pValue)
310 {
311 LONG nRet = SYSINFO_RC_ERROR;
312 int i, nCount;
313 struct pst_status *pst;
314 char szBuff[256];
315
316 pst = GetProcessList(&nCount);
317 if (pst != NULL)
318 {
319 for (i = 0; i < nCount; i++)
320 {
321 snprintf(szBuff, sizeof(szBuff), "%d %s", (DWORD)pst[i].pst_pid, pst[i].pst_ucomm);
322 pValue->add(szBuff);
323 }
324 nRet = SYSINFO_RC_SUCCESS;
325 }
326
327 return nRet;
328 }