90e9819ca1f4eadd753426be86abf1eeef2d2d8a
[public/netxms.git] / src / agent / subagents / sunos / system.cpp
1 /*
2 ** NetXMS subagent for SunOS/Solaris
3 ** Copyright (C) 2004-2011 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 ** File: system.cpp
20 **
21 **/
22
23 #include "sunos_subagent.h"
24 #include <sys/sysinfo.h>
25 #include <sys/systeminfo.h>
26 #include <sys/swap.h>
27 #include <sys/param.h>
28
29 /**
30 * Handler for System.Uname parameter
31 */
32 LONG H_Uname(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
33 {
34 char szSysStr[7][64];
35 int i;
36 LONG nRet = SYSINFO_RC_SUCCESS;
37 static int nSysCode[7] =
38 {
39 SI_SYSNAME,
40 SI_HOSTNAME,
41 SI_RELEASE,
42 SI_VERSION,
43 SI_MACHINE,
44 SI_ARCHITECTURE,
45 SI_PLATFORM
46 };
47
48 for(i = 0; i < 7; i++)
49 if (sysinfo(nSysCode[i], szSysStr[i], 64) == -1)
50 {
51 nRet = SYSINFO_RC_ERROR;
52 break;
53 }
54
55 if (nRet == SYSINFO_RC_SUCCESS)
56 {
57 _sntprintf(pValue, MAX_RESULT_LENGTH, _T("%hs %hs %hs %hs %hs %hs %hs"),
58 szSysStr[0], szSysStr[1], szSysStr[2], szSysStr[3],
59 szSysStr[4], szSysStr[5], szSysStr[6]);
60 }
61
62 return nRet;
63 }
64
65 /**
66 * Handler for System.Uptime parameter
67 */
68 LONG H_Uptime(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
69 {
70 kstat_ctl_t *kc;
71 kstat_t *kp;
72 kstat_named_t *kn;
73 DWORD hz, secs;
74 LONG nRet = SYSINFO_RC_ERROR;
75
76 hz = sysconf(_SC_CLK_TCK);
77
78 // Open kstat
79 kstat_lock();
80 kc = kstat_open();
81 if (kc != NULL)
82 {
83 // read uptime counter
84 kp = kstat_lookup(kc, (char *)"unix", 0, (char *)"system_misc");
85 if (kp != NULL)
86 {
87 if(kstat_read(kc, kp, 0) != -1)
88 {
89 kn = (kstat_named_t *)kstat_data_lookup(kp, (char *)"clk_intr");
90 if (kn != NULL)
91 {
92 secs = kn->value.ul / hz;
93 ret_uint(pValue, secs);
94 nRet = SYSINFO_RC_SUCCESS;
95 }
96 }
97 }
98 kstat_close(kc);
99 }
100 kstat_unlock();
101
102 return nRet;
103 }
104
105 /**
106 * Handler for System.Hostname parameter
107 */
108 LONG H_Hostname(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
109 {
110 #ifdef UNICODE
111 char buffer[MAX_RESULT_LENGTH];
112 if (sysinfo(SI_HOSTNAME, buffer, MAX_RESULT_LENGTH) == -1)
113 return SYSINFO_RC_ERROR;
114 ret_mbstring(pValue, buffer);
115 return SYSINFO_RC_SUCCESS;
116 #else
117 return (sysinfo(SI_HOSTNAME, pValue, MAX_RESULT_LENGTH) == -1) ?
118 SYSINFO_RC_ERROR : SYSINFO_RC_SUCCESS;
119 #endif
120 }
121
122 /**
123 * Handler for System.CPU.LoadAvg
124 */
125 LONG H_LoadAvg(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
126 {
127 kstat_ctl_t *kc;
128 kstat_t *kp;
129 kstat_named_t *kn;
130 LONG nRet = SYSINFO_RC_ERROR;
131 static char *szParam[] = { (char *)"avenrun_1min", (char *)"avenrun_5min", (char *)"avenrun_15min" };
132
133 kstat_lock();
134 kc = kstat_open();
135 if (kc != NULL)
136 {
137 kp = kstat_lookup(kc, (char *)"unix", 0, (char *)"system_misc");
138 if (kp != NULL)
139 {
140 if(kstat_read(kc, kp, 0) != -1)
141 {
142 kn = (kstat_named_t *)kstat_data_lookup(kp, szParam[CAST_FROM_POINTER(pArg, int)]);
143 if (kn != NULL)
144 {
145 _sntprintf(pValue, MAX_RESULT_LENGTH, _T("%0.02f"), (double)kn->value.ui32 / 256.0);
146 nRet = SYSINFO_RC_SUCCESS;
147 }
148 }
149 }
150 kstat_close(kc);
151 }
152 kstat_unlock();
153
154 return nRet;
155 }
156
157 /**
158 * Handler for System.KStat(*)
159 */
160 LONG H_KStat(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
161 {
162 char *eptr, szModule[128], szName[128], szInstance[16], szStat[128];
163 LONG nInstance;
164
165 // Read parameters
166 if ((!AgentGetParameterArgA(pszParam, 1, szModule, 128)) ||
167 (!AgentGetParameterArgA(pszParam, 2, szInstance, 16)) ||
168 (!AgentGetParameterArgA(pszParam, 3, szName, 128)) ||
169 (!AgentGetParameterArgA(pszParam, 4, szStat, 128)))
170 return SYSINFO_RC_UNSUPPORTED;
171
172 if (szInstance[0] != 0)
173 {
174 nInstance = strtol(szInstance, &eptr, 0);
175 if (*eptr != 0)
176 return SYSINFO_RC_UNSUPPORTED;
177 }
178 else
179 {
180 nInstance = 0;
181 }
182
183 return ReadKStatValue(szModule, nInstance, szName, szStat, pValue, NULL);
184 }
185
186 /**
187 * Handler for System.CPU.Count
188 */
189 LONG H_CPUCount(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
190 {
191 return ReadKStatValue("unix", 0, "system_misc", "ncpus", pValue, NULL);
192 }
193
194 /**
195 * Handler for generic kstat parameter
196 */
197 LONG ReadKStatValue(const char *pszModule, LONG nInstance, const char *pszName,
198 const char *pszStat, TCHAR *pValue, kstat_named_t *pRawValue)
199 {
200 kstat_ctl_t *kc;
201 kstat_t *kp;
202 kstat_named_t *kn;
203 LONG nRet = SYSINFO_RC_ERROR;
204
205 kstat_lock();
206 kc = kstat_open();
207 if (kc != NULL)
208 {
209 kp = kstat_lookup(kc, (char *)pszModule, nInstance, (char *)pszName);
210 if (kp != NULL)
211 {
212 if(kstat_read(kc, kp, 0) != -1)
213 {
214 kn = (kstat_named_t *)kstat_data_lookup(kp, (char *)pszStat);
215 if (kn != NULL)
216 {
217 if (pValue != NULL)
218 {
219 switch(kn->data_type)
220 {
221 case KSTAT_DATA_CHAR:
222 ret_mbstring(pValue, kn->value.c);
223 break;
224 case KSTAT_DATA_INT32:
225 ret_int(pValue, kn->value.i32);
226 break;
227 case KSTAT_DATA_UINT32:
228 ret_uint(pValue, kn->value.ui32);
229 break;
230 case KSTAT_DATA_INT64:
231 ret_int64(pValue, kn->value.i64);
232 break;
233 case KSTAT_DATA_UINT64:
234 ret_uint64(pValue, kn->value.ui64);
235 break;
236 case KSTAT_DATA_FLOAT:
237 ret_double(pValue, kn->value.f);
238 break;
239 case KSTAT_DATA_DOUBLE:
240 ret_double(pValue, kn->value.d);
241 break;
242 default:
243 ret_int(pValue, 0);
244 break;
245 }
246 }
247
248 if (pRawValue != NULL)
249 {
250 memcpy(pRawValue, kn, sizeof(kstat_named_t));
251 }
252
253 nRet = SYSINFO_RC_SUCCESS;
254 }
255 else
256 {
257 AgentWriteDebugLog(6, _T("SunOS::ReadKStatValue(%hs,%d,%hs,%hs): kstat_data_lookup failed (%hs)"), pszModule, nInstance, pszName, pszStat, strerror(errno));
258 }
259 }
260 else
261 {
262 AgentWriteDebugLog(6, _T("SunOS::ReadKStatValue(%hs,%d,%hs,%hs): kstat_read failed (%hs)"), pszModule, nInstance, pszName, pszStat, strerror(errno));
263 }
264 }
265 else
266 {
267 AgentWriteDebugLog(6, _T("SunOS::ReadKStatValue(%hs,%d,%hs,%hs): kstat_lookup failed (%hs)"), pszModule, nInstance, pszName, pszStat, strerror(errno));
268 }
269 kstat_close(kc);
270 }
271 kstat_unlock();
272
273 return nRet;
274 }
275
276 /**
277 * Read vminfo structure from kstat
278 */
279 static bool ReadVMInfo(kstat_ctl_t *kc, struct vminfo *info)
280 {
281 kstat_t *kp;
282 int i;
283 uint_t *pData;
284 bool success = false;
285
286 kstat_lock();
287 kp = kstat_lookup(kc, (char *)"unix", 0, (char *)"vminfo");
288 if (kp != NULL)
289 {
290 if (kstat_read(kc, kp, NULL) != -1)
291 {
292 memcpy(info, kp->ks_data, sizeof(struct vminfo));
293 success = true;
294 }
295 else
296 {
297 AgentWriteDebugLog(6, _T("SunOS: kstat_read failed in ReadVMInfo"));
298 }
299 }
300 else
301 {
302 AgentWriteDebugLog(6, _T("SunOS: kstat_lookup failed in ReadVMInfo"));
303 }
304 kstat_unlock();
305 return success;
306 }
307
308 /**
309 * Last swap info update time
310 */
311 static time_t s_lastSwapInfoUpdate = 0;
312 static MUTEX s_swapInfoMutex = MutexCreate();
313 static UINT64 s_swapUsed = 0;
314 static UINT64 s_swapFree = 0;
315 static UINT64 s_swapTotal = 0;
316
317 /**
318 * Update swap info
319 */
320 static void UpdateSwapInfo()
321 {
322 swaptable* swapTable;
323 swapent* swapEntry;
324 char* path;
325 int i;
326 static char METHOD_NAME[16] = "UpdateSwapInfo";
327
328 int num = swapctl(SC_GETNSWP, NULL);
329 if (num == -1)
330 {
331 AgentWriteDebugLog(6, _T("%s: %s: call to swapctl(SC_GETNSWP) failed"), AGENT_NAME, METHOD_NAME);
332 return;
333 }
334
335 swapTable = (swaptable*) malloc(num * sizeof(swapent_t) + sizeof(int));
336 if (swapTable == NULL) {
337 AgentWriteDebugLog(6, _T("%s: %s: failed to allocate the swap table"), AGENT_NAME, METHOD_NAME);
338 return;
339 }
340 swapTable->swt_n = num;
341
342 swapEntry = swapTable->swt_ent;
343
344 int ret = swapctl(SC_LIST, swapTable);
345 if (ret == -1)
346 {
347 AgentWriteDebugLog(6, _T("%s: %s: call to swapctl(SC_LIST) failed"), AGENT_NAME, METHOD_NAME);
348 delete swapEntry;
349 return;
350 }
351
352 UINT64 free, total = 0;
353 int bytesPerPage = (int) ((sysconf(_SC_PAGESIZE) >> DEV_BSHIFT) * DEV_BSIZE);
354
355 for(i = 0; i < num; i++) {
356 total += swapEntry[i].ste_pages * bytesPerPage;
357 free += swapEntry[i].ste_free * bytesPerPage;
358 }
359
360 delete swapEntry;
361
362 s_swapTotal = total;
363 s_swapFree = free;
364 s_swapUsed = total - free;
365 }
366
367 static void UpdateSwapInfo2()
368 {
369 kstat_lock();
370 kstat_ctl_t *kc = kstat_open();
371 if (kc != NULL)
372 {
373 kstat_unlock();
374
375 struct vminfo v1, v2;
376 if (ReadVMInfo(kc, &v1))
377 {
378 ThreadSleep(1);
379 if (ReadVMInfo(kc, &v2))
380 {
381 s_swapUsed = v2.swap_alloc - v1.swap_alloc;
382 s_swapFree = v2.swap_free - v1.swap_free;
383 s_swapTotal = s_swapUsed + s_swapFree;
384 }
385 }
386
387 kstat_lock();
388 kstat_close(kc);
389 }
390 else
391 {
392 AgentWriteDebugLog(6, _T("SunOS: kstat_open failed in UpdateSwapInfo"));
393 return;
394 }
395 kstat_unlock();
396 }
397
398 /**
399 * Get swap info counter, calling update if needed
400 */
401 static UINT64 GetSwapCounter(UINT64 *cnt)
402 {
403 MutexLock(s_swapInfoMutex);
404 time_t now = time(NULL);
405 if (now - s_lastSwapInfoUpdate > 10) // older then 10 seconds
406 {
407 UpdateSwapInfo();
408 s_lastSwapInfoUpdate = now;
409 }
410 INT64 result = *cnt;
411 MutexUnlock(s_swapInfoMutex);
412 return result;
413 }
414
415 /**
416 * Handler for System.Memory.* parameters
417 */
418 LONG H_MemoryInfo(const TCHAR *pszParam, const TCHAR *pArg, TCHAR *pValue)
419 {
420 LONG nRet = SYSINFO_RC_SUCCESS;
421 kstat_named_t kn;
422 QWORD qwPageSize;
423
424 qwPageSize = sysconf(_SC_PAGESIZE);
425
426 switch(CAST_FROM_POINTER(pArg, int))
427 {
428 case MEMINFO_PHYSICAL_TOTAL:
429 ret_uint64(pValue, (QWORD)sysconf(_SC_PHYS_PAGES) * qwPageSize);
430 break;
431 case MEMINFO_PHYSICAL_FREE:
432 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
433 if (nRet == SYSINFO_RC_SUCCESS)
434 {
435 ret_uint64(pValue, (QWORD)kn.value.ul * qwPageSize);
436 }
437 break;
438 case MEMINFO_PHYSICAL_FREEPCT:
439 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
440 if (nRet == SYSINFO_RC_SUCCESS)
441 {
442 ret_double(pValue, (double)kn.value.ul * 100.0 / (double)sysconf(_SC_PHYS_PAGES));
443 }
444 break;
445 case MEMINFO_PHYSICAL_USED:
446 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
447 if (nRet == SYSINFO_RC_SUCCESS)
448 {
449 ret_uint64(pValue, (QWORD)(sysconf(_SC_PHYS_PAGES) - kn.value.ul) * qwPageSize);
450 }
451 break;
452 case MEMINFO_PHYSICAL_USEDPCT:
453 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
454 if (nRet == SYSINFO_RC_SUCCESS)
455 {
456 ret_double(pValue, (double)(sysconf(_SC_PHYS_PAGES) - kn.value.ul) * 100.0 / (double)sysconf(_SC_PHYS_PAGES));
457 }
458 break;
459 case MEMINFO_SWAP_TOTAL:
460 ret_uint64(pValue, GetSwapCounter(&s_swapTotal) * qwPageSize);
461 break;
462 case MEMINFO_SWAP_FREE:
463 ret_uint64(pValue, GetSwapCounter(&s_swapFree) * qwPageSize);
464 break;
465 case MEMINFO_SWAP_FREEPCT:
466 ret_double(pValue, (double)GetSwapCounter(&s_swapFree) * 100.0 / (double)GetSwapCounter(&s_swapTotal));
467 break;
468 case MEMINFO_SWAP_USED:
469 ret_uint64(pValue, GetSwapCounter(&s_swapUsed) * qwPageSize);
470 break;
471 case MEMINFO_SWAP_USEDPCT:
472 ret_double(pValue, (double)GetSwapCounter(&s_swapUsed) * 100.0 / (double)GetSwapCounter(&s_swapTotal));
473 break;
474 case MEMINFO_VIRTUAL_TOTAL:
475 ret_uint64(pValue, ((QWORD)sysconf(_SC_PHYS_PAGES) + GetSwapCounter(&s_swapTotal)) * qwPageSize);
476 break;
477 case MEMINFO_VIRTUAL_FREE:
478 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
479 if (nRet == SYSINFO_RC_SUCCESS)
480 {
481 ret_uint64(pValue, ((QWORD)kn.value.ul + GetSwapCounter(&s_swapFree)) * qwPageSize);
482 }
483 break;
484 case MEMINFO_VIRTUAL_FREEPCT:
485 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
486 if (nRet == SYSINFO_RC_SUCCESS)
487 {
488 ret_double(pValue, ((double)kn.value.ul + (double)GetSwapCounter(&s_swapFree)) * 100.0 / ((double)sysconf(_SC_PHYS_PAGES) + (double)GetSwapCounter(&s_swapTotal)));
489 }
490 break;
491 case MEMINFO_VIRTUAL_USED:
492 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
493 if (nRet == SYSINFO_RC_SUCCESS)
494 {
495 ret_uint64(pValue, ((QWORD)(sysconf(_SC_PHYS_PAGES) - kn.value.ul) + GetSwapCounter(&s_swapUsed)) * qwPageSize);
496 }
497 break;
498 case MEMINFO_VIRTUAL_USEDPCT:
499 nRet = ReadKStatValue("unix", 0, "system_pages", "freemem", NULL, &kn);
500 if (nRet == SYSINFO_RC_SUCCESS)
501 {
502 ret_double(pValue, ((double)(sysconf(_SC_PHYS_PAGES) - kn.value.ul) + (double)GetSwapCounter(&s_swapUsed)) * 100.0 / ((double)sysconf(_SC_PHYS_PAGES) + (double)GetSwapCounter(&s_swapTotal)));
503 }
504 break;
505 default:
506 nRet = SYSINFO_RC_UNSUPPORTED;
507 break;
508 }
509
510 return nRet;
511 }