2004-06-22 06:37:04 +08:00
|
|
|
#include "sigar.h"
|
|
|
|
#include "sigar_private.h"
|
|
|
|
#include "sigar_pdh.h"
|
|
|
|
#include "sigar_os.h"
|
|
|
|
#include "sigar_util.h"
|
|
|
|
#include <shellapi.h>
|
|
|
|
|
|
|
|
#define USING_WIDE_S(s) (s)->using_wide
|
|
|
|
#define USING_WIDE() USING_WIDE_S(sigar)
|
|
|
|
|
|
|
|
#define PERFBUF_SIZE 8192
|
|
|
|
|
|
|
|
#define PERF_TITLE_PROC 230
|
|
|
|
#define PERF_TITLE_PROC_KEY "230"
|
|
|
|
#define PERF_TITLE_CPU_KEY "238"
|
2004-12-05 09:18:57 +08:00
|
|
|
#define PERF_TITLE_DISK_KEY "236"
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
#define PERF_TITLE_CPU_USER 142
|
|
|
|
#define PERF_TITLE_CPU_IDLE 1746
|
|
|
|
#define PERF_TITLE_CPU_SYS 144
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
PERF_IX_CPU_USER,
|
|
|
|
PERF_IX_CPU_IDLE,
|
|
|
|
PERF_IX_CPU_SYS,
|
|
|
|
PERF_IX_CPU_MAX
|
|
|
|
} perf_cpu_offsets_t;
|
|
|
|
|
|
|
|
#define PERF_TITLE_CPUTIME 6
|
2005-11-24 01:51:19 +08:00
|
|
|
#define PERF_TITLE_PAGE_FAULTS 28
|
2004-06-22 06:37:04 +08:00
|
|
|
#define PERF_TITLE_MEM_VSIZE 174
|
|
|
|
#define PERF_TITLE_MEM_SIZE 180
|
|
|
|
#define PERF_TITLE_MEM_PRIV 186
|
|
|
|
#define PERF_TITLE_THREAD_CNT 680
|
|
|
|
#define PERF_TITLE_HANDLE_CNT 952
|
|
|
|
#define PERF_TITLE_PID 784
|
|
|
|
#define PERF_TITLE_PPID 1410
|
|
|
|
#define PERF_TITLE_PRIORITY 682
|
|
|
|
#define PERF_TITLE_START_TIME 684
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
PERF_IX_CPUTIME,
|
2005-11-24 01:51:19 +08:00
|
|
|
PERF_IX_PAGE_FAULTS,
|
2004-06-22 06:37:04 +08:00
|
|
|
PERF_IX_MEM_VSIZE,
|
|
|
|
PERF_IX_MEM_SIZE,
|
|
|
|
PERF_IX_MEM_PRIV,
|
|
|
|
PERF_IX_THREAD_CNT,
|
|
|
|
PERF_IX_HANDLE_CNT,
|
|
|
|
PERF_IX_PID,
|
|
|
|
PERF_IX_PPID,
|
|
|
|
PERF_IX_PRIORITY,
|
|
|
|
PERF_IX_START_TIME,
|
|
|
|
PERF_IX_MAX
|
|
|
|
} perf_proc_offsets_t;
|
|
|
|
|
2004-12-05 09:18:57 +08:00
|
|
|
typedef enum {
|
|
|
|
PERF_IX_DISK_READ,
|
|
|
|
PERF_IX_DISK_WRITE,
|
2005-04-07 09:23:49 +08:00
|
|
|
PERF_IX_DISK_READ_BYTES,
|
|
|
|
PERF_IX_DISK_WRITE_BYTES,
|
|
|
|
PERF_IX_DISK_QUEUE,
|
2004-12-05 09:18:57 +08:00
|
|
|
PERF_IX_DISK_MAX
|
|
|
|
} perf_disk_offsets_t;
|
|
|
|
|
|
|
|
#define PERF_TITLE_DISK_READ 208
|
|
|
|
#define PERF_TITLE_DISK_WRITE 210
|
2005-04-07 09:23:49 +08:00
|
|
|
#define PERF_TITLE_DISK_READ_BYTES 220
|
|
|
|
#define PERF_TITLE_DISK_WRITE_BYTES 222
|
2005-04-07 10:11:00 +08:00
|
|
|
#define PERF_TITLE_DISK_QUEUE 1028
|
2004-12-05 09:18:57 +08:00
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
/*
|
|
|
|
* diff is:
|
|
|
|
* ExW -> ExA
|
|
|
|
* wcounter -> counter
|
|
|
|
*/
|
|
|
|
#define MyRegQueryValue() \
|
|
|
|
(USING_WIDE() ? \
|
|
|
|
RegQueryValueExW(sigar->handle, \
|
|
|
|
wcounter_key, NULL, &type, \
|
|
|
|
sigar->perfbuf, \
|
2004-08-10 05:46:34 +08:00
|
|
|
&bytes) : \
|
2004-06-22 06:37:04 +08:00
|
|
|
RegQueryValueExA(sigar->handle, \
|
|
|
|
counter_key, NULL, &type, \
|
|
|
|
sigar->perfbuf, \
|
2004-08-10 05:46:34 +08:00
|
|
|
&bytes))
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
#define PERF_VAL(ix) \
|
|
|
|
perf_offsets[ix] ? \
|
|
|
|
*((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
|
|
|
|
|
2005-05-12 07:17:39 +08:00
|
|
|
/* 1/100ns units to seconds */
|
|
|
|
#define NS100_2SEC(t) ((t) / 10000000)
|
|
|
|
|
2005-05-12 07:37:22 +08:00
|
|
|
#define PERF_VAL_CPU(ix) \
|
|
|
|
NS100_2SEC(PERF_VAL(ix))
|
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
static PERF_OBJECT_TYPE *get_perf_object(sigar_t *sigar, char *counter_key,
|
|
|
|
DWORD *err)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2004-08-10 05:46:34 +08:00
|
|
|
DWORD retval, type, bytes;
|
2004-06-22 06:37:04 +08:00
|
|
|
WCHAR wcounter_key[MAX_PATH+1];
|
|
|
|
PERF_DATA_BLOCK *block;
|
2005-01-27 10:28:31 +08:00
|
|
|
PERF_OBJECT_TYPE *object;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
*err = SIGAR_OK;
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
if (!sigar->perfbuf) {
|
2004-06-23 07:44:46 +08:00
|
|
|
sigar->perfbuf = malloc(PERFBUF_SIZE);
|
2004-06-22 06:37:04 +08:00
|
|
|
sigar->perfbuf_size = PERFBUF_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (USING_WIDE()) {
|
|
|
|
SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
|
|
|
|
}
|
|
|
|
|
2004-08-10 05:46:34 +08:00
|
|
|
bytes = sigar->perfbuf_size;
|
2004-06-22 06:37:04 +08:00
|
|
|
while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
|
|
|
|
if (retval == ERROR_MORE_DATA) {
|
|
|
|
sigar->perfbuf_size += PERFBUF_SIZE;
|
2004-08-10 05:46:34 +08:00
|
|
|
bytes = sigar->perfbuf_size;
|
2004-06-23 07:44:46 +08:00
|
|
|
sigar->perfbuf =
|
|
|
|
realloc(sigar->perfbuf, sigar->perfbuf_size);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
else {
|
2004-06-23 01:51:38 +08:00
|
|
|
*err = retval;
|
2004-06-22 06:37:04 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
block = (PERF_DATA_BLOCK *)sigar->perfbuf;
|
2005-01-27 10:28:31 +08:00
|
|
|
object = PdhFirstObject(block);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-01-27 10:28:31 +08:00
|
|
|
/*
|
|
|
|
* only seen on windows 2003 server when pdh.dll
|
|
|
|
* functions are in use by the same process.
|
|
|
|
* confucius say what the fuck.
|
|
|
|
*/
|
|
|
|
if (object->NumInstances == PERF_NO_INSTANCES) {
|
2005-01-29 00:33:12 +08:00
|
|
|
int i;
|
2005-01-27 10:28:31 +08:00
|
|
|
|
2005-01-29 00:33:12 +08:00
|
|
|
for (i=0; i<block->NumObjectTypes; i++) {
|
2005-01-27 10:28:31 +08:00
|
|
|
if (object->NumInstances != PERF_NO_INSTANCES) {
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
object = PdhNextObject(object);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return object;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void get_sysinfo(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
SYSTEM_INFO sysinfo;
|
|
|
|
|
|
|
|
GetSystemInfo(&sysinfo);
|
|
|
|
|
|
|
|
sigar->ncpu = sysinfo.dwNumberOfProcessors;
|
|
|
|
sigar->pagesize = sysinfo.dwPageSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for C# bindings */
|
|
|
|
SIGAR_DECLARE(sigar_t *) sigar_new(void)
|
|
|
|
{
|
|
|
|
sigar_t *sigar;
|
|
|
|
if (sigar_open(&sigar) != SIGAR_OK) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return sigar;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
static sigar_wtsapi_t sigar_wtsapi = {
|
|
|
|
"wtsapi32.dll",
|
|
|
|
NULL,
|
|
|
|
{ "WTSEnumerateSessionsA", NULL },
|
|
|
|
{ "WTSFreeMemory", NULL },
|
|
|
|
{ "WTSQuerySessionInformationA", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static sigar_iphlpapi_t sigar_iphlpapi = {
|
|
|
|
"iphlpapi.dll",
|
|
|
|
NULL,
|
|
|
|
{ "GetIpForwardTable", NULL },
|
|
|
|
{ "GetIfTable", NULL },
|
|
|
|
{ "GetIfEntry", NULL },
|
|
|
|
{ "GetTcpTable", NULL },
|
|
|
|
{ "GetUdpTable", NULL },
|
|
|
|
{ "AllocateAndGetTcpExTableFromStack", NULL },
|
|
|
|
{ "AllocateAndGetUdpExTableFromStack", NULL },
|
|
|
|
{ "GetNetworkParams", NULL },
|
|
|
|
{ "GetAdaptersInfo", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static sigar_advapi_t sigar_advapi = {
|
|
|
|
"advapi32.dll",
|
|
|
|
NULL,
|
|
|
|
{ "ConvertStringSidToSidA", NULL },
|
|
|
|
{ "QueryServiceStatusEx", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static sigar_ntdll_t sigar_ntdll = {
|
|
|
|
"ntdll.dll",
|
|
|
|
NULL,
|
|
|
|
{ "NtQuerySystemInformation", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static sigar_psapi_t sigar_psapi = {
|
|
|
|
"psapi.dll",
|
|
|
|
NULL,
|
|
|
|
{ "EnumProcessModules", NULL },
|
|
|
|
{ "GetModuleFileNameExA", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static sigar_psapi_t sigar_winsta = {
|
|
|
|
"winsta.dll",
|
|
|
|
NULL,
|
|
|
|
{ "WinStationQueryInformationW", NULL },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DLLMOD_COPY(name) \
|
2005-12-21 12:58:02 +08:00
|
|
|
memcpy(&(sigar->##name), &sigar_##name, sizeof(sigar_##name))
|
2005-12-21 07:09:34 +08:00
|
|
|
|
|
|
|
#define DLLMOD_INIT(name, all) \
|
|
|
|
sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->##name), all)
|
|
|
|
|
|
|
|
#define DLLMOD_FREE(name) \
|
|
|
|
sigar_dllmod_free((sigar_dll_module_t *)&(sigar->##name))
|
|
|
|
|
|
|
|
static void sigar_dllmod_free(sigar_dll_module_t *module)
|
|
|
|
{
|
|
|
|
if (module->handle) {
|
|
|
|
FreeLibrary(module->handle);
|
|
|
|
module->handle = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sigar_dllmod_init(sigar_t *sigar,
|
|
|
|
sigar_dll_module_t *module,
|
|
|
|
int all)
|
|
|
|
{
|
|
|
|
sigar_dll_func_t *funcs = &module->funcs[0];
|
|
|
|
int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
|
|
|
|
int rc, success;
|
|
|
|
|
|
|
|
if (module->handle == INVALID_HANDLE_VALUE) {
|
|
|
|
return ENOENT; /* XXX better rc */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (module->handle) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
module->handle = LoadLibrary(module->name);
|
|
|
|
if (!(success = (module->handle ? TRUE : FALSE))) {
|
|
|
|
rc = GetLastError();
|
|
|
|
/* dont try again */
|
|
|
|
module->handle = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"LoadLibrary(%s): %s",
|
|
|
|
module->name,
|
|
|
|
success ?
|
|
|
|
"OK" :
|
|
|
|
sigar_strerror(sigar, rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (funcs->name) {
|
|
|
|
funcs->func = GetProcAddress(module->handle, funcs->name);
|
|
|
|
|
|
|
|
if (!(success = (funcs->func ? TRUE : FALSE))) {
|
|
|
|
rc = GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_debug) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"GetProcAddress(%s:%s): %s",
|
|
|
|
module->name, funcs->name,
|
|
|
|
success ?
|
|
|
|
"OK" :
|
|
|
|
sigar_strerror(sigar, rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (all && !success) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
funcs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
int sigar_os_open(sigar_t **sigar_ptr)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
LONG result;
|
|
|
|
HINSTANCE h;
|
2004-06-23 01:15:10 +08:00
|
|
|
OSVERSIONINFO version;
|
2005-12-21 07:09:34 +08:00
|
|
|
int i;
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar_t *sigar;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
*sigar_ptr = sigar = malloc(sizeof(*sigar));
|
|
|
|
sigar->machine = ""; /* local machine */
|
|
|
|
sigar->using_wide = 0; /*XXX*/
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar->perfbuf = NULL;
|
|
|
|
sigar->perfbuf_size = 0;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2004-06-23 01:15:10 +08:00
|
|
|
version.dwOSVersionInfoSize = sizeof(version);
|
|
|
|
GetVersionEx(&version);
|
2004-07-01 05:20:19 +08:00
|
|
|
|
2004-07-01 06:43:48 +08:00
|
|
|
/*
|
|
|
|
* 4 == NT 4.0
|
|
|
|
* 5 == 2000, XP, 2003 Server
|
|
|
|
*/
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar->winnt = (version.dwMajorVersion == 4);
|
2004-06-23 01:15:10 +08:00
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
if (USING_WIDE_S(sigar)) {
|
2004-06-22 06:37:04 +08:00
|
|
|
WCHAR wmachine[MAX_PATH+1];
|
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine));
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
result = RegConnectRegistryW(wmachine,
|
|
|
|
HKEY_PERFORMANCE_DATA,
|
2005-12-21 12:58:02 +08:00
|
|
|
&sigar->handle);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
else {
|
2005-12-21 12:58:02 +08:00
|
|
|
result = RegConnectRegistryA(sigar->machine,
|
2004-06-22 06:37:04 +08:00
|
|
|
HKEY_PERFORMANCE_DATA,
|
2005-12-21 12:58:02 +08:00
|
|
|
&sigar->handle);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
get_sysinfo(sigar);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_COPY(wtsapi);
|
|
|
|
DLLMOD_COPY(iphlpapi);
|
|
|
|
DLLMOD_COPY(advapi);
|
|
|
|
DLLMOD_COPY(ntdll);
|
|
|
|
DLLMOD_COPY(psapi);
|
|
|
|
DLLMOD_COPY(winsta);
|
2005-09-27 09:18:54 +08:00
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar->log_level = -1; /* else below segfaults */
|
2005-12-21 07:09:34 +08:00
|
|
|
/* XXX init early for use by javasigar.c */
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar_dllmod_init(sigar,
|
|
|
|
(sigar_dll_module_t *)&sigar->advapi,
|
2005-12-21 07:09:34 +08:00
|
|
|
FALSE);
|
2005-09-27 09:18:54 +08:00
|
|
|
|
2005-12-21 12:58:02 +08:00
|
|
|
sigar->pinfo.pid = -1;
|
|
|
|
sigar->ws_version = 0;
|
|
|
|
sigar->ncpu = 0;
|
|
|
|
sigar->peb = NULL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sigar_os_close(sigar_t *sigar)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_FREE(wtsapi);
|
|
|
|
DLLMOD_FREE(iphlpapi);
|
|
|
|
DLLMOD_FREE(advapi);
|
|
|
|
DLLMOD_FREE(ntdll);
|
|
|
|
DLLMOD_FREE(psapi);
|
|
|
|
DLLMOD_FREE(winsta);
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
if (sigar->perfbuf) {
|
|
|
|
free(sigar->perfbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = RegCloseKey(sigar->handle);
|
|
|
|
|
|
|
|
if (sigar->ws_version != 0) {
|
|
|
|
WSACleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sigar->peb) {
|
|
|
|
free(sigar->peb);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(sigar);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2005-03-12 14:19:34 +08:00
|
|
|
char *sigar_os_error_string(sigar_t *sigar, int err)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2004-08-11 06:24:12 +08:00
|
|
|
switch (err) {
|
|
|
|
case SIGAR_NO_SUCH_PROCESS:
|
|
|
|
return "No such process";
|
|
|
|
break;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
|
|
|
|
{
|
|
|
|
MEMORYSTATUS memstat;
|
|
|
|
|
|
|
|
GlobalMemoryStatus(&memstat);
|
|
|
|
|
|
|
|
mem->total = memstat.dwTotalPhys;
|
|
|
|
mem->free = memstat.dwAvailPhys;
|
|
|
|
mem->shared = memstat.dwTotalVirtual - memstat.dwAvailVirtual;
|
|
|
|
mem->used = mem->total - mem->free;
|
|
|
|
|
|
|
|
sigar_mem_calc_ram(sigar, mem);
|
|
|
|
|
2004-11-20 10:08:16 +08:00
|
|
|
mem->actual_free = mem->free;
|
|
|
|
mem->actual_used = mem->used;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
|
|
|
|
{
|
|
|
|
MEMORYSTATUS memstat;
|
|
|
|
|
|
|
|
GlobalMemoryStatus(&memstat);
|
|
|
|
|
|
|
|
swap->total = memstat.dwTotalPageFile;
|
|
|
|
swap->free = memstat.dwAvailPageFile;
|
|
|
|
swap->used = swap->total - swap->free;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
|
|
|
|
DWORD *perf_offsets,
|
2004-06-23 01:51:38 +08:00
|
|
|
DWORD *num, DWORD *err)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2004-06-23 01:51:38 +08:00
|
|
|
PERF_OBJECT_TYPE *object = get_perf_object(sigar, "238", err);
|
2004-06-22 06:37:04 +08:00
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_DEFINITION *counter;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
if (!object) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0, counter = PdhFirstCounter(object);
|
|
|
|
i<object->NumCounters;
|
|
|
|
i++, counter = PdhNextCounter(counter))
|
|
|
|
{
|
|
|
|
DWORD offset = counter->CounterOffset;
|
|
|
|
|
|
|
|
switch (counter->CounterNameTitleIndex) {
|
|
|
|
case PERF_TITLE_CPU_SYS:
|
|
|
|
perf_offsets[PERF_IX_CPU_SYS] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_CPU_USER:
|
|
|
|
perf_offsets[PERF_IX_CPU_USER] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_CPU_IDLE:
|
|
|
|
perf_offsets[PERF_IX_CPU_IDLE] = offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num) {
|
|
|
|
*num = object->NumInstances;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PdhFirstInstance(object);
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_NtQuerySystemInformation \
|
|
|
|
sigar->ntdll.query_sys_info.func
|
|
|
|
|
2004-11-03 07:17:18 +08:00
|
|
|
static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
|
|
|
|
DWORD idx,
|
|
|
|
PERF_COUNTER_BLOCK *counter_block,
|
|
|
|
DWORD *perf_offsets)
|
|
|
|
{
|
|
|
|
cpu->idle = 0;
|
|
|
|
|
|
|
|
if (perf_offsets[PERF_IX_CPU_IDLE]) {
|
2005-05-12 07:37:22 +08:00
|
|
|
cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE);
|
2004-11-03 07:17:18 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* windows NT and 2000 do not have an Idle counter */
|
|
|
|
sigar_cpu_count(sigar);
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(ntdll, FALSE);
|
|
|
|
if (sigar_NtQuerySystemInformation) {
|
2004-11-03 07:17:18 +08:00
|
|
|
DWORD retval, num;
|
|
|
|
/* XXX unhardcode 16 */
|
|
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
|
2004-11-03 07:34:01 +08:00
|
|
|
/* into the lungs of hell */
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
|
|
|
|
&info, sizeof(info), &retval);
|
2004-11-03 07:17:18 +08:00
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
num = retval/sizeof(info[0]);
|
|
|
|
|
|
|
|
if (idx == -1) {
|
|
|
|
int i;
|
|
|
|
for (i=0; i<num; i++) {
|
2005-05-12 07:17:39 +08:00
|
|
|
cpu->idle += NS100_2SEC(info[i].IdleTime.QuadPart);
|
2004-11-03 07:17:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (idx < num) {
|
2005-05-12 07:17:39 +08:00
|
|
|
cpu->idle = NS100_2SEC(info[idx].IdleTime.QuadPart);
|
2004-11-03 07:17:18 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return ERROR_INVALID_DATA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return ERROR_INVALID_FUNCTION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-19 04:03:52 +08:00
|
|
|
static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
2004-11-03 07:34:01 +08:00
|
|
|
int status;
|
2004-06-22 06:37:04 +08:00
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_BLOCK *counter_block;
|
2004-06-23 01:51:38 +08:00
|
|
|
DWORD perf_offsets[PERF_IX_CPU_MAX], err;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
SIGAR_ZERO(cpu);
|
|
|
|
memset(&perf_offsets, 0, sizeof(perf_offsets));
|
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!inst) {
|
2004-08-28 07:06:46 +08:00
|
|
|
return err;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* first instance is total, rest are per-cpu */
|
|
|
|
counter_block = PdhGetCounterBlock(inst);
|
|
|
|
|
2005-05-12 07:37:22 +08:00
|
|
|
cpu->sys = PERF_VAL_CPU(PERF_IX_CPU_SYS);
|
|
|
|
cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER);
|
2004-11-03 07:34:01 +08:00
|
|
|
status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
|
2004-06-22 06:37:04 +08:00
|
|
|
cpu->nice = 0; /* no nice here */
|
2004-11-22 09:51:34 +08:00
|
|
|
cpu->wait = 0; /*N/A?*/
|
|
|
|
cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait;
|
2004-11-03 07:34:01 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_WARN,
|
|
|
|
"unable to determine idle cpu time: %s",
|
|
|
|
sigar_strerror(sigar, status));
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-19 04:03:52 +08:00
|
|
|
static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu)
|
|
|
|
{
|
|
|
|
DWORD retval, num;
|
|
|
|
int i;
|
|
|
|
/* XXX unhardcode 16 */
|
|
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
|
|
|
|
/* into the lungs of hell */
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
|
|
|
|
&info, sizeof(info), &retval);
|
2005-02-19 04:03:52 +08:00
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
num = retval/sizeof(info[0]);
|
|
|
|
SIGAR_ZERO(cpu);
|
|
|
|
|
|
|
|
for (i=0; i<num; i++) {
|
2005-05-12 07:17:39 +08:00
|
|
|
cpu->idle += NS100_2SEC(info[i].IdleTime.QuadPart);
|
|
|
|
cpu->user += NS100_2SEC(info[i].UserTime.QuadPart);
|
|
|
|
cpu->sys += NS100_2SEC(info[i].KernelTime.QuadPart -
|
|
|
|
info[i].IdleTime.QuadPart);
|
|
|
|
cpu->total += cpu->idle + cpu->user + cpu->sys;
|
2005-02-19 04:03:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
|
|
|
|
{
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(ntdll, FALSE);
|
|
|
|
if (sigar_NtQuerySystemInformation) {
|
2005-02-19 04:03:52 +08:00
|
|
|
return sigar_cpu_ntsys_get(sigar, cpu);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sigar_cpu_perflib_get(sigar, cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-19 04:13:17 +08:00
|
|
|
static int sigar_cpu_list_perflib_get(sigar_t *sigar,
|
|
|
|
sigar_cpu_list_t *cpulist)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
int status, i, j, hthread=0;
|
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
2004-06-23 01:51:38 +08:00
|
|
|
DWORD perf_offsets[PERF_IX_CPU_MAX], num, err;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
memset(&perf_offsets, 0, sizeof(perf_offsets));
|
|
|
|
|
|
|
|
/* first instance is total, rest are per-cpu */
|
2004-06-23 01:51:38 +08:00
|
|
|
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!inst) {
|
2004-06-23 01:51:38 +08:00
|
|
|
return err;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
2004-06-23 13:21:13 +08:00
|
|
|
if (!sigar->winnt) {
|
|
|
|
/* skip Processor _Total instance (NT doesnt have one) */
|
|
|
|
--num;
|
|
|
|
inst = PdhNextInstance(inst);
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
sigar_cpu_count(sigar);
|
|
|
|
sigar_cpu_list_create(cpulist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if hyper-threading was detected and ncpu is less than
|
|
|
|
* the number of counter instances, assume there is a counter
|
|
|
|
* for each logical processor.
|
|
|
|
* XXX assuming this is correct until have something to test on.
|
|
|
|
*/
|
2004-06-23 03:22:50 +08:00
|
|
|
if (sigar->ht_enabled && ((sigar->ncpu * sigar->lcpu) == num)) {
|
2004-06-22 06:37:04 +08:00
|
|
|
hthread = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
PERF_COUNTER_BLOCK *counter_block;
|
|
|
|
sigar_cpu_t *cpu;
|
|
|
|
|
2004-06-23 03:22:50 +08:00
|
|
|
if (hthread && (i % sigar->lcpu)) {
|
2004-06-22 06:37:04 +08:00
|
|
|
/* merge times of logical processors */
|
|
|
|
cpu = &cpulist->data[cpulist->number-1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_CPU_LIST_GROW(cpulist);
|
|
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
|
|
SIGAR_ZERO(cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
counter_block = PdhGetCounterBlock(inst);
|
|
|
|
|
2005-05-12 07:37:22 +08:00
|
|
|
cpu->sys += PERF_VAL_CPU(PERF_IX_CPU_SYS);
|
|
|
|
cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER);
|
2004-11-03 07:17:18 +08:00
|
|
|
get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
|
2005-02-19 04:13:17 +08:00
|
|
|
cpu->nice = cpu->wait = 0; /*N/A*/
|
|
|
|
|
|
|
|
/*XXX adding up too much here if xeon, but not using this atm*/
|
2004-06-22 06:37:04 +08:00
|
|
|
cpu->total += cpu->sys + cpu->user + cpu->idle;
|
2004-06-23 13:21:13 +08:00
|
|
|
|
|
|
|
inst = PdhNextInstance(inst);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-02-19 04:13:17 +08:00
|
|
|
static int sigar_cpu_list_ntsys_get(sigar_t *sigar,
|
|
|
|
sigar_cpu_list_t *cpulist)
|
|
|
|
{
|
|
|
|
DWORD retval, num;
|
|
|
|
int status, i, j, hthread=0;
|
|
|
|
/* XXX unhardcode 16 */
|
|
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
|
|
|
|
/* into the lungs of hell */
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation,
|
2005-02-19 04:13:17 +08:00
|
|
|
&info, sizeof(info), &retval);
|
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
num = retval/sizeof(info[0]);
|
|
|
|
|
|
|
|
sigar_cpu_count(sigar);
|
|
|
|
sigar_cpu_list_create(cpulist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if hyper-threading was detected and ncpu is less than
|
|
|
|
* the number of counter instances, assume there is a counter
|
|
|
|
* for each logical processor.
|
|
|
|
* XXX assuming this is correct until have something to test on.
|
|
|
|
*/
|
|
|
|
if (sigar->ht_enabled && ((sigar->ncpu * sigar->lcpu) == num)) {
|
|
|
|
hthread = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
sigar_cpu_t *cpu;
|
|
|
|
sigar_uint64_t idle, user, sys;
|
|
|
|
|
|
|
|
if (hthread && (i % sigar->lcpu)) {
|
|
|
|
/* merge times of logical processors */
|
|
|
|
cpu = &cpulist->data[cpulist->number-1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_CPU_LIST_GROW(cpulist);
|
|
|
|
cpu = &cpulist->data[cpulist->number++];
|
|
|
|
SIGAR_ZERO(cpu);
|
|
|
|
}
|
|
|
|
|
2005-05-12 07:17:39 +08:00
|
|
|
idle = NS100_2SEC(info[i].IdleTime.QuadPart);
|
|
|
|
user = NS100_2SEC(info[i].UserTime.QuadPart);
|
|
|
|
sys = NS100_2SEC(info[i].KernelTime.QuadPart -
|
|
|
|
info[i].IdleTime.QuadPart);
|
2005-02-19 04:13:17 +08:00
|
|
|
cpu->idle += idle;
|
|
|
|
cpu->user += user;
|
|
|
|
cpu->sys += sys;
|
|
|
|
cpu->nice = cpu->wait = 0; /*N/A*/
|
|
|
|
cpu->total += idle + user + sys;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar,
|
|
|
|
sigar_cpu_list_t *cpulist)
|
|
|
|
{
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(ntdll, FALSE);
|
|
|
|
if (sigar_NtQuerySystemInformation) {
|
2005-02-19 04:13:17 +08:00
|
|
|
return sigar_cpu_list_ntsys_get(sigar, cpulist);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sigar_cpu_list_perflib_get(sigar, cpulist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
|
|
|
|
sigar_uptime_t *uptime)
|
|
|
|
{
|
|
|
|
uptime->uptime = GetTickCount() / 1000;
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* there is no api for this info.
|
|
|
|
* closest i've seen is enumerating the entire process table
|
|
|
|
* and calculating an average based on process times.
|
|
|
|
*/
|
|
|
|
SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar,
|
|
|
|
sigar_loadavg_t *loadavg)
|
|
|
|
{
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
#define get_process_object(sigar, err) \
|
|
|
|
get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar,
|
|
|
|
sigar_proc_list_t *proclist)
|
|
|
|
{
|
|
|
|
PERF_OBJECT_TYPE *object;
|
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_DEFINITION *counter;
|
2004-06-23 01:51:38 +08:00
|
|
|
DWORD i, err;
|
2004-06-22 06:37:04 +08:00
|
|
|
DWORD perf_offsets[PERF_IX_MAX];
|
|
|
|
|
|
|
|
perf_offsets[PERF_IX_PID] = 0;
|
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
object = get_process_object(sigar, &err);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
if (!object) {
|
2004-06-23 01:51:38 +08:00
|
|
|
return err;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* note we assume here:
|
|
|
|
* block->NumObjectTypes == 1
|
|
|
|
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
|
|
|
|
*
|
|
|
|
* which should always be the case.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (i=0, counter = PdhFirstCounter(object);
|
|
|
|
i<object->NumCounters;
|
|
|
|
i++, counter = PdhNextCounter(counter))
|
|
|
|
{
|
|
|
|
DWORD offset = counter->CounterOffset;
|
|
|
|
|
|
|
|
switch (counter->CounterNameTitleIndex) {
|
|
|
|
case PERF_TITLE_PID:
|
|
|
|
perf_offsets[PERF_IX_PID] = offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-11 05:51:13 +08:00
|
|
|
sigar_proc_list_create(proclist);
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
for (i=0, inst = PdhFirstInstance(object);
|
|
|
|
i<object->NumInstances;
|
|
|
|
i++, inst = PdhNextInstance(inst))
|
|
|
|
{
|
|
|
|
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
|
2004-07-29 05:50:06 +08:00
|
|
|
DWORD pid = PERF_VAL(PERF_IX_PID);
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
continue; /* dont include the system Idle process */
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_PROC_LIST_GROW(proclist);
|
|
|
|
|
2004-07-29 05:50:06 +08:00
|
|
|
proclist->data[proclist->number++] = pid;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar,
|
|
|
|
sigar_proc_stat_t *procstat)
|
|
|
|
{
|
|
|
|
int status = /* XXX optimize */
|
|
|
|
sigar_proc_count(sigar, &procstat->total);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
|
|
|
|
|
|
|
|
static HANDLE open_process(sigar_pid_t pid)
|
|
|
|
{
|
|
|
|
return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_mem_t *procmem)
|
|
|
|
{
|
|
|
|
int status = get_proc_info(sigar, pid);
|
|
|
|
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
procmem->vsize = pinfo->vsize;
|
|
|
|
procmem->size = pinfo->size;
|
2005-11-02 02:48:33 +08:00
|
|
|
procmem->resident = pinfo->resident;
|
2004-12-06 07:36:48 +08:00
|
|
|
procmem->share = SIGAR_FIELD_NOTIMPL;
|
2005-11-02 03:15:23 +08:00
|
|
|
procmem->rss = pinfo->resident;
|
2005-11-24 01:51:19 +08:00
|
|
|
procmem->page_faults = pinfo->page_faults;
|
|
|
|
procmem->minor_faults = SIGAR_FIELD_NOTIMPL;
|
|
|
|
procmem->major_faults = SIGAR_FIELD_NOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY)
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int)
|
|
|
|
sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_cred_name_t *proccredname)
|
|
|
|
{
|
|
|
|
HANDLE proc, token;
|
|
|
|
DWORD len;
|
|
|
|
int success;
|
|
|
|
TOKEN_USER *user = NULL;
|
|
|
|
TOKEN_PRIMARY_GROUP *group = NULL;
|
|
|
|
SID_NAME_USE type;
|
|
|
|
char domain[SIGAR_CRED_NAME_MAX];
|
|
|
|
|
|
|
|
/* XXX cache lookup */
|
|
|
|
|
|
|
|
if (!(proc = open_process(pid))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!OpenProcessToken(proc, TOKEN_DAC, &token)) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(proc);
|
|
|
|
|
|
|
|
success =
|
|
|
|
!GetTokenInformation(token, TokenUser, NULL, 0, &len) &&
|
|
|
|
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
|
|
|
|
(user = malloc(len)) &&
|
|
|
|
GetTokenInformation(token, TokenUser, user, len, &len);
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
DWORD domain_len = sizeof(domain);
|
|
|
|
DWORD user_len = sizeof(proccredname->user);
|
|
|
|
|
|
|
|
success = LookupAccountSid(NULL, user->User.Sid,
|
|
|
|
proccredname->user, &user_len,
|
|
|
|
domain, &domain_len, &type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user != NULL) {
|
|
|
|
free(user);
|
|
|
|
}
|
|
|
|
if (!success) {
|
|
|
|
CloseHandle(token);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
success =
|
|
|
|
!GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) &&
|
|
|
|
(GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
|
|
|
|
(group = malloc(len)) &&
|
|
|
|
GetTokenInformation(token, TokenPrimaryGroup, group, len, &len);
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
DWORD domain_len = sizeof(domain);
|
|
|
|
DWORD group_len = sizeof(proccredname->group);
|
|
|
|
|
|
|
|
success = LookupAccountSid(NULL, group->PrimaryGroup,
|
|
|
|
proccredname->group, &group_len,
|
|
|
|
domain, &domain_len, &type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (group != NULL) {
|
|
|
|
free(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(token);
|
|
|
|
|
|
|
|
if (!success) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_cred_t *proccred)
|
|
|
|
{
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FILETIME2SEC(ft) \
|
2005-05-12 07:17:39 +08:00
|
|
|
NS100_2SEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime))
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_time_t *proctime)
|
|
|
|
{
|
|
|
|
HANDLE proc = open_process(pid);
|
|
|
|
FILETIME start_time, exit_time, system_time, user_time;
|
|
|
|
|
|
|
|
if (!proc) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GetProcessTimes(proc,
|
|
|
|
&start_time, &exit_time,
|
|
|
|
&system_time, &user_time))
|
|
|
|
{
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(proc);
|
|
|
|
|
|
|
|
if (start_time.dwHighDateTime) {
|
|
|
|
proctime->start_time = FileTimeToTime(&start_time) / 1000;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
proctime->start_time = 0;
|
|
|
|
}
|
|
|
|
|
2004-08-21 08:13:13 +08:00
|
|
|
proctime->user = FILETIME2SEC(user_time);
|
|
|
|
proctime->sys = FILETIME2SEC(system_time);
|
2004-08-21 08:25:07 +08:00
|
|
|
proctime->total = proctime->user + proctime->sys;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_state_t *procstate)
|
|
|
|
{
|
|
|
|
int status = get_proc_info(sigar, pid);
|
|
|
|
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(procstate->name, pinfo->name, sizeof(procstate->name));
|
|
|
|
procstate->state = pinfo->state;
|
|
|
|
procstate->ppid = pinfo->ppid;
|
|
|
|
procstate->priority = pinfo->priority;
|
2004-12-06 07:36:48 +08:00
|
|
|
procstate->nice = SIGAR_FIELD_NOTIMPL;
|
|
|
|
procstate->tty = SIGAR_FIELD_NOTIMPL;
|
2005-11-23 05:48:52 +08:00
|
|
|
procstate->threads = pinfo->threads;
|
2005-11-23 09:28:51 +08:00
|
|
|
procstate->processor = SIGAR_FIELD_NOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_proc_info(sigar_t *sigar, sigar_pid_t pid)
|
|
|
|
{
|
|
|
|
PERF_OBJECT_TYPE *object;
|
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_DEFINITION *counter;
|
2004-06-23 01:51:38 +08:00
|
|
|
DWORD i, err;
|
2004-06-22 06:37:04 +08:00
|
|
|
DWORD perf_offsets[PERF_IX_MAX];
|
|
|
|
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
|
|
|
|
time_t timenow = time(NULL);
|
|
|
|
|
|
|
|
if (pinfo->pid == pid) {
|
|
|
|
if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&perf_offsets, 0, sizeof(perf_offsets));
|
|
|
|
|
2004-06-23 01:51:38 +08:00
|
|
|
object = get_process_object(sigar, &err);
|
|
|
|
|
|
|
|
if (object == NULL) {
|
|
|
|
return err;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2004-08-11 05:51:13 +08:00
|
|
|
pinfo->pid = pid;
|
|
|
|
pinfo->mtime = timenow;
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
/*
|
|
|
|
* note we assume here:
|
|
|
|
* block->NumObjectTypes == 1
|
|
|
|
* object->ObjectNameTitleIndex == PERF_TITLE_PROC
|
|
|
|
*
|
|
|
|
* which should always be the case.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (i=0, counter = PdhFirstCounter(object);
|
|
|
|
i<object->NumCounters;
|
|
|
|
i++, counter = PdhNextCounter(counter))
|
|
|
|
{
|
|
|
|
DWORD offset = counter->CounterOffset;
|
|
|
|
|
|
|
|
switch (counter->CounterNameTitleIndex) {
|
|
|
|
case PERF_TITLE_CPUTIME:
|
|
|
|
perf_offsets[PERF_IX_CPUTIME] = offset;
|
|
|
|
break;
|
2005-11-24 01:51:19 +08:00
|
|
|
case PERF_TITLE_PAGE_FAULTS:
|
|
|
|
perf_offsets[PERF_IX_PAGE_FAULTS] = offset;
|
|
|
|
break;
|
2004-06-22 06:37:04 +08:00
|
|
|
case PERF_TITLE_MEM_VSIZE:
|
|
|
|
perf_offsets[PERF_IX_MEM_VSIZE] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_MEM_SIZE:
|
|
|
|
perf_offsets[PERF_IX_MEM_SIZE] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_MEM_PRIV:
|
|
|
|
perf_offsets[PERF_IX_MEM_PRIV] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_THREAD_CNT:
|
|
|
|
perf_offsets[PERF_IX_THREAD_CNT] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_HANDLE_CNT:
|
|
|
|
perf_offsets[PERF_IX_HANDLE_CNT] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_PID:
|
|
|
|
perf_offsets[PERF_IX_PID] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_PPID:
|
|
|
|
perf_offsets[PERF_IX_PPID] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_PRIORITY:
|
|
|
|
perf_offsets[PERF_IX_PRIORITY] = offset;
|
|
|
|
break;
|
|
|
|
case PERF_TITLE_START_TIME:
|
|
|
|
perf_offsets[PERF_IX_START_TIME] = offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0, inst = PdhFirstInstance(object);
|
|
|
|
i<object->NumInstances;
|
|
|
|
i++, inst = PdhNextInstance(inst))
|
|
|
|
{
|
|
|
|
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
|
|
|
|
sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID);
|
|
|
|
|
|
|
|
if (this_pid != pid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pinfo->state = 'R'; /* XXX? */
|
|
|
|
SIGAR_W2A(PdhInstanceName(inst),
|
|
|
|
pinfo->name, sizeof(pinfo->name));
|
|
|
|
|
|
|
|
pinfo->size = PERF_VAL(PERF_IX_MEM_SIZE);
|
|
|
|
pinfo->vsize = PERF_VAL(PERF_IX_MEM_VSIZE);
|
2005-11-02 02:48:33 +08:00
|
|
|
pinfo->resident = PERF_VAL(PERF_IX_MEM_PRIV);
|
2004-06-22 06:37:04 +08:00
|
|
|
pinfo->ppid = PERF_VAL(PERF_IX_PPID);
|
|
|
|
pinfo->priority = PERF_VAL(PERF_IX_PRIORITY);
|
|
|
|
pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT);
|
2005-11-23 05:48:52 +08:00
|
|
|
pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT);
|
2005-11-24 01:51:19 +08:00
|
|
|
pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-08-11 06:24:12 +08:00
|
|
|
return SIGAR_NO_SUCH_PROCESS;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
2004-07-29 05:47:14 +08:00
|
|
|
static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_args_t *procargs)
|
|
|
|
{
|
|
|
|
int status;
|
2004-08-03 10:45:26 +08:00
|
|
|
char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg;
|
2004-07-29 05:47:14 +08:00
|
|
|
HANDLE proc = open_process(pid);
|
|
|
|
|
|
|
|
if (!proc) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
2004-08-03 11:06:25 +08:00
|
|
|
status = sigar_proc_args_peb_get(sigar, proc, procargs);
|
2004-07-29 05:47:14 +08:00
|
|
|
|
|
|
|
CloseHandle(proc);
|
|
|
|
|
2004-08-03 11:06:25 +08:00
|
|
|
return status;
|
2004-07-29 05:47:14 +08:00
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_args_t *procargs)
|
|
|
|
{
|
|
|
|
if (pid == sigar->pid) {
|
2004-08-03 11:25:17 +08:00
|
|
|
return sigar_parse_proc_args(sigar, NULL, procargs);
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sigar_remote_proc_args_get(sigar, pid, procargs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_env_t *procenv)
|
|
|
|
{
|
|
|
|
UCHAR *ptr, *env;
|
|
|
|
|
|
|
|
env = ptr = (UCHAR*)GetEnvironmentStrings();
|
|
|
|
|
|
|
|
while (*ptr) {
|
|
|
|
char *val;
|
|
|
|
int klen, vlen, status;
|
|
|
|
char key[128]; /* XXX is there a max key size? */
|
|
|
|
|
|
|
|
if (*ptr == '=') {
|
|
|
|
ptr += strlen(ptr)+1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = strchr(ptr, '=');
|
|
|
|
|
|
|
|
if (val == NULL) {
|
|
|
|
break; /*XXX*/
|
|
|
|
}
|
|
|
|
|
|
|
|
klen = val - ptr;
|
|
|
|
SIGAR_SSTRCPY(key, ptr);
|
|
|
|
key[klen] = '\0';
|
|
|
|
++val;
|
|
|
|
|
|
|
|
vlen = strlen(val);
|
|
|
|
|
|
|
|
status = procenv->env_getter(procenv->data,
|
|
|
|
key, klen, val, vlen);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
/* not an error; just stop iterating */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += klen + 1 + vlen + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeEnvironmentStrings(env);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_env_t *procenv)
|
|
|
|
{
|
|
|
|
FARPROC rgetenv, fstrlen;
|
|
|
|
HANDLE proc, thread, kdll;
|
|
|
|
PVOID data=NULL;
|
|
|
|
const char *key;
|
|
|
|
char *value;
|
|
|
|
DWORD rv, thrid, bytes, datalen=0, size;
|
|
|
|
LPVOID addr;
|
|
|
|
|
|
|
|
if (!(kdll = GetModuleHandle("msvcrt.dll"))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(rgetenv = GetProcAddress(kdll, "getenv"))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(kdll = GetModuleHandle("kernel32.dll"))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(fstrlen = GetProcAddress(kdll, "lstrlenA"))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(proc = OpenProcess(MAXIMUM_ALLOWED, 0, (DWORD)pid))) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
key = procenv->key;
|
|
|
|
size = procenv->klen+1;
|
|
|
|
addr = VirtualAllocEx(proc, NULL, size,
|
|
|
|
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
if (!addr) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WriteProcessMemory(proc, addr, (char*)&key[0], size, 0)) {
|
|
|
|
VirtualFreeEx(proc, addr, size, 0);
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
thread = CreateRemoteThread(proc, NULL, 0,
|
|
|
|
(LPTHREAD_START_ROUTINE)rgetenv,
|
|
|
|
addr, 0, &thrid);
|
|
|
|
if (!thread) {
|
|
|
|
VirtualFreeEx(proc, addr, size, 0);
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
WaitForSingleObject(thread, INFINITE);
|
|
|
|
GetExitCodeThread(thread, (LPDWORD)(&data));
|
|
|
|
CloseHandle(thread);
|
|
|
|
VirtualFreeEx(proc, addr, size, 0);
|
|
|
|
|
|
|
|
if (!data) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
thread = CreateRemoteThread(proc, NULL, 0,
|
|
|
|
(LPTHREAD_START_ROUTINE)fstrlen,
|
|
|
|
data, 0, &thrid);
|
|
|
|
if (!thread) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
WaitForSingleObject(thread, INFINITE);
|
|
|
|
GetExitCodeThread(thread, &datalen);
|
|
|
|
CloseHandle(thread);
|
|
|
|
|
|
|
|
if (!datalen) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
value = HeapAlloc(GetProcessHeap(),
|
|
|
|
HEAP_ZERO_MEMORY,
|
|
|
|
datalen);
|
|
|
|
|
|
|
|
if (!value) {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReadProcessMemory(proc, data, value,
|
|
|
|
datalen+1, &bytes))
|
|
|
|
{
|
|
|
|
procenv->env_getter(procenv->data,
|
|
|
|
key, strlen(key),
|
|
|
|
value, bytes-1);
|
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, value);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CloseHandle(proc);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(proc);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_env_t *procenv)
|
|
|
|
{
|
|
|
|
if (pid == sigar->pid) {
|
|
|
|
if (procenv->type == SIGAR_PROC_ENV_KEY) {
|
|
|
|
char value[32767]; /* max size from msdn docs */
|
|
|
|
DWORD retval =
|
|
|
|
GetEnvironmentVariable(procenv->key, value, sizeof(value));
|
|
|
|
|
|
|
|
if (retval == 0) {
|
|
|
|
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
else if (retval > sizeof(value)) {
|
|
|
|
/* XXX shouldnt happen */
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
procenv->env_getter(procenv->data,
|
|
|
|
procenv->key, procenv->klen,
|
|
|
|
value, retval);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sigar_local_proc_env_get(sigar, pid, procenv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (procenv->type == SIGAR_PROC_ENV_KEY) {
|
|
|
|
return sigar_remote_proc_env_get(sigar, pid, procenv);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_fd_t *procfd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
sigar_win32_pinfo_t *pinfo = &sigar->pinfo;
|
|
|
|
|
|
|
|
pinfo->pid = -1; /* force update */
|
|
|
|
if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
procfd->total = pinfo->handles;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_exe_t *procexe)
|
|
|
|
{
|
|
|
|
int status = SIGAR_OK;
|
|
|
|
HANDLE proc = open_process(pid);
|
|
|
|
|
|
|
|
if (!proc) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
2004-08-02 04:31:42 +08:00
|
|
|
status = sigar_proc_exe_peb_get(sigar, proc, procexe);
|
2004-08-02 04:42:18 +08:00
|
|
|
if (procexe->cwd[0] != '\0') {
|
|
|
|
/* strip trailing '\' */
|
|
|
|
int len = strlen(procexe->cwd);
|
|
|
|
if (procexe->cwd[len-1] == '\\') {
|
|
|
|
procexe->cwd[len-1] = '\0';
|
|
|
|
}
|
|
|
|
/* uppercase driver letter */
|
|
|
|
procexe->cwd[0] = toupper(procexe->cwd[0]);
|
|
|
|
/* e.g. C:\ */
|
|
|
|
strncpy(procexe->root, procexe->cwd, 3);
|
|
|
|
procexe->root[3] = '\0';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
procexe->root[0] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (procexe->name[0] != '\0') {
|
|
|
|
/* uppercase driver letter */
|
|
|
|
procexe->name[0] = toupper(procexe->name[0]);
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_EnumProcessModules \
|
|
|
|
sigar->psapi.enum_modules.func
|
|
|
|
|
|
|
|
#define sigar_GetModuleFileNameEx \
|
|
|
|
sigar->psapi.get_module_name.func
|
|
|
|
|
2005-05-14 04:56:17 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid,
|
|
|
|
sigar_proc_modules_t *procmods)
|
2004-06-22 14:12:51 +08:00
|
|
|
{
|
2005-05-14 04:56:17 +08:00
|
|
|
HANDLE proc;
|
|
|
|
HMODULE modules[1024];
|
|
|
|
DWORD size = 0;
|
|
|
|
unsigned int i;
|
2004-06-22 14:12:51 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) {
|
2005-05-14 04:56:17 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
2004-06-22 14:12:51 +08:00
|
|
|
}
|
|
|
|
|
2005-05-14 04:56:17 +08:00
|
|
|
if (!(proc = open_process(pid))) {
|
2004-06-22 14:12:51 +08:00
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) {
|
2005-05-14 04:56:17 +08:00
|
|
|
CloseHandle(proc);
|
2004-06-22 14:12:51 +08:00
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
2005-05-14 04:56:17 +08:00
|
|
|
for (i=0; i<(size/sizeof(HMODULE)); i++) {
|
|
|
|
int status;
|
|
|
|
char name[MAX_PATH];
|
2004-06-22 14:12:51 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_GetModuleFileNameEx(proc, modules[i],
|
|
|
|
name, sizeof(name)))
|
|
|
|
{
|
2005-05-14 04:56:17 +08:00
|
|
|
continue;
|
|
|
|
}
|
2004-06-22 14:12:51 +08:00
|
|
|
|
2005-05-14 04:56:17 +08:00
|
|
|
status = procmods->module_getter(procmods->data,
|
|
|
|
name, strlen(name));
|
2004-06-22 14:12:51 +08:00
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
/* not an error; just stop iterating */
|
|
|
|
break;
|
|
|
|
}
|
2005-05-14 04:56:17 +08:00
|
|
|
}
|
2004-06-22 14:12:51 +08:00
|
|
|
|
2005-05-14 04:56:17 +08:00
|
|
|
CloseHandle(proc);
|
2004-06-22 14:12:51 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-11-17 12:56:00 +08:00
|
|
|
#define FT2INT64(ft) \
|
|
|
|
((__int64)((__int64)(ft).dwHighDateTime << 32 | \
|
|
|
|
(__int64)(ft).dwLowDateTime))
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar,
|
|
|
|
sigar_uint64_t id,
|
|
|
|
sigar_thread_cpu_t *cpu)
|
|
|
|
{
|
|
|
|
FILETIME start, exit, sys, user;
|
|
|
|
DWORD retval;
|
|
|
|
|
|
|
|
if (id != 0) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = GetThreadTimes(GetCurrentThread(),
|
|
|
|
&start, &exit, &sys, &user);
|
|
|
|
|
|
|
|
if (retval == 0) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu->user = FT2INT64(user) * 100;
|
|
|
|
cpu->sys = FT2INT64(sys) * 100;
|
|
|
|
cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
int sigar_os_fs_type_get(sigar_file_system_t *fsp)
|
|
|
|
{
|
|
|
|
return fsp->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
|
|
|
|
sigar_file_system_list_t *fslist)
|
|
|
|
{
|
|
|
|
sigar_file_system_t *fsp;
|
|
|
|
char name[256];
|
|
|
|
char *ptr = name;
|
|
|
|
/* XXX: hmm, Find{First,Next}Volume not available in my sdk */
|
|
|
|
DWORD len = GetLogicalDriveStringsA(sizeof(name), name);
|
|
|
|
|
|
|
|
if (len == 0) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_file_system_list_create(fslist);
|
|
|
|
|
|
|
|
while (*ptr) {
|
|
|
|
DWORD flags, serialnum=0;
|
|
|
|
char fsname[1024];
|
|
|
|
UINT type;
|
|
|
|
|
|
|
|
fsname[0] = '\0';
|
|
|
|
|
|
|
|
GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
|
|
|
|
&flags, fsname, sizeof(fsname));
|
|
|
|
|
|
|
|
type = GetDriveType(ptr);
|
|
|
|
|
|
|
|
if (!serialnum && (type == DRIVE_FIXED)) {
|
|
|
|
ptr += strlen(ptr)+1;
|
|
|
|
continue; /* ignore unformatted partitions */
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
|
|
|
|
|
|
|
|
fsp = &fslist->data[fslist->number++];
|
|
|
|
|
|
|
|
SIGAR_SSTRCPY(fsp->dir_name, ptr);
|
|
|
|
SIGAR_SSTRCPY(fsp->dev_name, ptr);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case DRIVE_FIXED:
|
|
|
|
fsp->type = SIGAR_FSTYPE_LOCAL_DISK;
|
|
|
|
break;
|
|
|
|
case DRIVE_REMOTE:
|
|
|
|
fsp->type = SIGAR_FSTYPE_NETWORK;
|
|
|
|
break;
|
|
|
|
case DRIVE_CDROM:
|
|
|
|
fsp->type = SIGAR_FSTYPE_CDROM;
|
|
|
|
break;
|
|
|
|
case DRIVE_RAMDISK:
|
|
|
|
fsp->type = SIGAR_FSTYPE_RAM_DISK;
|
|
|
|
break;
|
|
|
|
case DRIVE_REMOVABLE:
|
|
|
|
/* XXX */
|
|
|
|
default:
|
|
|
|
fsp->type = SIGAR_FSTYPE_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we set fsp->type, just looking up sigar.c:fstype_names[type] */
|
|
|
|
sigar_fs_type_get(fsp);
|
|
|
|
|
|
|
|
if (*fsname == '\0') {
|
|
|
|
SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += strlen(ptr)+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-12-05 09:18:57 +08:00
|
|
|
static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar,
|
|
|
|
DWORD *perf_offsets,
|
|
|
|
DWORD *num, DWORD *err)
|
|
|
|
{
|
2005-11-09 02:16:03 +08:00
|
|
|
PERF_OBJECT_TYPE *object =
|
|
|
|
get_perf_object(sigar, PERF_TITLE_DISK_KEY, err);
|
2004-12-05 09:18:57 +08:00
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_DEFINITION *counter;
|
2005-11-09 02:16:03 +08:00
|
|
|
DWORD i, found=0;
|
2004-12-05 09:18:57 +08:00
|
|
|
|
|
|
|
if (!object) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0, counter = PdhFirstCounter(object);
|
|
|
|
i<object->NumCounters;
|
|
|
|
i++, counter = PdhNextCounter(counter))
|
|
|
|
{
|
|
|
|
DWORD offset = counter->CounterOffset;
|
|
|
|
|
|
|
|
switch (counter->CounterNameTitleIndex) {
|
|
|
|
case PERF_TITLE_DISK_READ:
|
|
|
|
perf_offsets[PERF_IX_DISK_READ] = offset;
|
2005-11-09 02:16:03 +08:00
|
|
|
found = 1;
|
2004-12-05 09:18:57 +08:00
|
|
|
break;
|
|
|
|
case PERF_TITLE_DISK_WRITE:
|
|
|
|
perf_offsets[PERF_IX_DISK_WRITE] = offset;
|
2005-11-09 02:16:03 +08:00
|
|
|
found = 1;
|
2004-12-05 09:18:57 +08:00
|
|
|
break;
|
2005-04-07 09:23:49 +08:00
|
|
|
case PERF_TITLE_DISK_READ_BYTES:
|
|
|
|
perf_offsets[PERF_IX_DISK_READ_BYTES] = offset;
|
2005-11-09 02:16:03 +08:00
|
|
|
found = 1;
|
2005-04-07 09:23:49 +08:00
|
|
|
break;
|
|
|
|
case PERF_TITLE_DISK_WRITE_BYTES:
|
|
|
|
perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset;
|
2005-11-09 02:16:03 +08:00
|
|
|
found = 1;
|
2005-04-07 09:23:49 +08:00
|
|
|
break;
|
|
|
|
case PERF_TITLE_DISK_QUEUE:
|
|
|
|
perf_offsets[PERF_IX_DISK_QUEUE] = offset;
|
2005-11-09 02:16:03 +08:00
|
|
|
found = 1;
|
2005-04-07 09:23:49 +08:00
|
|
|
break;
|
2004-12-05 09:18:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-09 02:16:03 +08:00
|
|
|
if (!found) {
|
|
|
|
*err = ENOENT;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-12-05 09:18:57 +08:00
|
|
|
if (num) {
|
|
|
|
*num = object->NumInstances;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PdhFirstInstance(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_disk_metrics(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
DWORD i, err;
|
|
|
|
PERF_OBJECT_TYPE *object =
|
2005-02-19 04:18:40 +08:00
|
|
|
get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err);
|
2004-12-05 09:18:57 +08:00
|
|
|
PERF_INSTANCE_DEFINITION *inst;
|
|
|
|
PERF_COUNTER_DEFINITION *counter;
|
|
|
|
DWORD perf_offsets[PERF_IX_DISK_MAX];
|
|
|
|
|
|
|
|
if (!object) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&perf_offsets, 0, sizeof(perf_offsets));
|
|
|
|
inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err);
|
|
|
|
|
|
|
|
if (!inst) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0, inst = PdhFirstInstance(object);
|
|
|
|
i<object->NumInstances;
|
|
|
|
i++, inst = PdhNextInstance(inst))
|
|
|
|
{
|
|
|
|
char drive[MAX_PATH];
|
|
|
|
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
|
|
|
|
wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset);
|
|
|
|
|
|
|
|
SIGAR_W2A(name, drive, sizeof(drive));
|
|
|
|
|
2005-04-28 02:54:42 +08:00
|
|
|
if (sigar_isdigit(*name)) {
|
|
|
|
char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */
|
|
|
|
|
|
|
|
if (ptr) {
|
|
|
|
++ptr;
|
|
|
|
SIGAR_SSTRCPY(drive, ptr);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* XXX NT is a number only "0", how to map? */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-12-05 09:18:57 +08:00
|
|
|
if (strnEQ(drive, dirname, 2)) {
|
|
|
|
fsusage->disk_reads = PERF_VAL(PERF_IX_DISK_READ);
|
|
|
|
fsusage->disk_writes = PERF_VAL(PERF_IX_DISK_WRITE);
|
2005-04-07 09:23:49 +08:00
|
|
|
fsusage->disk_read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES);
|
|
|
|
fsusage->disk_write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES);
|
|
|
|
fsusage->disk_queue = PERF_VAL(PERF_IX_DISK_QUEUE);
|
2004-12-05 09:18:57 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(int)
|
|
|
|
sigar_file_system_usage_get(sigar_t *sigar,
|
|
|
|
const char *dirname,
|
|
|
|
sigar_file_system_usage_t *fsusage)
|
|
|
|
{
|
|
|
|
BOOL retval;
|
|
|
|
ULARGE_INTEGER avail, total, free;
|
2004-12-05 09:18:57 +08:00
|
|
|
int status;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
/* prevent dialog box if A:\ drive is empty */
|
|
|
|
UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
|
|
|
|
retval = GetDiskFreeSpaceEx(dirname,
|
|
|
|
&avail, &total, &free);
|
|
|
|
|
|
|
|
/* restore previous error mode */
|
|
|
|
SetErrorMode(errmode);
|
|
|
|
|
|
|
|
if (!retval) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
fsusage->total = total.QuadPart / 1024;
|
|
|
|
fsusage->free = free.QuadPart / 1024;
|
|
|
|
fsusage->avail = avail.QuadPart / 1024;
|
2005-04-27 03:55:21 +08:00
|
|
|
fsusage->used = fsusage->total - fsusage->free;
|
2004-06-22 06:37:04 +08:00
|
|
|
fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage);
|
|
|
|
|
2004-12-06 07:36:48 +08:00
|
|
|
/* N/A */
|
|
|
|
fsusage->files = SIGAR_FIELD_NOTIMPL;
|
|
|
|
fsusage->free_files = SIGAR_FIELD_NOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2004-12-05 09:18:57 +08:00
|
|
|
status = get_disk_metrics(sigar, dirname, fsusage);
|
|
|
|
if (status != SIGAR_OK) {
|
2004-12-06 07:42:23 +08:00
|
|
|
SIGAR_DISK_STATS_NOTIMPL(fsusage);
|
2004-12-05 09:18:57 +08:00
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2004-07-10 12:44:45 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar,
|
|
|
|
sigar_cpu_info_list_t *cpu_infos)
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
int i, status;
|
|
|
|
sigar_cpu_info_t *info;
|
|
|
|
|
|
|
|
sigar_cpu_count(sigar);
|
|
|
|
|
2004-07-10 12:44:45 +08:00
|
|
|
sigar_cpu_info_list_create(cpu_infos);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
info = &cpu_infos->data[cpu_infos->number++];
|
|
|
|
|
|
|
|
status = sigar_cpu_info_get(sigar, info);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sigar->ncpu > 1) {
|
|
|
|
for (i=1; i<sigar->ncpu; i++) {
|
2004-07-10 12:44:45 +08:00
|
|
|
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
memcpy(&cpu_infos->data[cpu_infos->number++],
|
|
|
|
info, sizeof(*info));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetNetworkParams \
|
|
|
|
sigar->iphlpapi.get_net_params.func
|
|
|
|
|
|
|
|
#define sigar_GetAdaptersInfo \
|
|
|
|
sigar->iphlpapi.get_adapters_info.func
|
|
|
|
|
2005-12-21 10:45:38 +08:00
|
|
|
static int sigar_get_adapters_info(sigar_t *sigar,
|
|
|
|
PIP_ADAPTER_INFO *adapter)
|
2005-12-21 10:31:06 +08:00
|
|
|
{
|
|
|
|
ULONG size = sigar->ifconf_len;
|
|
|
|
DWORD rc;
|
|
|
|
|
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
|
|
|
|
if (!sigar_GetAdaptersInfo) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
2005-12-21 10:45:38 +08:00
|
|
|
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
|
|
|
|
rc = sigar_GetAdaptersInfo(*adapter, &size);
|
2005-12-21 10:31:06 +08:00
|
|
|
|
|
|
|
if (rc == ERROR_BUFFER_OVERFLOW) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"GetAdaptersInfo "
|
|
|
|
"realloc ifconf_buf old=%d, new=%d",
|
|
|
|
sigar->ifconf_len, size);
|
|
|
|
sigar->ifconf_len = size;
|
|
|
|
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
|
|
|
|
sigar->ifconf_len);
|
|
|
|
|
2005-12-21 10:45:38 +08:00
|
|
|
*adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf;
|
|
|
|
rc = sigar_GetAdaptersInfo(*adapter, &size);
|
2005-12-21 10:31:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != NO_ERROR) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-12 06:40:31 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar,
|
|
|
|
sigar_net_info_t *netinfo)
|
|
|
|
{
|
2005-12-21 10:31:06 +08:00
|
|
|
PIP_ADAPTER_INFO adapter;
|
2005-07-12 07:54:39 +08:00
|
|
|
FIXED_INFO *info;
|
|
|
|
ULONG len = 0;
|
2005-07-12 06:40:31 +08:00
|
|
|
IP_ADDR_STRING *ip;
|
2005-07-12 07:54:39 +08:00
|
|
|
DWORD rc;
|
2005-12-21 07:09:34 +08:00
|
|
|
|
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
2005-07-12 07:54:39 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_GetNetworkParams) {
|
2005-07-12 06:40:31 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_ZERO(netinfo);
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetNetworkParams(NULL, &len);
|
2005-07-12 07:54:39 +08:00
|
|
|
if (rc != ERROR_BUFFER_OVERFLOW) {
|
|
|
|
return rc;
|
|
|
|
}
|
2005-07-12 06:40:31 +08:00
|
|
|
|
2005-07-12 07:54:39 +08:00
|
|
|
info = malloc(len);
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetNetworkParams(info, &len);
|
2005-07-12 07:54:39 +08:00
|
|
|
if (rc != NO_ERROR) {
|
|
|
|
free(info);
|
|
|
|
return rc;
|
2005-07-12 06:40:31 +08:00
|
|
|
}
|
|
|
|
|
2005-07-12 07:54:39 +08:00
|
|
|
SIGAR_SSTRCPY(netinfo->host_name, info->HostName);
|
|
|
|
SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName);
|
2005-07-12 06:40:31 +08:00
|
|
|
SIGAR_SSTRCPY(netinfo->primary_dns,
|
2005-07-12 07:54:39 +08:00
|
|
|
info->DnsServerList.IpAddress.String);
|
2005-07-12 06:40:31 +08:00
|
|
|
|
2005-07-12 07:54:39 +08:00
|
|
|
if ((ip = info->DnsServerList.Next)) {
|
2005-07-12 06:40:31 +08:00
|
|
|
SIGAR_SSTRCPY(netinfo->secondary_dns,
|
|
|
|
ip->IpAddress.String);
|
|
|
|
}
|
2005-07-12 07:54:39 +08:00
|
|
|
|
|
|
|
free(info);
|
2005-07-12 06:40:31 +08:00
|
|
|
|
2005-12-21 10:45:38 +08:00
|
|
|
if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) {
|
2005-12-21 10:31:06 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2005-07-12 07:24:00 +08:00
|
|
|
|
2005-12-21 10:31:06 +08:00
|
|
|
while (adapter) {
|
|
|
|
/* should only be 1 */
|
|
|
|
if (adapter->GatewayList.IpAddress.String[0]) {
|
|
|
|
SIGAR_SSTRCPY(netinfo->default_gateway,
|
|
|
|
adapter->GatewayList.IpAddress.String);
|
2005-07-12 07:24:00 +08:00
|
|
|
}
|
2005-07-18 01:46:07 +08:00
|
|
|
#if 0
|
2005-12-21 10:31:06 +08:00
|
|
|
if (apapters->DhcpEnabled) {
|
|
|
|
SIGAR_SSTRCPY(netinfo->dhcp_server,
|
|
|
|
apdaters->DhcpServer.IpAddress.String);
|
2005-07-12 07:24:00 +08:00
|
|
|
}
|
2005-12-21 10:31:06 +08:00
|
|
|
#endif
|
|
|
|
adapter = adapter->Next;
|
2005-07-12 07:24:00 +08:00
|
|
|
}
|
|
|
|
|
2005-07-12 06:40:31 +08:00
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetIpForwardTable \
|
|
|
|
sigar->iphlpapi.get_ipforward_table.func
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar,
|
|
|
|
sigar_net_route_list_t *routelist)
|
|
|
|
{
|
2005-12-21 07:09:34 +08:00
|
|
|
PMIB_IPFORWARDTABLE buffer = NULL;
|
2004-06-22 06:37:04 +08:00
|
|
|
ULONG bufsize = 0;
|
|
|
|
DWORD rc, i;
|
|
|
|
MIB_IPFORWARDTABLE *ipt;
|
|
|
|
sigar_net_route_t *route;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
if (!sigar_GetIpForwardTable) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = malloc(bufsize);
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc != NO_ERROR) {
|
|
|
|
free(buffer);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
sigar_net_route_list_create(routelist);
|
|
|
|
routelist->size = routelist->number = 0;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
ipt = buffer;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
for (i=0; i<ipt->dwNumEntries; i++) {
|
|
|
|
MIB_IPFORWARDROW *ipr = ipt->table + i;
|
|
|
|
|
|
|
|
SIGAR_NET_ROUTE_LIST_GROW(routelist);
|
|
|
|
|
|
|
|
route = &routelist->data[routelist->number++];
|
|
|
|
SIGAR_ZERO(route); /* XXX: other fields */
|
|
|
|
|
|
|
|
route->destination = ipr->dwForwardDest;
|
|
|
|
route->mask = ipr->dwForwardMask;
|
|
|
|
route->gateway = ipr->dwForwardNextHop;
|
2005-07-15 12:13:45 +08:00
|
|
|
route->metric = ipr->dwForwardMetric1;
|
2005-07-13 02:45:28 +08:00
|
|
|
|
|
|
|
route->flags = SIGAR_RTF_UP;
|
|
|
|
if ((route->destination == 0) &&
|
|
|
|
(route->mask == 0))
|
|
|
|
{
|
|
|
|
route->flags |= SIGAR_RTF_GATEWAY;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetIfTable \
|
|
|
|
sigar->iphlpapi.get_if_table.func
|
|
|
|
|
2005-12-21 10:49:18 +08:00
|
|
|
static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
|
2005-12-20 08:09:32 +08:00
|
|
|
{
|
|
|
|
ULONG size = sigar->ifconf_len;
|
|
|
|
DWORD rc;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
|
|
|
|
if (!sigar_GetIfTable) {
|
2005-12-20 08:09:32 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
2005-12-21 10:49:18 +08:00
|
|
|
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
|
|
|
|
rc = sigar_GetIfTable(*iftable, &size, FALSE);
|
2005-12-20 08:09:32 +08:00
|
|
|
|
|
|
|
if (rc == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
|
2005-12-21 10:31:06 +08:00
|
|
|
"GetIfTable "
|
2005-12-20 08:09:32 +08:00
|
|
|
"realloc ifconf_buf old=%d, new=%d",
|
|
|
|
sigar->ifconf_len, size);
|
|
|
|
sigar->ifconf_len = size;
|
|
|
|
sigar->ifconf_buf = realloc(sigar->ifconf_buf,
|
|
|
|
sigar->ifconf_len);
|
|
|
|
|
2005-12-21 10:49:18 +08:00
|
|
|
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
|
|
|
|
rc = sigar_GetIfTable(*iftable, &size, FALSE);
|
2005-12-20 08:09:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rc != NO_ERROR) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(int)
|
|
|
|
sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
|
|
|
|
sigar_net_interface_stat_t *ifstat)
|
|
|
|
{
|
|
|
|
DWORD rc, i;
|
|
|
|
MIB_IFTABLE *ift;
|
|
|
|
MIB_IFROW *ifr;
|
|
|
|
DWORD lo=0, eth=0;
|
|
|
|
int status, type, inst;
|
|
|
|
|
2005-09-03 09:34:20 +08:00
|
|
|
if ((status = sigar_get_iftype(name, &type, &inst)) != SIGAR_OK) {
|
2004-06-22 06:37:04 +08:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2005-12-21 10:49:18 +08:00
|
|
|
if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
|
2005-12-20 08:09:32 +08:00
|
|
|
return status;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<ift->dwNumEntries; i++) {
|
|
|
|
ifr = ift->table + i;
|
|
|
|
|
|
|
|
if (!(ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
|
|
|
|
if ((type == IFTYPE_LO) && (inst == lo)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++lo;
|
|
|
|
}
|
|
|
|
else if (ifr->dwType == MIB_IF_TYPE_ETHERNET) {
|
|
|
|
if ((type == IFTYPE_ETH) && (inst == eth)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++eth;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ifr) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifstat->rx_bytes = ifr->dwInOctets;
|
|
|
|
ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts;
|
|
|
|
ifstat->rx_errors = ifr->dwInErrors;
|
|
|
|
ifstat->rx_dropped = ifr->dwInDiscards;
|
2004-12-06 07:36:48 +08:00
|
|
|
ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL;
|
2005-05-14 08:02:33 +08:00
|
|
|
ifstat->rx_frame = SIGAR_FIELD_NOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
ifstat->tx_bytes = ifr->dwOutOctets;
|
|
|
|
ifstat->tx_packets = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts;
|
|
|
|
ifstat->tx_errors = ifr->dwOutErrors;
|
|
|
|
ifstat->tx_dropped = ifr->dwOutDiscards;
|
2004-12-06 07:36:48 +08:00
|
|
|
ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL;
|
|
|
|
ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL;
|
|
|
|
ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-05-07 14:00:55 +08:00
|
|
|
#define IS_TCP_SERVER(state, flags) \
|
|
|
|
((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN))
|
|
|
|
|
|
|
|
#define IS_TCP_CLIENT(state, flags) \
|
|
|
|
((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN))
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetTcpTable \
|
|
|
|
sigar->iphlpapi.get_tcp_table.func
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
static int net_conn_get_tcp(sigar_t *sigar,
|
|
|
|
sigar_net_connection_list_t *connlist,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
int status;
|
2005-12-21 07:09:34 +08:00
|
|
|
DWORD rc, size=0, i;
|
2004-06-22 06:37:04 +08:00
|
|
|
PMIB_TCPTABLE tcp;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
|
|
|
|
if (!sigar_GetTcpTable) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = sigar_GetTcpTable(NULL, &size, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
2004-06-23 07:44:46 +08:00
|
|
|
tcp = malloc(size);
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetTcpTable(tcp, &size, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc) {
|
|
|
|
free(tcp);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < tcp->dwNumEntries; i++) {
|
|
|
|
sigar_net_connection_t conn;
|
|
|
|
DWORD state = tcp->table[i].dwState;
|
|
|
|
|
2005-05-07 14:00:55 +08:00
|
|
|
if (!(IS_TCP_SERVER(state, flags) ||
|
|
|
|
IS_TCP_CLIENT(state, flags)))
|
|
|
|
{
|
|
|
|
continue;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
conn.local_port = htons((WORD)tcp->table[i].dwLocalPort);
|
|
|
|
conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort);
|
|
|
|
|
|
|
|
conn.type = SIGAR_NETCONN_TCP;
|
|
|
|
|
2005-05-13 23:16:49 +08:00
|
|
|
sigar_inet_ntoa(sigar, tcp->table[i].dwLocalAddr,
|
|
|
|
conn.local_address);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-05-13 23:16:49 +08:00
|
|
|
sigar_inet_ntoa(sigar, tcp->table[i].dwRemoteAddr,
|
|
|
|
conn.remote_address);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-03-12 12:49:38 +08:00
|
|
|
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
|
|
|
|
|
2005-03-11 12:45:09 +08:00
|
|
|
switch (state) {
|
|
|
|
case MIB_TCP_STATE_CLOSED:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_CLOSE;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_LISTEN:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_LISTEN;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_SYN_SENT:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_SYN_SENT;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_SYN_RCVD:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_SYN_RECV;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_ESTAB:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_ESTABLISHED;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_FIN_WAIT1:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_FIN_WAIT1;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_FIN_WAIT2:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_FIN_WAIT2;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_CLOSE_WAIT:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_CLOSE_WAIT;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_CLOSING:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_CLOSING;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_LAST_ACK:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_LAST_ACK;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_TIME_WAIT:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_TIME_WAIT;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
case MIB_TCP_STATE_DELETE_TCB:
|
|
|
|
default:
|
2005-03-12 01:11:30 +08:00
|
|
|
conn.state = SIGAR_TCP_UNKNOWN;
|
2005-03-11 12:45:09 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_NET_CONNLIST_GROW(connlist);
|
|
|
|
memcpy(&connlist->data[connlist->number++],
|
|
|
|
&conn, sizeof(conn));
|
|
|
|
}
|
|
|
|
|
|
|
|
free(tcp);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-05-07 14:00:55 +08:00
|
|
|
#define IS_UDP_SERVER(conn, flags) \
|
|
|
|
((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port)
|
|
|
|
|
|
|
|
#define IS_UDP_CLIENT(state, flags) \
|
|
|
|
((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port)
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetUdpTable \
|
|
|
|
sigar->iphlpapi.get_udp_table.func
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
static int net_conn_get_udp(sigar_t *sigar,
|
|
|
|
sigar_net_connection_list_t *connlist,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
int status;
|
2005-12-21 07:09:34 +08:00
|
|
|
DWORD rc, size=0, i;
|
2004-06-22 06:37:04 +08:00
|
|
|
PMIB_UDPTABLE udp;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
|
|
|
|
if (!sigar_GetTcpTable) {
|
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = sigar_GetUdpTable(NULL, &size, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
2004-06-23 07:44:46 +08:00
|
|
|
udp = malloc(size);
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetUdpTable(udp, &size, FALSE);
|
2004-06-22 06:37:04 +08:00
|
|
|
if (rc) {
|
|
|
|
free(udp);
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < udp->dwNumEntries; i++) {
|
|
|
|
sigar_net_connection_t conn;
|
|
|
|
|
2005-05-07 14:00:55 +08:00
|
|
|
if (!(IS_UDP_SERVER(conn, flags) ||
|
|
|
|
IS_UDP_CLIENT(conn, flags)))
|
2004-06-22 06:37:04 +08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn.local_port = htons((WORD)udp->table[i].dwLocalPort);
|
2005-05-09 01:20:00 +08:00
|
|
|
conn.remote_port = 0;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
|
|
|
conn.type = SIGAR_NETCONN_UDP;
|
|
|
|
|
2005-05-13 23:16:49 +08:00
|
|
|
sigar_inet_ntoa(sigar, udp->table[i].dwLocalAddr,
|
|
|
|
conn.local_address);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-05-09 01:23:24 +08:00
|
|
|
SIGAR_SSTRCPY(conn.remote_address, "0.0.0.0");
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-03-12 12:49:38 +08:00
|
|
|
conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL;
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_NET_CONNLIST_GROW(connlist);
|
|
|
|
memcpy(&connlist->data[connlist->number++],
|
|
|
|
&conn, sizeof(conn));
|
|
|
|
}
|
|
|
|
|
|
|
|
free(udp);
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_DECLARE(int)
|
|
|
|
sigar_net_connection_list_get(sigar_t *sigar,
|
|
|
|
sigar_net_connection_list_t *connlist,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
sigar_net_connection_list_create(connlist);
|
|
|
|
|
|
|
|
if (flags & SIGAR_NETCONN_TCP) {
|
|
|
|
status = net_conn_get_tcp(sigar, connlist, flags);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & SIGAR_NETCONN_UDP) {
|
|
|
|
status = net_conn_get_udp(sigar, connlist, flags);
|
|
|
|
|
|
|
|
if (status != SIGAR_OK) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_GetTcpExTable \
|
|
|
|
sigar->iphlpapi.get_tcpx_table.func
|
|
|
|
|
|
|
|
#define sigar_GetUdpExTable \
|
|
|
|
sigar->iphlpapi.get_udpx_table.func
|
|
|
|
|
2004-06-22 06:37:04 +08:00
|
|
|
SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar,
|
2005-03-16 10:44:52 +08:00
|
|
|
int protocol,
|
2004-06-22 06:37:04 +08:00
|
|
|
unsigned long port,
|
|
|
|
sigar_pid_t *pid)
|
|
|
|
{
|
|
|
|
DWORD rc, i;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(iphlpapi, FALSE);
|
|
|
|
|
2005-03-20 11:20:28 +08:00
|
|
|
if (protocol == SIGAR_NETCONN_TCP) {
|
|
|
|
PMIB_TCPEXTABLE tcp;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_GetTcpExTable) {
|
2005-03-20 11:20:28 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
|
|
|
}
|
2005-03-16 11:49:54 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(),
|
|
|
|
2, 2);
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-03-20 11:20:28 +08:00
|
|
|
if (rc) {
|
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<tcp->dwNumEntries; i++) {
|
|
|
|
if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (htons((WORD)tcp->table[i].dwLocalPort) != port) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pid = tcp->table[i].dwProcessId;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
2005-03-20 11:20:28 +08:00
|
|
|
else if (protocol == SIGAR_NETCONN_UDP) {
|
|
|
|
PMIB_UDPEXTABLE udp;
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_GetUdpExTable) {
|
2005-03-20 11:20:28 +08:00
|
|
|
return SIGAR_ENOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(),
|
|
|
|
2, 2);
|
2005-03-20 11:20:28 +08:00
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
return GetLastError();
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
2005-03-20 11:20:28 +08:00
|
|
|
for (i=0; i<udp->dwNumEntries; i++) {
|
|
|
|
if (htons((WORD)udp->table[i].dwLocalPort) != port) {
|
|
|
|
continue;
|
|
|
|
}
|
2004-06-22 06:37:04 +08:00
|
|
|
|
2005-03-20 11:20:28 +08:00
|
|
|
*pid = udp->table[i].dwProcessId;
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return SIGAR_ENOTIMPL;
|
2004-06-22 06:37:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ENOENT;
|
|
|
|
}
|
2005-09-27 07:35:57 +08:00
|
|
|
|
|
|
|
#include <lm.h>
|
|
|
|
|
|
|
|
static int sigar_who_net_sessions(sigar_t *sigar,
|
|
|
|
sigar_who_list_t *wholist)
|
|
|
|
{
|
|
|
|
NET_API_STATUS status;
|
|
|
|
LPSESSION_INFO_10 buffer=NULL, ptr;
|
|
|
|
DWORD entries=0, total_entries=0;
|
|
|
|
DWORD resume_handle=0;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
do {
|
|
|
|
status = NetSessionEnum(NULL, /* server name */
|
|
|
|
NULL, /* client name */
|
|
|
|
NULL, /* user name */
|
|
|
|
10, /* level */
|
|
|
|
(LPBYTE*)&buffer,
|
|
|
|
MAX_PREFERRED_LENGTH,
|
|
|
|
&entries,
|
|
|
|
&total_entries,
|
|
|
|
&resume_handle);
|
|
|
|
|
|
|
|
if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) {
|
|
|
|
if ((ptr = buffer)) {
|
|
|
|
for (i=0; i<entries; i++) {
|
|
|
|
sigar_who_t *who;
|
|
|
|
|
|
|
|
if (!ptr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_WHO_LIST_GROW(wholist);
|
|
|
|
who = &wholist->data[wholist->number++];
|
|
|
|
|
|
|
|
who->time = (time(NULL) - ptr->sesi10_time);
|
|
|
|
SIGAR_W2A((LPCWSTR)ptr->sesi10_username,
|
|
|
|
who->user, sizeof(who->user));
|
|
|
|
SIGAR_W2A((LPCWSTR)ptr->sesi10_cname,
|
|
|
|
who->host, sizeof(who->host));
|
|
|
|
SIGAR_SSTRCPY(who->device, "network share");
|
|
|
|
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer) {
|
|
|
|
NetApiBufferFree(buffer);
|
|
|
|
buffer = NULL;
|
|
|
|
}
|
|
|
|
} while (status == ERROR_MORE_DATA);
|
|
|
|
|
|
|
|
if (buffer) {
|
|
|
|
NetApiBufferFree(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_logon_info(HKEY users,
|
|
|
|
char *username,
|
|
|
|
sigar_who_t *who)
|
|
|
|
{
|
|
|
|
DWORD status, size, type;
|
|
|
|
HKEY key;
|
|
|
|
char key_name[MAX_PATH];
|
|
|
|
char value[256];
|
|
|
|
FILETIME wtime;
|
|
|
|
|
|
|
|
who->time = 0;
|
|
|
|
|
|
|
|
sprintf(key_name, "%s\\Volatile Environment", username);
|
|
|
|
if (RegOpenKey(users, key_name, &key) != ERROR_SUCCESS) {
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = RegQueryInfoKey(key,
|
|
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
|
|
&wtime);
|
|
|
|
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
FileTimeToLocalFileTime(&wtime, &wtime);
|
|
|
|
who->time = FileTimeToTime(&wtime) / 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = sizeof(value);
|
|
|
|
status = RegQueryValueEx(key, "CLIENTNAME",
|
|
|
|
NULL, &type, value, &size);
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
if ((value[0] != '\0') && !strEQ(value, "Console")) {
|
|
|
|
SIGAR_SSTRCPY(who->host, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size = sizeof(value);
|
|
|
|
status = RegQueryValueEx(key, "SESSIONNAME",
|
|
|
|
NULL, &type, value, &size);
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
SIGAR_SSTRCPY(who->device, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(key);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_ConvertStringSidToSid \
|
|
|
|
sigar->advapi.convert_string_sid.func
|
|
|
|
|
2005-09-27 07:35:57 +08:00
|
|
|
static int sigar_who_registry(sigar_t *sigar,
|
|
|
|
sigar_who_list_t *wholist)
|
|
|
|
{
|
|
|
|
HKEY users;
|
2005-10-02 13:52:33 +08:00
|
|
|
DWORD index=0, status;
|
2005-09-27 07:35:57 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_ConvertStringSidToSid) {
|
2005-10-03 05:13:26 +08:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2005-09-27 07:35:57 +08:00
|
|
|
status = RegOpenKey(HKEY_USERS, NULL, &users);
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
char subkey[MAX_PATH];
|
|
|
|
char username[SIGAR_CRED_NAME_MAX];
|
|
|
|
char domain[SIGAR_CRED_NAME_MAX];
|
|
|
|
DWORD subkey_len = sizeof(subkey);
|
|
|
|
DWORD username_len = sizeof(username);
|
|
|
|
DWORD domain_len = sizeof(domain);
|
|
|
|
PSID sid;
|
|
|
|
SID_NAME_USE type;
|
|
|
|
|
|
|
|
status = RegEnumKeyEx(users, index, subkey, &subkey_len,
|
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
if (status != ERROR_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-10-02 13:52:33 +08:00
|
|
|
index++;
|
|
|
|
|
|
|
|
if ((subkey[0] == '.') || strstr(subkey, "_Classes")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (!sigar_ConvertStringSidToSid(subkey, &sid)) {
|
2005-09-27 07:35:57 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LookupAccountSid(NULL, /* server */
|
|
|
|
sid,
|
|
|
|
username, &username_len,
|
|
|
|
domain, &domain_len,
|
|
|
|
&type))
|
|
|
|
{
|
|
|
|
sigar_who_t *who;
|
2005-10-02 13:52:33 +08:00
|
|
|
|
2005-09-27 07:35:57 +08:00
|
|
|
SIGAR_WHO_LIST_GROW(wholist);
|
|
|
|
who = &wholist->data[wholist->number++];
|
|
|
|
|
|
|
|
SIGAR_SSTRCPY(who->user, username);
|
|
|
|
SIGAR_SSTRCPY(who->host, domain);
|
|
|
|
SIGAR_SSTRCPY(who->device, "console");
|
2005-10-02 13:52:33 +08:00
|
|
|
|
2005-09-27 07:35:57 +08:00
|
|
|
get_logon_info(users, subkey, who);
|
|
|
|
}
|
|
|
|
|
|
|
|
LocalFree(sid);
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(users);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2005-09-27 09:18:54 +08:00
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
#define sigar_WTSEnumerateSessions \
|
|
|
|
sigar->wtsapi.enum_sessions.func
|
|
|
|
|
|
|
|
#define sigar_WTSFreeMemory \
|
|
|
|
sigar->wtsapi.free_mem.func
|
|
|
|
|
|
|
|
#define sigar_WTSQuerySessionInformation \
|
|
|
|
sigar->wtsapi.query_session.func
|
|
|
|
|
|
|
|
#define sigar_WinStationQueryInformation \
|
|
|
|
sigar->winsta.query_info.func
|
|
|
|
|
2005-09-27 09:18:54 +08:00
|
|
|
static int sigar_who_wts(sigar_t *sigar,
|
|
|
|
sigar_who_list_t *wholist)
|
|
|
|
{
|
2005-10-02 13:52:33 +08:00
|
|
|
DWORD count=0, i;
|
2005-09-27 09:18:54 +08:00
|
|
|
WTS_SESSION_INFO *sessions = NULL;
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
if (DLLMOD_INIT(wtsapi, TRUE) != SIGAR_OK) {
|
2005-10-02 14:03:36 +08:00
|
|
|
sigar_log(sigar, SIGAR_LOG_DEBUG,
|
|
|
|
"Terminal Services api functions not available");
|
2005-09-27 09:18:54 +08:00
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
DLLMOD_INIT(winsta, FALSE);
|
|
|
|
|
|
|
|
if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) {
|
2005-09-27 09:18:54 +08:00
|
|
|
return GetLastError();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<count; i++) {
|
|
|
|
DWORD bytes;
|
|
|
|
LPTSTR buffer;
|
|
|
|
DWORD sessionId = sessions[i].SessionId;
|
|
|
|
WINSTATION_INFO station_info;
|
|
|
|
sigar_who_t *who;
|
|
|
|
|
|
|
|
if (sessions[i].State != WTSActive) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
bytes = 0;
|
2005-12-21 07:09:34 +08:00
|
|
|
if (sigar_WTSQuerySessionInformation(0,
|
|
|
|
sessionId,
|
|
|
|
WTSClientProtocolType,
|
|
|
|
&buffer,
|
|
|
|
&bytes))
|
2005-09-27 09:18:54 +08:00
|
|
|
{
|
2005-10-11 01:00:30 +08:00
|
|
|
int isConsole =
|
|
|
|
(*buffer == WTS_PROTOCOL_TYPE_CONSOLE);
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_WTSFreeMemory(buffer);
|
2005-09-27 09:18:54 +08:00
|
|
|
|
2005-10-11 01:00:30 +08:00
|
|
|
if (isConsole) {
|
2005-09-27 09:18:54 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SIGAR_WHO_LIST_GROW(wholist);
|
|
|
|
who = &wholist->data[wholist->number++];
|
|
|
|
|
|
|
|
SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName);
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
bytes = 0;
|
2005-12-21 07:09:34 +08:00
|
|
|
if (sigar_WTSQuerySessionInformation(0,
|
|
|
|
sessionId,
|
|
|
|
WTSClientAddress,
|
|
|
|
&buffer,
|
|
|
|
&bytes))
|
2005-09-27 09:18:54 +08:00
|
|
|
{
|
|
|
|
PWTS_CLIENT_ADDRESS client =
|
|
|
|
(PWTS_CLIENT_ADDRESS)buffer;
|
|
|
|
|
|
|
|
sprintf(who->host, "%u.%u.%u.%u",
|
|
|
|
client->Address[2],
|
|
|
|
client->Address[3],
|
|
|
|
client->Address[4],
|
|
|
|
client->Address[5]);
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_WTSFreeMemory(buffer);
|
2005-09-27 09:18:54 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_SSTRCPY(who->host, "unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
bytes = 0;
|
2005-12-21 07:09:34 +08:00
|
|
|
if (sigar_WTSQuerySessionInformation(0,
|
|
|
|
sessionId,
|
|
|
|
WTSUserName,
|
|
|
|
&buffer,
|
|
|
|
&bytes))
|
2005-09-27 09:18:54 +08:00
|
|
|
{
|
|
|
|
SIGAR_SSTRCPY(who->user, buffer);
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_WTSFreeMemory(buffer);
|
2005-09-27 09:18:54 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
SIGAR_SSTRCPY(who->user, "unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = NULL;
|
|
|
|
bytes = 0;
|
2005-12-21 07:09:34 +08:00
|
|
|
if (sigar_WinStationQueryInformation &&
|
|
|
|
sigar_WinStationQueryInformation(0,
|
|
|
|
sessionId,
|
|
|
|
WinStationInformation,
|
|
|
|
&station_info,
|
|
|
|
sizeof(station_info),
|
|
|
|
&bytes))
|
2005-09-27 09:18:54 +08:00
|
|
|
{
|
|
|
|
who->time =
|
|
|
|
FileTimeToTime(&station_info.ConnectTime) / 1000000;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
who->time = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-21 07:09:34 +08:00
|
|
|
sigar_WTSFreeMemory(sessions);
|
2005-09-27 09:18:54 +08:00
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|
2005-10-02 13:52:33 +08:00
|
|
|
|
|
|
|
int sigar_who_list_get_win32(sigar_t *sigar,
|
|
|
|
sigar_who_list_t *wholist)
|
|
|
|
{
|
|
|
|
sigar_who_net_sessions(sigar, wholist);
|
|
|
|
|
|
|
|
sigar_who_registry(sigar, wholist);
|
|
|
|
|
|
|
|
sigar_who_wts(sigar, wholist);
|
|
|
|
|
|
|
|
return SIGAR_OK;
|
|
|
|
}
|