sigar/src/os/win32/win32_sigar.c

3722 lines
96 KiB
C
Raw Normal View History

2006-07-16 01:46:36 +08:00
/*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of SIGAR.
*
* SIGAR is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
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_SYS_KEY "2"
#define PERF_TITLE_MEM_KEY "4"
2004-06-22 06:37:04 +08:00
#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
2008-05-25 09:45:02 +08:00
#define PERF_TITLE_CPU_IRQ 698
2004-06-22 06:37:04 +08:00
typedef enum {
PERF_IX_CPU_USER,
PERF_IX_CPU_IDLE,
PERF_IX_CPU_SYS,
2008-05-25 09:45:02 +08:00
PERF_IX_CPU_IRQ,
2004-06-22 06:37:04 +08:00
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_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_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 {
2007-10-11 00:47:39 +08:00
PERF_IX_DISK_TIME,
PERF_IX_DISK_READ_TIME,
PERF_IX_DISK_WRITE_TIME,
2004-12-05 09:18:57 +08:00
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;
2007-10-11 00:47:39 +08:00
#define PERF_TITLE_DISK_TIME 200 /* % Disk Time */
#define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */
#define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */
2007-10-11 00:53:11 +08:00
#define PERF_TITLE_DISK_READ 214 /* Disk Reads/sec */
#define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */
#define PERF_TITLE_DISK_READ_BYTES 220 /* Disk Read Bytes/sec */
#define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */
2007-10-11 00:49:24 +08:00
#define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */
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, \
&bytes) : \
2004-06-22 06:37:04 +08:00
RegQueryValueExA(sigar->handle, \
counter_key, NULL, &type, \
sigar->perfbuf, \
&bytes))
2004-06-22 06:37:04 +08:00
#define PERF_VAL(ix) \
perf_offsets[ix] ? \
*((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0
/* 1/100ns units to milliseconds */
#define NS100_2MSEC(t) ((t) / 10000)
2005-05-12 07:37:22 +08:00
#define PERF_VAL_CPU(ix) \
NS100_2MSEC(PERF_VAL(ix))
2005-05-12 07:37:22 +08:00
#define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter"
#define NETIF_LA "la"
sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft)
{
sigar_uint64_t time;
time = ft->dwHighDateTime;
time = time << 32;
time |= ft->dwLowDateTime;
time /= 10;
time -= EPOCH_DELTA;
return time;
}
static DWORD perfbuf_init(sigar_t *sigar)
{
if (!sigar->perfbuf) {
sigar->perfbuf = malloc(PERFBUF_SIZE);
sigar->perfbuf_size = PERFBUF_SIZE;
}
return sigar->perfbuf_size;
}
static DWORD perfbuf_grow(sigar_t *sigar)
{
sigar->perfbuf_size += PERFBUF_SIZE;
sigar->perfbuf =
realloc(sigar->perfbuf, sigar->perfbuf_size);
return sigar->perfbuf_size;
}
static char *get_counter_name(char *key)
{
if (strEQ(key, PERF_TITLE_MEM_KEY)) {
return "Memory";
}
else if (strEQ(key, PERF_TITLE_PROC_KEY)) {
return "Process";
}
else if (strEQ(key, PERF_TITLE_CPU_KEY)) {
return "Processor";
}
else if (strEQ(key, PERF_TITLE_DISK_KEY)) {
return "LogicalDisk";
}
else {
return key;
}
}
2007-08-03 22:54:22 +08:00
static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar,
char *counter_key,
DWORD inst, DWORD *err)
2004-06-22 06:37:04 +08:00
{
DWORD retval, type, bytes;
2004-06-22 06:37:04 +08:00
WCHAR wcounter_key[MAX_PATH+1];
PERF_DATA_BLOCK *block;
PERF_OBJECT_TYPE *object;
2004-06-22 06:37:04 +08:00
*err = SIGAR_OK;
2004-06-22 06:37:04 +08:00
if (USING_WIDE()) {
SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key));
}
bytes = perfbuf_init(sigar);
2004-06-22 06:37:04 +08:00
while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) {
if (retval == ERROR_MORE_DATA) {
bytes = perfbuf_grow(sigar);
2004-06-22 06:37:04 +08:00
}
else {
*err = retval;
2004-06-22 06:37:04 +08:00
return NULL;
}
}
block = (PERF_DATA_BLOCK *)sigar->perfbuf;
if (block->NumObjectTypes == 0) {
counter_key = get_counter_name(counter_key);
sigar_strerror_printf(sigar, "No %s counters defined (disabled?)",
counter_key);
*err = -1;
return NULL;
}
object = PdhFirstObject(block);
2004-06-22 06:37:04 +08:00
/*
* only seen on windows 2003 server when pdh.dll
* functions are in use by the same process.
* confucius say what the fuck.
*/
2007-08-03 22:54:22 +08:00
if (inst && (object->NumInstances == PERF_NO_INSTANCES)) {
2005-01-29 00:33:12 +08:00
int i;
2005-01-29 00:33:12 +08:00
for (i=0; i<block->NumObjectTypes; i++) {
if (object->NumInstances != PERF_NO_INSTANCES) {
return object;
}
object = PdhNextObject(object);
}
return NULL;
}
else {
return object;
}
2004-06-22 06:37:04 +08:00
}
2007-08-03 22:54:22 +08:00
#define get_perf_object(sigar, counter_key, err) \
get_perf_object_inst(sigar, counter_key, 1, err)
static int get_swap_counters(sigar_t *sigar, sigar_swap_t *swap)
{
int status;
PERF_OBJECT_TYPE *object =
get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status);
2007-08-03 22:54:22 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
BYTE *data;
DWORD i;
if (!object) {
return status;
}
data = (BYTE *)((BYTE *)object + object->DefinitionLength);
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
DWORD offset = counter->CounterOffset;
switch (counter->CounterNameTitleIndex) {
case 48: /* "Pages Output/sec" */
swap->page_out = *((DWORD *)(data + offset));
break;
case 822: /* "Pages Input/sec" */
swap->page_in = *((DWORD *)(data + offset));
break;
default:
continue;
}
}
return SIGAR_OK;
}
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 },
2006-11-05 09:36:40 +08:00
{ "GetIpAddrTable", NULL },
2005-12-21 07:09:34 +08:00
{ "GetIfTable", NULL },
{ "GetIfEntry", NULL },
{ "GetNumberOfInterfaces", NULL },
2005-12-21 07:09:34 +08:00
{ "GetTcpTable", NULL },
{ "GetUdpTable", NULL },
{ "AllocateAndGetTcpExTableFromStack", NULL },
{ "AllocateAndGetUdpExTableFromStack", NULL },
2007-07-15 01:38:14 +08:00
{ "GetTcpStatistics", NULL },
2005-12-21 07:09:34 +08:00
{ "GetNetworkParams", NULL },
{ "GetAdaptersInfo", NULL },
2006-11-06 06:41:11 +08:00
{ "GetAdaptersAddresses", NULL },
2005-12-21 07:09:34 +08:00
{ 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 },
{ "NtQueryInformationProcess", NULL },
2005-12-21 07:09:34 +08:00
{ NULL, NULL }
};
static sigar_psapi_t sigar_psapi = {
"psapi.dll",
NULL,
{ "EnumProcessModules", NULL },
{ "EnumProcesses", NULL },
2005-12-21 07:09:34 +08:00
{ "GetModuleFileNameExA", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_winsta = {
"winsta.dll",
NULL,
{ "WinStationQueryInformationW", NULL },
{ NULL, NULL }
};
static sigar_psapi_t sigar_kernel = {
"kernel32.dll",
NULL,
{ "GlobalMemoryStatusEx", NULL },
{ NULL, NULL }
};
2005-12-21 07:09:34 +08:00
#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;
}
int sigar_wsa_init(sigar_t *sigar)
{
if (sigar->ws_version == 0) {
WSADATA data;
if (WSAStartup(MAKEWORD(2, 0), &data)) {
sigar->ws_error = WSAGetLastError();
WSACleanup();
return sigar->ws_error;
}
sigar->ws_version = data.wVersion;
}
return SIGAR_OK;
}
2007-08-22 04:51:46 +08:00
static int sigar_enable_privilege(char *name)
{
int status;
HANDLE handle;
TOKEN_PRIVILEGES tok;
SIGAR_ZERO(&tok);
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
&handle))
{
return GetLastError();
}
if (LookupPrivilegeValue(NULL, name,
&tok.Privileges[0].Luid))
{
tok.PrivilegeCount = 1;
tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) {
status = SIGAR_OK;
}
else {
status = GetLastError();
}
}
else {
status = GetLastError();
}
CloseHandle(handle);
return status;
}
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;
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
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);
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);
DLLMOD_COPY(kernel);
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);
sigar->netif_mib_rows = NULL;
sigar->netif_addr_rows = NULL;
sigar->netif_adapters = NULL;
2005-12-21 12:58:02 +08:00
sigar->pinfo.pid = -1;
sigar->ws_version = 0;
2008-04-11 04:40:29 +08:00
sigar->lcpu = -1;
2004-06-22 06:37:04 +08:00
2007-08-22 04:51:46 +08:00
/* increase process visibility */
sigar_enable_privilege(SE_DEBUG_NAME);
2004-06-22 06:37:04 +08:00
return result;
}
void dllmod_init_ntdll(sigar_t *sigar)
{
DLLMOD_INIT(ntdll, FALSE);
}
2004-06-22 06:37:04 +08:00
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);
DLLMOD_FREE(kernel);
2005-12-21 07:09:34 +08:00
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->netif_mib_rows) {
sigar_cache_destroy(sigar->netif_mib_rows);
}
if (sigar->netif_addr_rows) {
sigar_cache_destroy(sigar->netif_addr_rows);
}
if (sigar->netif_adapters) {
sigar_cache_destroy(sigar->netif_adapters);
}
2004-06-22 06:37:04 +08:00
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
{
switch (err) {
case SIGAR_NO_SUCH_PROCESS:
return "No such process";
break;
}
2004-06-22 06:37:04 +08:00
return NULL;
}
#define sigar_GlobalMemoryStatusEx \
sigar->kernel.memory_status.func
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem)
{
DLLMOD_INIT(kernel, TRUE);
2004-06-22 06:37:04 +08:00
if (sigar_GlobalMemoryStatusEx) {
MEMORYSTATUSEX memstat;
memstat.dwLength = sizeof(memstat);
if (!sigar_GlobalMemoryStatusEx(&memstat)) {
return GetLastError();
}
mem->total = memstat.ullTotalPhys;
mem->free = memstat.ullAvailPhys;
}
else {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
mem->total = memstat.dwTotalPhys;
mem->free = memstat.dwAvailPhys;
}
2004-06-22 06:37:04 +08:00
mem->used = mem->total - mem->free;
2004-06-22 06:37:04 +08:00
mem->actual_free = mem->free;
mem->actual_used = mem->used;
2004-06-22 06:37:04 +08:00
sigar_mem_calc_ram(sigar, mem);
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap)
{
2007-08-03 22:54:22 +08:00
int status;
DLLMOD_INIT(kernel, TRUE);
if (sigar_GlobalMemoryStatusEx) {
MEMORYSTATUSEX memstat;
2004-06-22 06:37:04 +08:00
memstat.dwLength = sizeof(memstat);
if (!sigar_GlobalMemoryStatusEx(&memstat)) {
return GetLastError();
}
swap->total = memstat.ullTotalPageFile;
swap->free = memstat.ullAvailPageFile;
}
else {
MEMORYSTATUS memstat;
GlobalMemoryStatus(&memstat);
swap->total = memstat.dwTotalPageFile;
swap->free = memstat.dwAvailPageFile;
}
2004-06-22 06:37:04 +08:00
swap->used = swap->total - swap->free;
2004-06-22 06:37:04 +08:00
2007-08-03 22:54:22 +08:00
if (get_swap_counters(sigar, swap) != SIGAR_OK) {
swap->page_in = SIGAR_FIELD_NOTIMPL;
swap->page_out = SIGAR_FIELD_NOTIMPL;
}
2007-07-21 02:02:21 +08:00
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
DWORD *perf_offsets,
DWORD *num, DWORD *err)
2004-06-22 06:37:04 +08:00
{
PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, 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;
2008-05-25 09:45:02 +08:00
case PERF_TITLE_CPU_IRQ:
perf_offsets[PERF_IX_CPU_IRQ] = offset;
break;
2004-06-22 06:37:04 +08:00
}
}
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
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);
}
else {
/* windows NT and 2000 do not have an Idle counter */
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(ntdll, FALSE);
if (sigar_NtQuerySystemInformation) {
DWORD retval, num;
/* 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);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
if (idx == -1) {
int i;
for (i=0; i<num; i++) {
cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
}
}
else if (idx < num) {
cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart);
}
else {
return ERROR_INVALID_DATA;
}
}
else {
return ERROR_INVALID_FUNCTION;
}
}
return SIGAR_OK;
}
static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu)
2004-06-22 06:37:04 +08:00
{
int status;
2004-06-22 06:37:04 +08:00
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_BLOCK *counter_block;
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));
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);
status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
2008-05-25 09:45:02 +08:00
cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ);
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?*/
2008-05-25 09:45:02 +08:00
cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq;
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;
}
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);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
SIGAR_ZERO(cpu);
for (i=0; i<num; i++) {
cpu->idle += NS100_2MSEC(info[i].IdleTime.QuadPart);
cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart);
cpu->sys += NS100_2MSEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
2008-05-25 09:45:02 +08:00
cpu->irq += NS100_2MSEC(info[i].InterruptTime.QuadPart);
2005-05-12 07:17:39 +08:00
cpu->total += cpu->idle + cpu->user + cpu->sys;
}
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) {
return sigar_cpu_ntsys_get(sigar, cpu);
}
else {
return sigar_cpu_perflib_get(sigar, cpu);
}
}
static int sigar_cpu_list_perflib_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
2004-06-22 06:37:04 +08:00
{
2008-04-11 04:40:29 +08:00
int status, i, j;
2004-06-22 06:37:04 +08:00
PERF_INSTANCE_DEFINITION *inst;
DWORD perf_offsets[PERF_IX_CPU_MAX], num, err;
2008-04-11 04:40:29 +08:00
int core_rollup = sigar_cpu_core_rollup(sigar);
2004-06-22 06:37:04 +08:00
memset(&perf_offsets, 0, sizeof(perf_offsets));
/* first instance is total, rest are per-cpu */
inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err);
2004-06-22 06:37:04 +08:00
if (!inst) {
return err;
2004-06-22 06:37:04 +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_list_create(cpulist);
2008-04-11 04:40:29 +08:00
/* verify there's a counter for each logical cpu */
2008-04-11 04:51:23 +08:00
if (core_rollup && (sigar->ncpu != num)) {
2008-04-11 04:40:29 +08:00
core_rollup = 0;
2004-06-22 06:37:04 +08:00
}
for (i=0; i<num; i++) {
PERF_COUNTER_BLOCK *counter_block;
sigar_cpu_t *cpu;
2008-04-11 04:40:29 +08:00
if (core_rollup && (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);
2008-05-25 09:45:02 +08:00
cpu->irq += PERF_VAL_CPU(PERF_IX_CPU_IRQ);
get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
cpu->nice = cpu->wait = 0; /*N/A*/
/*XXX adding up too much here if xeon, but not using this atm*/
2008-05-25 09:45:02 +08:00
cpu->total += cpu->sys + cpu->user + cpu->idle + cpu->irq;
inst = PdhNextInstance(inst);
2004-06-22 06:37:04 +08:00
}
return SIGAR_OK;
}
static int sigar_cpu_list_ntsys_get(sigar_t *sigar,
sigar_cpu_list_t *cpulist)
{
DWORD retval, num;
2008-04-11 04:40:29 +08:00
int status, i, j;
int core_rollup = sigar_cpu_core_rollup(sigar);
/* 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);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
sigar_cpu_list_create(cpulist);
2008-04-11 04:40:29 +08:00
/* verify there's a counter for each logical cpu */
2008-04-11 04:51:23 +08:00
if (core_rollup && (sigar->ncpu != num)) {
2008-04-11 04:40:29 +08:00
core_rollup = 0;
}
for (i=0; i<num; i++) {
sigar_cpu_t *cpu;
sigar_uint64_t idle, user, sys;
2008-04-11 04:40:29 +08:00
if (core_rollup && (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);
}
idle = NS100_2MSEC(info[i].IdleTime.QuadPart);
user = NS100_2MSEC(info[i].UserTime.QuadPart);
sys = NS100_2MSEC(info[i].KernelTime.QuadPart -
info[i].IdleTime.QuadPart);
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) {
return sigar_cpu_list_ntsys_get(sigar, cpulist);
}
else {
return sigar_cpu_list_perflib_get(sigar, cpulist);
}
}
#define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar,
sigar_uptime_t *uptime)
{
int status;
PERF_OBJECT_TYPE *object =
get_perf_object_inst(sigar, PERF_TITLE_SYS_KEY, 0, &status);
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
BYTE *data;
DWORD i;
if (!object) {
return status;
}
data = (BYTE *)((BYTE *)object + object->DefinitionLength);
for (i=0, counter = PdhFirstCounter(object);
i<object->NumCounters;
i++, counter = PdhNextCounter(counter))
{
if (counter->CounterNameTitleIndex == PERF_TITLE_UPTIME_KEY) {
DWORD offset = counter->CounterOffset;
LONGLONG time = object->PerfTime.QuadPart;
LONGLONG freq = object->PerfFreq.QuadPart;
LONGLONG counter = *((LONGLONG *)(data + offset));
uptime->uptime = (time - counter) / freq;
return SIGAR_OK;
}
}
/* http://msdn.microsoft.com/en-us/library/ms724408.aspx */
return GetTickCount() / 1000;
2004-06-22 06:37:04 +08:00
}
/*
* 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;
}
#define get_process_object(sigar, err) \
get_perf_object(sigar, PERF_TITLE_PROC_KEY, err)
2004-06-22 06:37:04 +08:00
static int sigar_proc_list_get_perf(sigar_t *sigar,
sigar_proc_list_t *proclist)
2004-06-22 06:37:04 +08:00
{
2004-06-22 06:37:04 +08:00
PERF_OBJECT_TYPE *object;
PERF_INSTANCE_DEFINITION *inst;
PERF_COUNTER_DEFINITION *counter;
DWORD i, err;
2004-06-22 06:37:04 +08:00
DWORD perf_offsets[PERF_IX_MAX];
perf_offsets[PERF_IX_PID] = 0;
object = get_process_object(sigar, &err);
2004-06-22 06:37:04 +08:00
if (!object) {
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;
}
}
for (i=0, inst = PdhFirstInstance(object);
i<object->NumInstances;
i++, inst = PdhNextInstance(inst))
{
PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst);
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);
proclist->data[proclist->number++] = pid;
2004-06-22 06:37:04 +08:00
}
return SIGAR_OK;
}
#define sigar_EnumProcesses \
sigar->psapi.enum_processes.func
2007-04-22 11:54:04 +08:00
int sigar_os_proc_list_get(sigar_t *sigar,
sigar_proc_list_t *proclist)
{
DLLMOD_INIT(psapi, FALSE);
if (sigar_EnumProcesses) {
DWORD retval, *pids;
DWORD size = 0, i;
do {
/* re-use the perfbuf */
if (size == 0) {
size = perfbuf_init(sigar);
}
else {
size = perfbuf_grow(sigar);
}
if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf,
sigar->perfbuf_size,
&retval))
{
return GetLastError();
}
} while (retval == sigar->perfbuf_size); //unlikely
pids = (DWORD *)sigar->perfbuf;
2007-04-22 11:54:04 +08:00
size = retval / sizeof(DWORD);
2007-04-22 11:54:04 +08:00
for (i=0; i<size; i++) {
DWORD pid = pids[i];
if (pid == 0) {
continue; /* dont include the system Idle process */
}
2007-04-22 11:54:04 +08:00
SIGAR_PROC_LIST_GROW(proclist);
proclist->data[proclist->number++] = pid;
}
return SIGAR_OK;
}
else {
return sigar_proc_list_get_perf(sigar, proclist);
}
}
2004-06-22 06:37:04 +08:00
#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
static HANDLE open_process(sigar_pid_t pid)
{
return OpenProcess(PROCESS_DAC, 0, (DWORD)pid);
}
2006-03-04 10:23:02 +08:00
/*
* Pretty good explanation of counters:
* http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory
*/
2004-06-22 06:37:04 +08:00
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;
}
2006-03-04 10:23:02 +08:00
procmem->size = pinfo->size; /* "Virtual Bytes" */
procmem->resident = pinfo->resident; /* "Working Set" */
procmem->share = SIGAR_FIELD_NOTIMPL;
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 FILETIME2MSEC(ft) \
NS100_2MSEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime))
2004-06-22 06:37:04 +08:00
2008-03-17 03:26:29 +08:00
sigar_int64_t sigar_time_now_millis(void)
{
SYSTEMTIME st;
2008-03-17 03:26:29 +08:00
FILETIME time;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &time);
2008-03-17 03:26:29 +08:00
return sigar_FileTimeToTime(&time) / 1000;
2008-03-17 03:26:29 +08:00
}
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;
int status = ERROR_SUCCESS;
2004-06-22 06:37:04 +08:00
if (!proc) {
return GetLastError();
}
if (!GetProcessTimes(proc,
&start_time, &exit_time,
&system_time, &user_time))
{
status = GetLastError();
2004-06-22 06:37:04 +08:00
}
CloseHandle(proc);
if (status != ERROR_SUCCESS) {
return status;
}
2004-06-22 06:37:04 +08:00
if (start_time.dwHighDateTime) {
proctime->start_time =
sigar_FileTimeToTime(&start_time) / 1000;
2004-06-22 06:37:04 +08:00
}
else {
proctime->start_time = 0;
}
proctime->user = FILETIME2MSEC(user_time);
proctime->sys = FILETIME2MSEC(system_time);
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;
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;
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));
object = get_process_object(sigar, &err);
if (object == NULL) {
return err;
}
2004-06-22 06:37:04 +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_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));
2006-03-04 10:23:02 +08:00
pinfo->size = PERF_VAL(PERF_IX_MEM_VSIZE);
pinfo->resident = PERF_VAL(PERF_IX_MEM_SIZE);
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;
}
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();
}
status = sigar_proc_args_peb_get(sigar, proc, procargs);
2004-07-29 05:47:14 +08:00
CloseHandle(proc);
2009-08-06 05:30:16 +08:00
if (status == ERROR_DATATYPE_MISMATCH) {
/* we are 32-bit, pid process is 64-bit */
status = sigar_proc_args_wmi_get(sigar, pid, procargs);
}
return status;
2004-07-29 05:47:14 +08:00
}
2004-06-22 06:37:04 +08:00
2007-04-22 13:37:39 +08:00
int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_args_t *procargs)
2004-06-22 06:37:04 +08:00
{
if (pid == sigar->pid) {
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_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv)
2004-06-22 06:37:04 +08:00
{
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 */
return status;
2004-06-22 06:37:04 +08:00
}
ptr += klen + 1 + vlen + 1;
}
return SIGAR_OK;
}
static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
UCHAR *env = (UCHAR*)GetEnvironmentStrings();
sigar_proc_env_parse(env, procenv);
2004-06-22 06:37:04 +08:00
FreeEnvironmentStrings(env);
return SIGAR_OK;
}
static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid,
sigar_proc_env_t *procenv)
{
int status;
HANDLE proc = open_process(pid);
WCHAR env[4096];
2004-06-22 06:37:04 +08:00
if (!proc) {
2004-06-22 06:37:04 +08:00
return GetLastError();
}
status = sigar_proc_env_peb_get(sigar, proc, env, sizeof(env));
2004-06-22 06:37:04 +08:00
CloseHandle(proc);
2004-06-22 06:37:04 +08:00
if (status == SIGAR_OK) {
LPBYTE ptr = (LPBYTE)env;
DWORD size = sizeof(env);
2007-08-21 13:43:10 +08:00
UCHAR ent[4096];
while ((size > 0) && (*ptr != L'\0')) {
DWORD len = (wcslen((LPWSTR)ptr) + 1) * sizeof(WCHAR);
SIGAR_W2A((WCHAR *)ptr, ent, sizeof(ent));
if (sigar_proc_env_parse(ent, procenv) != SIGAR_OK) {
break;
}
size -= len;
ptr += len;
}
2004-06-22 06:37:04 +08:00
}
return status;
2004-06-22 06:37:04 +08:00
}
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 {
return sigar_remote_proc_env_get(sigar, pid, procenv);
2004-06-22 06:37:04 +08:00
}
}
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);
2009-08-06 06:09:00 +08:00
if (status == ERROR_DATATYPE_MISMATCH) {
/* we are 32-bit, pid process is 64-bit */
procexe->cwd[0] = '\0'; /* XXX where else can we try? */
status = sigar_proc_exe_wmi_get(sigar, pid, 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
CloseHandle(proc);
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
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
{
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) {
return SIGAR_ENOTIMPL;
2004-06-22 14:12:51 +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)) {
CloseHandle(proc);
2004-06-22 14:12:51 +08:00
return GetLastError();
}
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)))
{
continue;
}
2004-06-22 14:12:51 +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;
}
}
2004-06-22 14:12:51 +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;
}
#ifndef FILE_READ_ONLY_VOLUME
#define FILE_READ_ONLY_VOLUME 0x00080000
#endif
#ifndef FILE_NAMED_STREAMS
#define FILE_NAMED_STREAMS 0x00040000
#endif
#ifndef FILE_SEQUENTIAL_WRITE_ONCE
#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
#endif
#ifndef FILE_SUPPORTS_TRANSACTIONS
#define FILE_SUPPORTS_TRANSACTIONS 0x00200000
#endif
static void get_fs_options(char *opts, int osize, long flags)
{
*opts = '\0';
if (flags & FILE_READ_ONLY_VOLUME) strncat(opts, "ro", osize);
else strncat(opts, "rw", osize);
#if 0 /*XXX*/
if (flags & FILE_CASE_PRESERVED_NAMES) strncat(opts, ",casepn", osize);
if (flags & FILE_CASE_SENSITIVE_SEARCH) strncat(opts, ",casess", osize);
if (flags & FILE_FILE_COMPRESSION) strncat(opts, ",fcomp", osize);
if (flags & FILE_NAMED_STREAMS) strncat(opts, ",streams", osize);
if (flags & FILE_PERSISTENT_ACLS) strncat(opts, ",acls", osize);
if (flags & FILE_SEQUENTIAL_WRITE_ONCE) strncat(opts, ",wronce", osize);
if (flags & FILE_SUPPORTS_ENCRYPTION) strncat(opts, ",efs", osize);
if (flags & FILE_SUPPORTS_OBJECT_IDS) strncat(opts, ",oids", osize);
if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize);
if (flags & FILE_SUPPORTS_SPARSE_FILES) strncat(opts, ",sparse", osize);
if (flags & FILE_SUPPORTS_TRANSACTIONS) strncat(opts, ",trans", osize);
if (flags & FILE_UNICODE_ON_DISK) strncat(opts, ",unicode", osize);
if (flags & FILE_VOLUME_IS_COMPRESSED) strncat(opts, ",vcomp", osize);
if (flags & FILE_VOLUME_QUOTAS) strncat(opts, ",quota", osize);
#endif
}
2004-06-22 06:37:04 +08:00
SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar,
sigar_file_system_list_t *fslist)
{
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) {
sigar_file_system_t *fsp;
2004-06-22 06:37:04 +08:00
DWORD flags, serialnum=0;
char fsname[1024];
UINT drive_type = GetDriveType(ptr);
int type;
switch (drive_type) {
case DRIVE_FIXED:
type = SIGAR_FSTYPE_LOCAL_DISK;
break;
case DRIVE_REMOTE:
type = SIGAR_FSTYPE_NETWORK;
break;
case DRIVE_CDROM:
type = SIGAR_FSTYPE_CDROM;
break;
case DRIVE_RAMDISK:
type = SIGAR_FSTYPE_RAM_DISK;
break;
case DRIVE_REMOVABLE:
/* skip floppy, usb, etc. drives */
ptr += strlen(ptr)+1;
continue;
default:
type = SIGAR_FSTYPE_NONE;
break;
}
2004-06-22 06:37:04 +08:00
fsname[0] = '\0';
GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL,
&flags, fsname, sizeof(fsname));
if (!serialnum && (drive_type == DRIVE_FIXED)) {
2004-06-22 06:37:04 +08:00
ptr += strlen(ptr)+1;
continue; /* ignore unformatted partitions */
}
SIGAR_FILE_SYSTEM_LIST_GROW(fslist);
fsp = &fslist->data[fslist->number++];
fsp->type = type;
2004-06-22 06:37:04 +08:00
SIGAR_SSTRCPY(fsp->dir_name, ptr);
SIGAR_SSTRCPY(fsp->dev_name, ptr);
/* 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 */
}
get_fs_options(fsp->options, sizeof(fsp->options)-1, flags);
2004-06-22 06:37:04 +08:00
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)
{
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;
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) {
2007-10-11 00:47:39 +08:00
case PERF_TITLE_DISK_TIME:
perf_offsets[PERF_IX_DISK_TIME] = offset;
found = 1;
break;
case PERF_TITLE_DISK_READ_TIME:
perf_offsets[PERF_IX_DISK_READ_TIME] = offset;
found = 1;
break;
case PERF_TITLE_DISK_WRITE_TIME:
perf_offsets[PERF_IX_DISK_WRITE_TIME] = offset;
found = 1;
break;
2004-12-05 09:18:57 +08:00
case PERF_TITLE_DISK_READ:
perf_offsets[PERF_IX_DISK_READ] = offset;
found = 1;
2004-12-05 09:18:57 +08:00
break;
case PERF_TITLE_DISK_WRITE:
perf_offsets[PERF_IX_DISK_WRITE] = offset;
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;
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;
found = 1;
2005-04-07 09:23:49 +08:00
break;
case PERF_TITLE_DISK_QUEUE:
perf_offsets[PERF_IX_DISK_QUEUE] = offset;
found = 1;
2005-04-07 09:23:49 +08:00
break;
2004-12-05 09:18:57 +08:00
}
}
if (!found) {
*err = ENOENT;
return NULL;
}
2004-12-05 09:18:57 +08:00
if (num) {
*num = object->NumInstances;
}
return PdhFirstInstance(object);
}
2007-10-14 05:27:26 +08:00
SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar,
const char *dirname,
2007-10-14 06:13:04 +08:00
sigar_disk_usage_t *disk)
2004-12-05 09:18:57 +08:00
{
DWORD i, err;
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;
DWORD perf_offsets[PERF_IX_DISK_MAX];
SIGAR_DISK_STATS_INIT(disk);
2004-12-05 09:18:57 +08:00
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)) {
2007-10-14 06:13:04 +08:00
disk->time = PERF_VAL(PERF_IX_DISK_TIME);
disk->rtime = PERF_VAL(PERF_IX_DISK_READ_TIME);
disk->wtime = PERF_VAL(PERF_IX_DISK_WRITE_TIME);
disk->reads = PERF_VAL(PERF_IX_DISK_READ);
disk->writes = PERF_VAL(PERF_IX_DISK_WRITE);
disk->read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES);
disk->write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES);
disk->queue = PERF_VAL(PERF_IX_DISK_QUEUE);
2004-12-05 09:18:57 +08:00
return SIGAR_OK;
}
}
return ENXIO;
2004-12-05 09:18:57 +08:00
}
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);
/* N/A */
fsusage->files = SIGAR_FIELD_NOTIMPL;
fsusage->free_files = SIGAR_FIELD_NOTIMPL;
2004-06-22 06:37:04 +08:00
2007-10-14 06:13:04 +08:00
status = sigar_disk_usage_get(sigar, dirname, &fsusage->disk);
2004-06-22 06:37:04 +08:00
return SIGAR_OK;
}
2008-04-11 04:40:29 +08:00
static int sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info)
{
HKEY key, cpu;
int i = 0;
char id[MAX_PATH + 1];
DWORD size = 0, rc;
RegOpenKey(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &key);
//just lookup the first id, then assume all cpus are the same.
rc = RegEnumKey(key, 0, id, sizeof(id));
if (rc != ERROR_SUCCESS) {
RegCloseKey(key);
return rc;
}
rc = RegOpenKey(key, id, &cpu);
if (rc != ERROR_SUCCESS) {
RegCloseKey(key);
return rc;
}
size = sizeof(info->vendor);
if (RegQueryValueEx(cpu, "VendorIdentifier", NULL, NULL,
(LPVOID)&info->vendor, &size) ||
strEQ(info->vendor, "GenuineIntel"))
{
SIGAR_SSTRCPY(info->vendor, "Intel");
}
else {
if (strEQ(info->vendor, "AuthenticAMD")) {
SIGAR_SSTRCPY(info->vendor, "AMD");
}
}
size = sizeof(info->model);
if (RegQueryValueEx(cpu, "ProcessorNameString", NULL, NULL,
(LPVOID)&info->model, &size))
{
size = sizeof(info->model);
if (RegQueryValueEx(cpu, "Identifier", NULL, NULL,
(LPVOID)&info->model, &size))
{
SIGAR_SSTRCPY(info->model, "x86");
}
}
else {
sigar_cpu_model_adjust(sigar, info);
}
size = sizeof(info->mhz); // == sizeof(DWORD)
if (RegQueryValueEx(cpu, "~MHz", NULL, NULL,
(LPVOID)&info->mhz, &size))
{
info->mhz = -1;
}
info->cache_size = -1; //XXX
RegCloseKey(key);
RegCloseKey(cpu);
2008-04-12 01:46:36 +08:00
info->total_cores = sigar->ncpu;
info->cores_per_socket = sigar->lcpu;
info->total_sockets = sigar_cpu_socket_count(sigar);
2008-04-11 04:40:29 +08:00
return SIGAR_OK;
}
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;
2008-04-11 04:51:23 +08:00
sigar_cpu_info_t info;
2008-04-11 04:40:29 +08:00
int core_rollup = sigar_cpu_core_rollup(sigar);
2004-06-22 06:37:04 +08:00
sigar_cpu_info_list_create(cpu_infos);
2004-06-22 06:37:04 +08:00
2008-04-11 04:51:23 +08:00
status = sigar_cpu_info_get(sigar, &info);
2004-06-22 06:37:04 +08:00
if (status != SIGAR_OK) {
return status;
}
2008-04-11 04:51:23 +08:00
for (i=0; i<sigar->ncpu; i++) {
2008-04-11 04:40:29 +08:00
SIGAR_CPU_INFO_LIST_GROW(cpu_infos);
2004-06-22 06:37:04 +08:00
2008-04-11 04:51:23 +08:00
if (core_rollup && (i % sigar->lcpu)) {
2008-04-11 04:40:29 +08:00
continue; /* fold logical processors */
2004-06-22 06:37:04 +08:00
}
2008-04-11 04:40:29 +08:00
memcpy(&cpu_infos->data[cpu_infos->number++],
2008-04-11 04:51:23 +08:00
&info, sizeof(info));
2004-06-22 06:37:04 +08:00
}
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
2006-11-06 06:41:11 +08:00
#define sigar_GetAdaptersAddresses \
sigar->iphlpapi.get_adapters_addrs.func
#define sigar_GetNumberOfInterfaces \
sigar->iphlpapi.get_num_if.func
static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar)
{
DWORD num = 0;
DLLMOD_INIT(iphlpapi, FALSE);
if (sigar_GetNumberOfInterfaces) {
DWORD rc = sigar_GetNumberOfInterfaces(&num);
if (rc == NO_ERROR) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetNumberOfInterfaces=%d",
num);
}
else {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetNumberOfInterfaces failed: %s",
sigar_strerror(sigar, rc));
}
}
if (num == 0) {
num = 10; /* reasonable default */
}
return sigar_cache_new(num);
}
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;
}
*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);
*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 rc;
2005-12-21 10:31:06 +08:00
}
else {
return SIGAR_OK;
}
}
static int sigar_get_adapter_info(sigar_t *sigar,
DWORD index,
IP_ADAPTER_INFO **adapter)
{
sigar_cache_entry_t *entry;
*adapter = NULL;
if (sigar->netif_adapters) {
entry = sigar_cache_get(sigar->netif_adapters, index);
if (entry->value) {
*adapter = (IP_ADAPTER_INFO *)entry->value;
}
}
else {
int status;
IP_ADAPTER_INFO *info;
sigar->netif_adapters =
sigar_netif_cache_new(sigar);
status = sigar_get_adapters_info(sigar, &info);
if (status != SIGAR_OK) {
return status;
}
while (info) {
entry = sigar_cache_get(sigar->netif_adapters,
info->Index);
if (!entry->value) {
entry->value = malloc(sizeof(*info));
}
memcpy(entry->value, info, sizeof(*info));
if (info->Index == index) {
*adapter = info;
}
info = info->Next;
}
}
if (*adapter) {
return SIGAR_OK;
}
else {
return ENOENT;
}
}
2006-11-06 06:41:11 +08:00
static int sigar_get_adapters_addresses(sigar_t *sigar,
PIP_ADAPTER_ADDRESSES *addrs)
{
ULONG size = sigar->ifconf_len;
ULONG rc;
ULONG flags =
GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_MULTICAST;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetAdaptersAddresses) {
return SIGAR_ENOTIMPL;
}
*addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
rc = sigar_GetAdaptersAddresses(AF_UNSPEC,
flags,
NULL,
*addrs,
&size);
if (rc == ERROR_BUFFER_OVERFLOW) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetAdaptersAddresses "
"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);
*addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf;
rc = sigar_GetAdaptersAddresses(AF_UNSPEC,
flags,
NULL,
*addrs,
&size);
}
if (rc != ERROR_SUCCESS) {
return rc;
}
else {
return SIGAR_OK;
}
}
2006-11-05 09:36:40 +08:00
#define sigar_GetIpAddrTable \
sigar->iphlpapi.get_ipaddr_table.func
static int sigar_get_ipaddr_table(sigar_t *sigar,
PMIB_IPADDRTABLE *ipaddr)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIpAddrTable) {
return SIGAR_ENOTIMPL;
}
*ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
if (rc == ERROR_INSUFFICIENT_BUFFER) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
"GetIpAddrTable "
"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);
*ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf;
rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE);
}
if (rc != NO_ERROR) {
return rc;
}
else {
return SIGAR_OK;
}
}
#ifndef MIB_IPADDR_PRIMARY
#define MIB_IPADDR_PRIMARY 0x0001
#endif
static int sigar_get_netif_ipaddr(sigar_t *sigar,
DWORD index,
MIB_IPADDRROW **ipaddr)
{
sigar_cache_entry_t *entry;
*ipaddr = NULL;
if (sigar->netif_addr_rows) {
entry = sigar_cache_get(sigar->netif_addr_rows, index);
if (entry->value) {
*ipaddr = (MIB_IPADDRROW *)entry->value;
}
}
else {
int status, i;
MIB_IPADDRTABLE *mib;
sigar->netif_addr_rows =
sigar_netif_cache_new(sigar);
status = sigar_get_ipaddr_table(sigar, &mib);
if (status != SIGAR_OK) {
return status;
}
for (i=0; i<mib->dwNumEntries; i++) {
MIB_IPADDRROW *row = &mib->table[i];
2006-11-06 04:10:52 +08:00
short type;
2008-04-10 04:58:35 +08:00
#ifdef SIGAR_USING_MSC6
2006-11-06 04:10:52 +08:00
type = row->unused2;
#else
type = row->wType;
#endif
if (!(type & MIB_IPADDR_PRIMARY)) {
continue;
}
entry = sigar_cache_get(sigar->netif_addr_rows,
row->dwIndex);
if (!entry->value) {
entry->value = malloc(sizeof(*row));
}
memcpy(entry->value, row, sizeof(*row));
if (row->dwIndex == index) {
*ipaddr = row;
}
}
}
if (*ipaddr) {
return SIGAR_OK;
}
else {
return ENOENT;
}
}
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
if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) {
2005-12-21 10:31:06 +08:00
return SIGAR_OK;
}
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-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-12-21 10:31:06 +08:00
#endif
adapter = adapter->Next;
}
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 */
2006-07-05 03:33:03 +08:00
sigar_net_address_set(route->destination,
ipr->dwForwardDest);
sigar_net_address_set(route->mask,
ipr->dwForwardMask);
sigar_net_address_set(route->gateway,
ipr->dwForwardNextHop);
route->metric = ipr->dwForwardMetric1;
2005-07-13 02:45:28 +08:00
route->flags = SIGAR_RTF_UP;
2006-07-05 03:33:03 +08:00
if ((ipr->dwForwardDest == 0) &&
(ipr->dwForwardMask == 0))
2005-07-13 02:45:28 +08:00
{
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
2006-11-03 22:56:57 +08:00
#define sigar_GetIfEntry \
sigar->iphlpapi.get_if_entry.func
static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable)
{
ULONG size = sigar->ifconf_len;
DWORD rc;
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetIfTable) {
return SIGAR_ENOTIMPL;
}
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
if (rc == ERROR_INSUFFICIENT_BUFFER) {
sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
2005-12-21 10:31:06 +08:00
"GetIfTable "
"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);
*iftable = (PMIB_IFTABLE)sigar->ifconf_buf;
rc = sigar_GetIfTable(*iftable, &size, FALSE);
}
if (rc != NO_ERROR) {
return rc;
}
else {
return SIGAR_OK;
}
}
2006-03-05 06:12:18 +08:00
static int get_mib_ifrow(sigar_t *sigar,
const char *name,
MIB_IFROW **ifrp)
2004-06-22 06:37:04 +08:00
{
2006-11-03 22:56:57 +08:00
int status, key, cached=0;
sigar_cache_entry_t *entry;
2006-11-03 22:56:57 +08:00
if (sigar->netif_mib_rows) {
cached = 1;
}
else {
status = sigar_net_interface_list_get(sigar, NULL);
if (status != SIGAR_OK) {
return status;
}
}
key = netif_hash(name);
entry = sigar_cache_get(sigar->netif_mib_rows, key);
if (!entry->value) {
return ENOENT;
}
*ifrp = (MIB_IFROW *)entry->value;
2006-11-03 22:56:57 +08:00
if (cached) {
/* refresh */
if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) {
return status;
}
}
return SIGAR_OK;
}
static int netif_hash(char *s)
{
int hash = 0;
while (*s) {
hash = 31*hash + *s++;
}
return hash;
}
SIGAR_DECLARE(int)
sigar_net_interface_list_get(sigar_t *sigar,
sigar_net_interface_list_t *iflist)
{
2004-06-22 06:37:04 +08:00
MIB_IFTABLE *ift;
int i, status;
int lo=0, eth=0, la=0;
2004-06-22 06:37:04 +08:00
if (!sigar->netif_mib_rows) {
sigar->netif_mib_rows =
sigar_netif_cache_new(sigar);
2004-06-22 06:37:04 +08:00
}
if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) {
return status;
2004-06-22 06:37:04 +08:00
}
if (iflist) {
iflist->number = 0;
iflist->size = ift->dwNumEntries;
iflist->data =
malloc(sizeof(*(iflist->data)) * iflist->size);
}
2004-06-22 06:37:04 +08:00
for (i=0; i<ift->dwNumEntries; i++) {
char name[16];
int key;
MIB_IFROW *ifr = ift->table + i;
sigar_cache_entry_t *entry;
2004-06-22 06:37:04 +08:00
if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) {
/* special-case */
sprintf(name, NETIF_LA "%d", la++);
}
else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
sprintf(name, "lo%d", lo++);
2004-06-22 06:37:04 +08:00
}
else if (ifr->dwType == MIB_IF_TYPE_ETHERNET) {
sprintf(name, "eth%d", eth++);
2004-06-22 06:37:04 +08:00
}
else {
continue; /*XXX*/
}
2004-06-22 06:37:04 +08:00
if (iflist) {
2007-06-27 09:10:12 +08:00
iflist->data[iflist->number++] = sigar_strdup(name);
}
2004-06-22 06:37:04 +08:00
key = netif_hash(name);
entry = sigar_cache_get(sigar->netif_mib_rows, key);
if (!entry->value) {
entry->value = malloc(sizeof(*ifr));
}
memcpy(entry->value, ifr, sizeof(*ifr));
2004-06-22 06:37:04 +08:00
}
2006-03-05 06:12:18 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_interface_config_get(sigar_t *sigar,
const char *name,
sigar_net_interface_config_t *ifconfig)
2006-03-05 06:12:18 +08:00
{
MIB_IFROW *ifr;
MIB_IPADDRROW *ipaddr;
2006-03-05 06:12:18 +08:00
int status;
if (!name) {
return sigar_net_interface_config_primary_get(sigar, ifconfig);
}
status = get_mib_ifrow(sigar, name, &ifr);
2006-03-05 06:12:18 +08:00
if (status != SIGAR_OK) {
return status;
}
SIGAR_ZERO(ifconfig);
SIGAR_SSTRCPY(ifconfig->name, name);
2006-03-05 06:12:18 +08:00
ifconfig->mtu = ifr->dwMtu;
2006-07-06 05:33:59 +08:00
sigar_net_address_mac_set(ifconfig->hwaddr,
ifr->bPhysAddr,
SIGAR_IFHWADDRLEN);
2006-03-05 06:12:18 +08:00
2006-03-05 06:28:09 +08:00
SIGAR_SSTRCPY(ifconfig->description,
ifr->bDescr);
if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) {
ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING;
}
status = sigar_get_netif_ipaddr(sigar,
ifr->dwIndex,
&ipaddr);
if (status == SIGAR_OK) {
sigar_net_address_set(ifconfig->address,
ipaddr->dwAddr);
sigar_net_address_set(ifconfig->netmask,
ipaddr->dwMask);
2006-11-06 04:18:11 +08:00
if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) {
if (ipaddr->dwBCastAddr) {
2006-11-06 04:21:29 +08:00
long bcast =
ipaddr->dwAddr & ipaddr->dwMask;
2006-11-06 04:18:11 +08:00
bcast |= ~ipaddr->dwMask;
ifconfig->flags |= SIGAR_IFF_BROADCAST;
2006-11-06 04:21:29 +08:00
sigar_net_address_set(ifconfig->broadcast,
bcast);
}
2006-11-06 04:18:11 +08:00
}
}
/* hack for MS_LOOPBACK_ADAPTER */
if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) {
ifr->dwType = MIB_IF_TYPE_LOOPBACK;
}
if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) {
ifconfig->flags |= SIGAR_IFF_LOOPBACK;
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_LOOPBACK);
}
else {
if (ipaddr) {
2006-11-06 04:18:11 +08:00
ifconfig->flags |= SIGAR_IFF_MULTICAST;
}
SIGAR_SSTRCPY(ifconfig->type,
SIGAR_NIC_ETHERNET);
}
2006-03-05 06:12:18 +08:00
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_interface_stat_get(sigar_t *sigar, const char *name,
sigar_net_interface_stat_t *ifstat)
{
MIB_IFROW *ifr;
int status;
status = get_mib_ifrow(sigar, name, &ifr);
if (status != SIGAR_OK) {
return status;
}
2004-06-22 06:37:04 +08:00
ifstat->rx_bytes = ifr->dwInOctets;
ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts;
ifstat->rx_errors = ifr->dwInErrors;
ifstat->rx_dropped = ifr->dwInDiscards;
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;
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
2006-03-07 09:08:23 +08:00
ifstat->speed = ifr->dwSpeed;
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
static int net_conn_get_tcp(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
int status, i;
DWORD rc, size=0;
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();
}
/* go in reverse to get LISTEN states first */
for (i = (tcp->dwNumEntries-1); i >= 0; i--) {
2004-06-22 06:37:04 +08:00
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;
sigar_net_address_set(conn.local_address,
tcp->table[i].dwLocalAddr);
2004-06-22 06:37:04 +08:00
sigar_net_address_set(conn.remote_address,
tcp->table[i].dwRemoteAddr);
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;
}
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
2004-06-22 06:37:04 +08:00
}
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
static int net_conn_get_udp(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
sigar_t *sigar = walker->sigar;
int flags = walker->flags;
2004-06-22 06:37:04 +08:00
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);
2006-06-20 08:02:47 +08:00
if (!sigar_GetUdpTable) {
2005-12-21 07:09:34 +08:00
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);
conn.remote_port = 0;
2004-06-22 06:37:04 +08:00
conn.type = SIGAR_NETCONN_UDP;
sigar_net_address_set(conn.local_address,
udp->table[i].dwLocalAddr);
2004-06-22 06:37:04 +08:00
sigar_net_address_set(conn.remote_address, 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;
if (walker->add_connection(walker, &conn) != SIGAR_OK) {
break;
}
2004-06-22 06:37:04 +08:00
}
free(udp);
return SIGAR_OK;
}
SIGAR_DECLARE(int)
sigar_net_connection_walk(sigar_net_connection_walker_t *walker)
2004-06-22 06:37:04 +08:00
{
int status;
if (walker->flags & SIGAR_NETCONN_TCP) {
status = net_conn_get_tcp(walker);
2004-06-22 06:37:04 +08:00
if (status != SIGAR_OK) {
return status;
}
}
if (walker->flags & SIGAR_NETCONN_UDP) {
status = net_conn_get_udp(walker);
2004-06-22 06:37:04 +08:00
if (status != SIGAR_OK) {
return status;
}
}
return SIGAR_OK;
}
2007-07-15 01:38:14 +08:00
#define sigar_GetTcpStatistics \
sigar->iphlpapi.get_tcp_stats.func
2007-07-15 00:01:58 +08:00
SIGAR_DECLARE(int)
2007-08-08 13:34:21 +08:00
sigar_tcp_get(sigar_t *sigar,
sigar_tcp_t *tcp)
2007-07-15 00:01:58 +08:00
{
2007-07-15 01:38:14 +08:00
MIB_TCPSTATS mib;
int status;
DLLMOD_INIT(iphlpapi, FALSE);
if (!sigar_GetTcpStatistics) {
return SIGAR_ENOTIMPL;
}
status = sigar_GetTcpStatistics(&mib);
if (status != NO_ERROR) {
return status;
}
2007-08-08 13:34:21 +08:00
tcp->active_opens = mib.dwActiveOpens;
tcp->passive_opens = mib.dwPassiveOpens;
tcp->attempt_fails = mib.dwAttemptFails;
tcp->estab_resets = mib.dwEstabResets;
tcp->curr_estab = mib.dwCurrEstab;
tcp->in_segs = mib.dwInSegs;
tcp->out_segs = mib.dwOutSegs;
tcp->retrans_segs = mib.dwRetransSegs;
2007-08-08 14:11:20 +08:00
tcp->in_errs = mib.dwInErrs;
2007-08-08 13:34:21 +08:00
tcp->out_rsts = mib.dwOutRsts;
2007-07-15 01:38:14 +08:00
return SIGAR_OK;
2007-07-15 00:01:58 +08:00
}
2007-07-26 14:30:29 +08:00
SIGAR_DECLARE(int)
sigar_nfs_client_v2_get(sigar_t *sigar,
2007-08-08 13:40:58 +08:00
sigar_nfs_client_v2_t *nfs)
2007-07-26 14:30:29 +08:00
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_server_v2_get(sigar_t *sigar,
2007-08-08 13:40:58 +08:00
sigar_nfs_server_v2_t *nfs)
2007-07-26 14:30:29 +08:00
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_client_v3_get(sigar_t *sigar,
2007-08-08 13:40:58 +08:00
sigar_nfs_client_v3_t *nfs)
2007-07-26 14:30:29 +08:00
{
return SIGAR_ENOTIMPL;
}
SIGAR_DECLARE(int)
sigar_nfs_server_v3_get(sigar_t *sigar,
2007-08-08 13:40:58 +08:00
sigar_nfs_server_v3_t *nfs)
2007-07-26 14:30:29 +08:00
{
return SIGAR_ENOTIMPL;
}
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,
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;
}
#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 = sigar_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
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-12-21 07:09:34 +08:00
if (!sigar_ConvertStringSidToSid) {
return ENOENT;
}
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)) {
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
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
get_logon_info(users, subkey, who);
}
LocalFree(sid);
}
RegCloseKey(users);
return SIGAR_OK;
}
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
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;
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");
return ENOENT;
}
2005-12-21 07:09:34 +08:00
DLLMOD_INIT(winsta, FALSE);
if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) {
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-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-10-11 01:00:30 +08:00
if (isConsole) {
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))
{
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);
}
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))
{
SIGAR_SSTRCPY(who->user, buffer);
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(buffer);
}
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))
{
who->time =
sigar_FileTimeToTime(&station_info.ConnectTime) / 1000000;
}
else {
who->time = 0;
}
}
2005-12-21 07:09:34 +08:00
sigar_WTSFreeMemory(sessions);
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;
}
/* see: http://msdn2.microsoft.com/en-us/library/ms724833.aspx */
#ifndef VER_NT_WORKSTATION
#define VER_NT_WORKSTATION 0x0000001
#endif
2008-04-11 01:38:18 +08:00
#ifdef SIGAR_USING_MSC6
#define sigar_wProductType wReserved[1]
#else
#define sigar_wProductType wProductType
#endif
2008-04-11 05:03:07 +08:00
#ifdef _M_X64
#define SIGAR_ARCH "x64"
#else
#define SIGAR_ARCH "x86"
#endif
int sigar_os_sys_info_get(sigar_t *sigar,
sigar_sys_info_t *sysinfo)
{
OSVERSIONINFOEX version;
2006-09-25 08:09:21 +08:00
char *vendor_name, *vendor_version, *code_name=NULL;
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx((OSVERSIONINFO *)&version);
2006-09-25 08:09:21 +08:00
2006-10-01 02:36:12 +08:00
if (version.dwMajorVersion == 4) {
2006-09-25 08:09:21 +08:00
vendor_name = "Windows NT";
vendor_version = "NT";
}
2006-10-01 02:36:12 +08:00
else if (version.dwMajorVersion == 5) {
2006-09-25 08:09:21 +08:00
switch (version.dwMinorVersion) {
case 0:
vendor_name = "Windows 2000";
vendor_version = "2000";
break;
case 1:
vendor_name = "Windows XP";
vendor_version = "XP";
code_name = "Whistler";
break;
case 2:
vendor_name = "Windows 2003";
vendor_version = "2003";
code_name = "Whistler Server";
break;
default:
vendor_name = "Windows Unknown";
break;
}
}
2006-10-01 02:36:12 +08:00
else if (version.dwMajorVersion == 6) {
if (version.sigar_wProductType == VER_NT_WORKSTATION) {
2006-10-01 02:36:12 +08:00
vendor_name = "Windows Vista";
vendor_version = "Vista";
}
else {
vendor_name = "Windows 2008";
vendor_version = "2008";
code_name = "Longhorn Server";
2006-10-01 02:36:12 +08:00
}
}
2006-09-25 08:09:21 +08:00
SIGAR_SSTRCPY(sysinfo->name, "Win32");
SIGAR_SSTRCPY(sysinfo->vendor, "Microsoft");
SIGAR_SSTRCPY(sysinfo->vendor_name, vendor_name);
SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version);
if (code_name) {
SIGAR_SSTRCPY(sysinfo->vendor_code_name, code_name);
}
2008-04-11 05:03:07 +08:00
SIGAR_SSTRCPY(sysinfo->arch, SIGAR_ARCH);
2006-09-25 08:09:21 +08:00
sprintf(sysinfo->version, "%d.%d",
version.dwMajorVersion,
version.dwMinorVersion);
SIGAR_SSTRCPY(sysinfo->patch_level,
version.szCSDVersion);
2006-09-25 08:23:22 +08:00
sprintf(sysinfo->description, "%s %s",
sysinfo->vendor, sysinfo->vendor_name);
return SIGAR_OK;
}
2007-03-07 14:51:18 +08:00
#define sigar_QueryServiceStatusEx \
sigar->advapi.query_service_status.func
int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid)
{
DWORD rc = ERROR_SUCCESS, len;
SC_HANDLE mgr;
HANDLE svc;
SERVICE_STATUS_PROCESS status;
if (!sigar_QueryServiceStatusEx) {
return SIGAR_ENOTIMPL;
}
mgr = OpenSCManager(NULL,
SERVICES_ACTIVE_DATABASE,
SC_MANAGER_ALL_ACCESS);
if (!mgr) {
return GetLastError();
}
if (!(svc = OpenService(mgr, name, SERVICE_ALL_ACCESS))) {
CloseServiceHandle(mgr);
return GetLastError();
}
if (sigar_QueryServiceStatusEx(svc,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&status,
sizeof(status), &len))
{
*pid = status.dwProcessId;
}
else {
*pid = -1;
rc = GetLastError();
}
CloseServiceHandle(svc);
CloseServiceHandle(mgr);
return rc;
}
2008-03-07 10:26:41 +08:00
2008-03-08 02:01:00 +08:00
int sigar_services_status_get(sigar_services_status_t *ss, DWORD state)
2008-03-07 10:26:41 +08:00
{
DWORD bytes, resume=0;
BOOL retval;
if (!ss->handle) {
ss->handle =
OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!ss->handle) {
return GetLastError();
}
}
retval = EnumServicesStatus(ss->handle,
SERVICE_WIN32, state,
ss->services, ss->size,
&bytes, &ss->count, &resume);
if (retval == FALSE) {
DWORD err = GetLastError();
if (err != ERROR_MORE_DATA) {
return err;
}
ss->services = realloc(ss->services, bytes);
ss->size = bytes;
retval = EnumServicesStatus(ss->handle,
SERVICE_WIN32, state,
ss->services, ss->size,
&bytes, &ss->count, &resume);
if (retval == FALSE) {
return GetLastError();
}
}
return SIGAR_OK;
}
void sigar_services_status_close(sigar_services_status_t *ss)
{
if (ss->handle) {
CloseServiceHandle(ss->handle);
}
if (ss->size) {
free(ss->services);
}
SIGAR_ZERO(ss);
}
/* extract exe from QUERY_SERVICE_CONFIG.lpBinaryPathName
* leaves behind command-line arguments and quotes (if any)
*/
char *sigar_service_exe_get(char *path, char *buffer, int basename)
{
char *ptr;
if (path) {
strncpy(buffer, path, SIGAR_CMDLINE_MAX);
}
path = buffer;
if (*path == '"') {
++path;
if ((ptr = strchr(path, '"'))) {
*ptr = '\0';
}
}
else {
ptr = sigar_strcasestr(path, ".exe");
if (ptr) {
*(ptr+4) = '\0';
}
else {
if ((ptr = strchr(path, ' '))) {
*ptr = '\0';
}
}
}
if (basename && (ptr = strrchr(path, '\\'))) {
path = ++ptr;
}
return path;
}
static char *string_file_info_keys[] = {
"Comments",
"CompanyName",
"FileDescription",
"FileVersion",
"InternalName",
"LegalCopyright",
"LegalTrademarks",
"OriginalFilename",
"ProductName",
"ProductVersion",
"PrivateBuild",
"SpecialBuild",
NULL
};
int sigar_file_version_get(sigar_file_version_t *version,
char *name,
sigar_proc_env_t *infocb)
{
DWORD handle, len;
LPTSTR data;
VS_FIXEDFILEINFO *info;
int status;
if (!(len = GetFileVersionInfoSize(name, &handle))) {
return GetLastError();
}
if (len == 0) {
return !SIGAR_OK;
}
data = malloc(len);
if (GetFileVersionInfo(name, handle, len, data)) {
if (VerQueryValue(data, "\\", &info, 0)) {
version->product_major = HIWORD(info->dwProductVersionMS);
version->product_minor = LOWORD(info->dwProductVersionMS);
version->product_build = HIWORD(info->dwProductVersionLS);
version->product_revision = LOWORD(info->dwProductVersionLS);
version->file_major = HIWORD(info->dwFileVersionMS);
version->file_minor = LOWORD(info->dwFileVersionMS);
version->file_build = HIWORD(info->dwFileVersionLS);
version->file_revision = LOWORD(info->dwFileVersionLS);
status = SIGAR_OK;
}
else {
status = GetLastError();
}
}
else {
status = GetLastError();
}
if (infocb && (status == SIGAR_OK)) {
struct {
WORD lang;
WORD code_page;
} *trans;
if (VerQueryValue(data, "\\VarFileInfo\\Translation",
&trans, &len))
{
int i;
char buf[1024];
void *ptr;
for (i=0; string_file_info_keys[i]; i++) {
char *key = string_file_info_keys[i];
sprintf(buf, "\\StringFileInfo\\%04x%04x\\%s",
trans[0].lang, trans[0].code_page,
key);
if (VerQueryValue(data, buf, &ptr, &len)) {
if (len == 0) {
continue;
}
infocb->env_getter(infocb->data,
key, strlen(key),
(char *)ptr, len);
}
}
}
}
free(data);
return status;
}