From b1dada8933883a0ed24670c30bbd4e71a26b827a Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Fri, 23 Jun 2017 10:15:09 +0530 Subject: [PATCH 01/15] Add disk_io_counters --- pslib_windows.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 pslib_windows.c diff --git a/pslib_windows.c b/pslib_windows.c new file mode 100644 index 0000000..f780d76 --- /dev/null +++ b/pslib_windows.c @@ -0,0 +1,83 @@ + +#include +#include +#include +#include + +#include "pslib.h" +#include "common.h" + +#pragma comment(lib, "WTSAPI32.lib") +// fix for mingw32, see +// https://github.com/giampaolo/psutil/issues/351#c2 +typedef struct _DISK_PERFORMANCE_WIN_2008 { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + DWORD ReadCount; + DWORD WriteCount; + DWORD QueueDepth; + DWORD SplitCount; + LARGE_INTEGER QueryTime; + DWORD StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE_WIN_2008; + +DiskIOCounterInfo *disk_io_counters(void) { + DISK_PERFORMANCE_WIN_2008 diskPerformance; + DWORD dwSize; + HANDLE hDevice = NULL; + char szDevice[MAX_PATH]; + char *szDeviceDisplay=NULL; + int devNum; + DiskIOCounterInfo *ret = NULL; + ret = (DiskIOCounterInfo *)calloc(1, sizeof(DiskIOCounterInfo)); + check_mem(ret); + ret->iocounters = (DiskIOCounters *)calloc(1, sizeof(DiskIOCounters)); + check_mem(ret->iocounters); + ret->nitems = 0; + for (devNum = 0; devNum <= 32; ++devNum) { + sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum); + hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + + if (hDevice == INVALID_HANDLE_VALUE) + { + continue; + } + if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, + &diskPerformance, sizeof(diskPerformance), + &dwSize, NULL)) + { + ret->nitems++; + ret->iocounters = (DiskIOCounters *)realloc(ret->iocounters , ret->nitems * sizeof(DiskIOCounters)); + check_mem(ret->iocounters); + szDeviceDisplay = (char *)calloc(MAX_PATH, sizeof(char)); + sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); + ret->iocounters[devNum].name = szDeviceDisplay; + ret->iocounters[devNum].reads = diskPerformance.ReadCount; + ret->iocounters[devNum].writes = diskPerformance.WriteCount; + ret->iocounters[devNum].readbytes = diskPerformance.BytesRead.QuadPart; + ret->iocounters[devNum].writebytes = diskPerformance.BytesWritten.QuadPart; + ret->iocounters[devNum].readtime = (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000; + ret->iocounters[devNum].writetime = (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000; + } + CloseHandle(hDevice); + } + return ret; +error: + if (ret) + { + free_disk_iocounter_info(ret); + } + if (hDevice != NULL) + CloseHandle(hDevice); + return NULL; +} +void free_disk_iocounter_info(DiskIOCounterInfo *tmp) +{ + free(tmp->iocounters); + free(tmp); +} From bad8467598e3bc1455a91f0d6cf4a0a327c846fc Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Fri, 23 Jun 2017 10:16:45 +0530 Subject: [PATCH 02/15] Add disk_partitions --- pslib_windows.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/pslib_windows.c b/pslib_windows.c index f780d76..46b75bb 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -25,6 +25,19 @@ typedef struct _DISK_PERFORMANCE_WIN_2008 { WCHAR StorageManagerName[8]; } DISK_PERFORMANCE_WIN_2008; +typedef struct _WINSTATION_INFO { + BYTE Reserved1[72]; + ULONG SessionId; + BYTE Reserved2[4]; + FILETIME ConnectTime; + FILETIME DisconnectTime; + FILETIME LastInputTime; + FILETIME LoginTime; + BYTE Reserved3[1096]; + FILETIME CurrentTime; +} WINSTATION_INFO; + + DiskIOCounterInfo *disk_io_counters(void) { DISK_PERFORMANCE_WIN_2008 diskPerformance; DWORD dwSize; @@ -81,3 +94,133 @@ void free_disk_iocounter_info(DiskIOCounterInfo *tmp) free(tmp->iocounters); free(tmp); } + +static char *get_drive_type(int type) { + switch (type) { + case DRIVE_FIXED: + return "fixed"; + case DRIVE_CDROM: + return "cdrom"; + case DRIVE_REMOVABLE: + return "removable"; + case DRIVE_UNKNOWN: + return "unknown"; + case DRIVE_NO_ROOT_DIR: + return "unmounted"; + case DRIVE_REMOTE: + return "remote"; + case DRIVE_RAMDISK: + return "ramdisk"; + default: + return "?"; + } +} + +DiskPartitionInfo *disk_partitions(bool all) { + DWORD num_bytes; + char *drive_letter = NULL; + int type; + int _ret; + unsigned int old_mode = 0; + char *tmpstring; + LPTSTR fs_type[MAX_PATH + 1] = { 0 }; + DWORD pflags = 0; + char opts[20]; + DiskPartitionInfo *ret = NULL; + ret = (DiskPartitionInfo *)calloc(1,sizeof(DiskPartitionInfo)); + check_mem(ret); + ret->nitems = 0; + drive_letter = (char *)calloc(1, 255 * sizeof(char)); + check_mem(drive_letter); + // avoid to visualize a message box in case something goes wrong + // see https://github.com/giampaolo/psutil/issues/264 + old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); + num_bytes = GetLogicalDriveStrings(254, drive_letter); + check(num_bytes, "Error in getting valid drives"); + while (*drive_letter != '\0') { + opts[0] = 0; + fs_type[0] = 0; + ret->nitems++; + ret->partitions = (DiskPartition *)realloc(ret->partitions, ret->nitems * sizeof(DiskPartition)); + type = GetDriveType(drive_letter); + + // by default we only show hard drives and cd-roms + if (all==0) { + if ((type == DRIVE_UNKNOWN) || + (type == DRIVE_NO_ROOT_DIR) || + (type == DRIVE_REMOTE) || + (type == DRIVE_RAMDISK)) { + goto next; + } + // floppy disk: skip it by default as it introduces a + // considerable slowdown. + if ((type == DRIVE_REMOVABLE) && + (strcmp(drive_letter, "A:\\") == 0)) { + goto next; + } + } + _ret = GetVolumeInformation( + (LPCTSTR)drive_letter, NULL, _ARRAYSIZE(drive_letter), + NULL, NULL, &pflags, (LPTSTR)fs_type, _ARRAYSIZE(fs_type)); + if (_ret == 0) { + // We might get here in case of a floppy hard drive, in + // which case the error is (21, "device not ready"). + // Let's pretend it didn't happen as we already have + // the drive name and type ('removable'). + strcat_s(opts, _countof(opts), ""); + SetLastError(0); + } + else { + if (pflags & FILE_READ_ONLY_VOLUME) + strcat_s(opts, _countof(opts), "ro"); + else + strcat_s(opts, _countof(opts), "rw"); + if (pflags & FILE_VOLUME_IS_COMPRESSED) + strcat_s(opts, _countof(opts), ",compressed"); + } + + if (strlen(opts) > 0) + strcat_s(opts, _countof(opts), ","); + strcat_s(opts, _countof(opts), get_drive_type(type)); + tmpstring = (char *)calloc(1, 20 * sizeof(char)); + check_mem(tmpstring); + strcpy(tmpstring, opts); + ret->partitions[ret->nitems - 1].opts = tmpstring; + tmpstring = (char *)calloc(1, (MAX_PATH + 1) * sizeof(char)); + check_mem(tmpstring); + strcpy(tmpstring, (char *)fs_type); + ret->partitions[ret->nitems - 1].device = drive_letter; + ret->partitions[ret->nitems - 1].mountpoint = drive_letter; + ret->partitions[ret->nitems - 1].fstype = tmpstring; + goto next; + + next: + drive_letter = strchr(drive_letter, 0) + 1; + } + SetErrorMode(old_mode); + return ret; + +error: + SetErrorMode(old_mode); + if (drive_letter) + { + free(drive_letter); + } + if (ret) + { + free_disk_partition_info(ret); + } + return NULL; +} +void free_disk_partition_info(DiskPartitionInfo *p) +{ + uint32_t i; + free(p->partitions[0].device); + for ( i = 0; i < p->nitems; i++) + { + free(p->partitions[i].fstype); + free(p->partitions[i].opts); + } + free(p->partitions); + free(p); +} From acb9ab5945a139d5f645d883499d89054141eb69 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Fri, 23 Jun 2017 10:17:39 +0530 Subject: [PATCH 03/15] Add disk_usage --- pslib_windows.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pslib_windows.c b/pslib_windows.c index 46b75bb..a71b32f 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -224,3 +224,21 @@ void free_disk_partition_info(DiskPartitionInfo *p) free(p->partitions); free(p); } + +bool disk_usage(const char path[], DiskUsage *disk) { + BOOL retval; + ULARGE_INTEGER _, total, free; + retval = GetDiskFreeSpaceExA((LPCSTR)path, &_, &total, &free); + if (retval) + { + disk->total = total.QuadPart; + disk->free = free.QuadPart; + disk->used = disk->total - disk->free; + disk->percent = percentage(disk->used, disk->total); + return TRUE; + } + else + { + return FALSE; + } +} From c4c81a0cd319e115d9c422b22fbe2dd3b32d1891 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Fri, 23 Jun 2017 10:18:11 +0530 Subject: [PATCH 04/15] Add get_users --- pslib_windows.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/pslib_windows.c b/pslib_windows.c index a71b32f..8b927be 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -242,3 +242,143 @@ bool disk_usage(const char path[], DiskUsage *disk) { return FALSE; } } + +UsersInfo *get_users() { + HANDLE hServer = WTS_CURRENT_SERVER_HANDLE; + WCHAR *buffer_user = NULL; + LPTSTR buffer_addr = NULL; + PWTS_SESSION_INFO sessions = NULL; + DWORD count; + DWORD i; + DWORD sessionId; + DWORD bytes; + PWTS_CLIENT_ADDRESS address; + char address_str[50]; + long long unix_time; + char *tmp; + PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; + WINSTATION_INFO station_info; + HINSTANCE hInstWinSta = NULL; + ULONG returnLen; + LPBOOL q = NULL; + + UsersInfo *users_info_ptr = NULL; + /*PyObject *py_retlist = PyList_New(0); + PyObject *py_tuple = NULL; + PyObject *py_address = NULL; + PyObject *py_username = NULL;*/ + hInstWinSta = LoadLibraryA("winsta.dll"); + WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) \ + GetProcAddress(hInstWinSta, "WinStationQueryInformationW"); + users_info_ptr = (UsersInfo *)calloc(1, sizeof(UsersInfo)); + check_mem(users_info_ptr); + check(WTSEnumerateSessions(hServer, 0, 1, &sessions, &count), + "error in retrieving list of sessions on a Remote Desktop Session Host server"); + users_info_ptr->users = (Users *)calloc(count, sizeof(Users)); + check_mem(users_info_ptr->users); + //users_info_ptr->nitems = 0; + users_info_ptr->nitems = 0; + for (i = 0; i < count; i++) { + //py_address = NULL; + //py_tuple = NULL; + sessionId = sessions[i].SessionId; + if (buffer_user != NULL) + WTSFreeMemory(buffer_user); + if (buffer_addr != NULL) + WTSFreeMemory(buffer_addr); + + buffer_user = NULL; + buffer_addr = NULL; + + // username + bytes = 0; + check(WTSQuerySessionInformationW(hServer, sessionId, WTSUserName, + &buffer_user, &bytes), "error in retriving Username"); + if (bytes <= 2) + continue; + // address + bytes = 0; + check( WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress, + &buffer_addr, &bytes),"error in retriving ClientAddress") + + address = (PWTS_CLIENT_ADDRESS)buffer_addr; + if (address->AddressFamily == 0) { // AF_INET + sprintf_s(address_str, + _countof(address_str), + "%u.%u.%u.%u", + address->Address[0], + address->Address[1], + address->Address[2], + address->Address[3]); + tmp = (char *)calloc(50, sizeof(char)); + check_mem(tmp); + strcpy(tmp,address_str); + users_info_ptr->users[users_info_ptr->nitems].hostname = tmp; + } + else { + users_info_ptr->users[users_info_ptr->nitems].hostname = NULL; + } + + // login time + check(WinStationQueryInformationW(hServer, + sessionId, + WinStationInformation, + &station_info, + sizeof(station_info), + &returnLen), "error in retriving login time"); + unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; + unix_time += \ + station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; + unix_time /= 10000000; + tmp = (char *)calloc(USERNAME_LENGTH, sizeof(char)); + check_mem(tmp); + if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, buffer_user, -1, tmp, USERNAME_LENGTH, "", q) == 0) + { + DWORD t; + t = GetLastError(); + check(t != ERROR_INSUFFICIENT_BUFFER, "Supplied buffer size was not large enough, or it was incorrectly set to NULL."); + check(t != ERROR_INVALID_FLAGS, "The values supplied for flags were not valid."); + check(t != ERROR_INVALID_PARAMETER, "Any of the parameter values was invalid"); + check(t != ERROR_NO_UNICODE_TRANSLATION, "Invalid Unicode was found in a string."); + } + users_info_ptr->users[users_info_ptr->nitems].username = tmp; + users_info_ptr->users[users_info_ptr->nitems].tstamp = (float)unix_time; + users_info_ptr->users[users_info_ptr->nitems].tty = NULL; + users_info_ptr->nitems++; + } + + WTSFreeMemory(sessions); + WTSFreeMemory(buffer_user); + WTSFreeMemory(buffer_addr); + FreeLibrary(hInstWinSta); + return users_info_ptr; +error: + if (hInstWinSta != NULL) + FreeLibrary(hInstWinSta); + if (sessions != NULL) + WTSFreeMemory(sessions); + if (buffer_user != NULL) + WTSFreeMemory(buffer_user); + if (buffer_addr != NULL) + WTSFreeMemory(buffer_addr); + if (users_info_ptr) + free_users_info(users_info_ptr); + if (tmp) + free(tmp); + return NULL; +} +void free_users_info(UsersInfo *u) +{ + uint32_t i; + for ( i = 0; i < u->nitems; i++) + { + if(u->users[i].hostname) + free(u->users[i].hostname); + if (u->users[i].tty) + free(u->users[i].tty); + if (u->users[i].username) + free(u->users[i].username); + } + free(u->users); + free(u); +} From 2b6386e419298bc4e29e54c925181a69d2befd02 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Fri, 30 Jun 2017 15:33:16 +0530 Subject: [PATCH 05/15] cpu_times_percent API --- pslib.h | 35 +++-- pslib_windows.c | 116 ++++++++++---- pslib_windows.h | 409 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 518 insertions(+), 42 deletions(-) create mode 100644 pslib_windows.h diff --git a/pslib.h b/pslib.h index 538d1c7..3b57229 100644 --- a/pslib.h +++ b/pslib.h @@ -3,6 +3,9 @@ #include #include #include +#ifndef pid_t +#define pid_t int +#endif enum proc_status { STATUS_RUNNING, @@ -63,7 +66,7 @@ enum con_status { IDLE, BOUND }; - +/* enum proc_priority { ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, @@ -72,7 +75,7 @@ enum proc_priority { NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS }; - +*/ typedef struct { uint64_t total; uint64_t used; @@ -158,6 +161,8 @@ typedef struct { uint64_t sout; } SwapMemInfo; +#if _WIN32 +#else typedef struct { double user; double system; @@ -170,7 +175,7 @@ typedef struct { double guest; double guest_nice; } CpuTimes; - +#endif typedef struct { pid_t pid; pid_t ppid; @@ -196,29 +201,29 @@ void free_disk_partition_info(DiskPartitionInfo *); DiskIOCounterInfo *disk_io_counters(void); void free_disk_iocounter_info(DiskIOCounterInfo *); -NetIOCounterInfo *net_io_counters(void); -void free_net_iocounter_info(NetIOCounterInfo *); +//NetIOCounterInfo *net_io_counters(void); +//void free_net_iocounter_info(NetIOCounterInfo *); UsersInfo *get_users(void); void free_users_info(UsersInfo *); -uint32_t get_boot_time(void); +//uint32_t get_boot_time(void); -bool virtual_memory(VmemInfo *); -bool swap_memory(SwapMemInfo *); +//bool virtual_memory(VmemInfo *); +//bool swap_memory(SwapMemInfo *); -CpuTimes *cpu_times(bool); +//CpuTimes *cpu_times(bool); -CpuTimes *cpu_times_percent(bool, CpuTimes *); +//CpuTimes *cpu_times_percent(bool, CpuTimes *); -double *cpu_util_percent(bool percpu, CpuTimes *prev_times); +//double *cpu_util_percent(bool percpu, CpuTimes *prev_times); -uint32_t cpu_count(bool); +//uint32_t cpu_count(bool); -bool pid_exists(pid_t); +//bool pid_exists(pid_t); -Process *get_process(pid_t); -void free_process(Process *); +//Process *get_process(pid_t); +//void free_process(Process *); /* Required to avoid [-Wimplicit-function-declaration] for python bindings */ void gcov_flush(void); diff --git a/pslib_windows.c b/pslib_windows.c index 8b927be..1d64d51 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -6,36 +6,10 @@ #include "pslib.h" #include "common.h" +#include "pslib_windows.h" #pragma comment(lib, "WTSAPI32.lib") -// fix for mingw32, see -// https://github.com/giampaolo/psutil/issues/351#c2 -typedef struct _DISK_PERFORMANCE_WIN_2008 { - LARGE_INTEGER BytesRead; - LARGE_INTEGER BytesWritten; - LARGE_INTEGER ReadTime; - LARGE_INTEGER WriteTime; - LARGE_INTEGER IdleTime; - DWORD ReadCount; - DWORD WriteCount; - DWORD QueueDepth; - DWORD SplitCount; - LARGE_INTEGER QueryTime; - DWORD StorageDeviceNumber; - WCHAR StorageManagerName[8]; -} DISK_PERFORMANCE_WIN_2008; -typedef struct _WINSTATION_INFO { - BYTE Reserved1[72]; - ULONG SessionId; - BYTE Reserved2[4]; - FILETIME ConnectTime; - FILETIME DisconnectTime; - FILETIME LastInputTime; - FILETIME LoginTime; - BYTE Reserved3[1096]; - FILETIME CurrentTime; -} WINSTATION_INFO; DiskIOCounterInfo *disk_io_counters(void) { @@ -382,3 +356,91 @@ void free_users_info(UsersInfo *u) free(u->users); free(u); } + +double get_valid_value(double a) +{ + if (a <= 0.0) + return 0.0; + else if (a > 100.0) + return 100.0; + else + return a; +} +CpuTimes *calculate(CpuTimes *t1, CpuTimes * t2) +{ + double all_delta; + int i; + CpuTimes *ret; + ret = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + check_mem(ret); + all_delta = (t2->user + t2->system + t2->interrupt + t2->idle + t2->dpc) - \ + (t1->user + t1->system + t1->interrupt + t1->idle + t1->dpc); + if (all_delta == 0) + { + all_delta = 100; + } + ret->user = get_valid_value((t2->user - t1->user)*100.0 / all_delta); + ret->system = get_valid_value((t2->system - t1->system)*100.0 / all_delta); + ret->interrupt = get_valid_value((t2->interrupt - t1->interrupt)*100.0 / all_delta); + ret->idle = get_valid_value((t2->idle - t1->idle)*100.0 / all_delta); + ret->dpc = get_valid_value((t2->dpc - t1->dpc)*100.0 / all_delta); + return ret; +error: + if (ret) + { + free(ret); + } + return NULL; +} + +/*"""Same as cpu_percent() but provides utilization percentages +for each specific CPU time as is returned by cpu_times(). + +*interval* and *percpu* arguments have the same meaning as in +cpu_percent(). +"""*/ + +CpuTimes *cpu_times_percent(bool percpu, CpuTimes * Last_Cpu_times) +{ + uint32_t no_cpu, i; + CpuTimes *t2 = NULL, *ret = NULL, *tmp = NULL; + t2 = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + check_mem(t2); + if (!percpu) { + t2 = cpu_times(false); + ret = calculate(t2, Last_Cpu_times); + } + + // # per - cpu usage + else { + ret = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + check_mem(ret); + t2 = cpu_times(true); + + no_cpu = cpu_count(true); + //t2, t2 in zip(tot2, _last_per_cpu_times_2) : + for (i = 0; i < no_cpu; i++) + { + ret = (CpuTimes *)realloc(ret, (i + 1) * sizeof(CpuTimes)); + check_mem(ret); + tmp = calculate(&t2[i], &Last_Cpu_times[i]); + check(tmp, "Error in calculting difference"); + ret[i].user = tmp->user; + ret[i].system = tmp->system; + ret[i].interrupt = tmp->interrupt; + ret[i].idle = tmp->idle; + ret[i].dpc = tmp->dpc; + free(tmp); + } + + } + return ret; +error: + if (tmp) + free(tmp); + if (t2) + free(t2); + if (ret) + free(ret); + return NULL; +} diff --git a/pslib_windows.h b/pslib_windows.h new file mode 100644 index 0000000..00db051 --- /dev/null +++ b/pslib_windows.h @@ -0,0 +1,409 @@ +#pragma once + +#include +#include +#define LO_T ((double)1e-7) +#define HI_T (LO_T*4294967296.0) + +#define ERROR_NOSUCHPROCESS 0x8000001 + +typedef BOOL(WINAPI *LPFN_GLPI) +(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); +// fix for mingw32, see +// https://github.com/giampaolo/psutil/issues/351#c2 +typedef struct _DISK_PERFORMANCE_WIN_2008 { + LARGE_INTEGER BytesRead; + LARGE_INTEGER BytesWritten; + LARGE_INTEGER ReadTime; + LARGE_INTEGER WriteTime; + LARGE_INTEGER IdleTime; + DWORD ReadCount; + DWORD WriteCount; + DWORD QueueDepth; + DWORD SplitCount; + LARGE_INTEGER QueryTime; + DWORD StorageDeviceNumber; + WCHAR StorageManagerName[8]; +} DISK_PERFORMANCE_WIN_2008; + +typedef struct _WINSTATION_INFO { + BYTE Reserved1[72]; + ULONG SessionId; + BYTE Reserved2[4]; + FILETIME ConnectTime; + FILETIME DisconnectTime; + FILETIME LastInputTime; + FILETIME LoginTime; + BYTE Reserved3[1096]; + FILETIME CurrentTime; +} WINSTATION_INFO; + +typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)( + HANDLE ProcessHandle, + DWORD ProcessInformationClass, + PVOID ProcessInformation, + DWORD ProcessInformationLength, + PDWORD ReturnLength + ); +enum psutil_process_data_kind { + KIND_CMDLINE, + KIND_CWD, + KIND_ENVIRON, +}; + +// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx +typedef struct { + BYTE Reserved1[16]; + PVOID Reserved2[5]; + UNICODE_STRING CurrentDirectoryPath; + PVOID CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + LPCWSTR env; +} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_; + +// https://msdn.microsoft.com/en-us/library/aa813706(v=vs.85).aspx +#ifdef _WIN64 +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[21]; + PVOID LoaderData; + PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters; + /* More fields ... */ +} PEB_; +#else +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PVOID Ldr; + PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters; + /* More fields ... */ +} PEB_; +#endif +#ifdef _WIN64 +/* When we are a 64 bit process accessing a 32 bit (WoW64) process we need to +use the 32 bit structure layout. */ +typedef struct { + USHORT Length; + USHORT MaxLength; + DWORD Buffer; +} UNICODE_STRING32; + +typedef struct { + BYTE Reserved1[16]; + DWORD Reserved2[5]; + UNICODE_STRING32 CurrentDirectoryPath; + DWORD CurrentDirectoryHandle; + UNICODE_STRING32 DllPath; + UNICODE_STRING32 ImagePathName; + UNICODE_STRING32 CommandLine; + DWORD env; +} RTL_USER_PROCESS_PARAMETERS32; + +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + DWORD Reserved3[2]; + DWORD Ldr; + DWORD ProcessParameters; + /* More fields ... */ +} PEB32; +#else +/* When we are a 32 bit (WoW64) process accessing a 64 bit process we need to +use the 64 bit structure layout and a special function to read its memory. +*/ +typedef NTSTATUS(NTAPI *_NtWow64ReadVirtualMemory64)( + IN HANDLE ProcessHandle, + IN PVOID64 BaseAddress, + OUT PVOID Buffer, + IN ULONG64 Size, + OUT PULONG64 NumberOfBytesRead); + +typedef enum { + MemoryInformationBasic +} MEMORY_INFORMATION_CLASS; + +typedef NTSTATUS(NTAPI *_NtWow64QueryVirtualMemory64)( + IN HANDLE ProcessHandle, + IN PVOID64 BaseAddress, + IN MEMORY_INFORMATION_CLASS MemoryInformationClass, + OUT PMEMORY_BASIC_INFORMATION64 MemoryInformation, + IN ULONG64 Size, + OUT PULONG64 ReturnLength OPTIONAL); + +typedef struct { + PVOID Reserved1[2]; + PVOID64 PebBaseAddress; + PVOID Reserved2[4]; + PVOID UniqueProcessId[2]; + PVOID Reserved3[2]; +} PROCESS_BASIC_INFORMATION64; + +typedef struct { + USHORT Length; + USHORT MaxLength; + PVOID64 Buffer; +} UNICODE_STRING64; + +typedef struct { + BYTE Reserved1[16]; + PVOID64 Reserved2[5]; + UNICODE_STRING64 CurrentDirectoryPath; + PVOID64 CurrentDirectoryHandle; + UNICODE_STRING64 DllPath; + UNICODE_STRING64 ImagePathName; + UNICODE_STRING64 CommandLine; + PVOID64 env; +} RTL_USER_PROCESS_PARAMETERS64; + +typedef struct { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[21]; + PVOID64 LoaderData; + PVOID64 ProcessParameters; + /* More fields ... */ +} PEB64; +#endif + +typedef struct { + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG PeakCommitment; + ULONG PageFaultCount; + ULONG CopyOnWriteCount; + ULONG TransitionCount; + ULONG CacheTransitionCount; + ULONG DemandZeroCount; + ULONG PageReadCount; + ULONG PageReadIoCount; + ULONG CacheReadCount; + ULONG CacheIoCount; + ULONG DirtyPagesWriteCount; + ULONG DirtyWriteIoCount; + ULONG MappedPagesWriteCount; + ULONG MappedWriteIoCount; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG ResidentSystemCodePage; + ULONG TotalSystemDriverPages; + ULONG TotalSystemCodePages; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG AvailablePagedPoolPages; + ULONG ResidentSystemCachePage; + ULONG ResidentPagedPoolPage; + ULONG ResidentSystemDriverPage; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadResourceMiss; + ULONG CcFastReadNotPossible; + ULONG CcFastMdlReadNoWait; + ULONG CcFastMdlReadWait; + ULONG CcFastMdlReadResourceMiss; + ULONG CcFastMdlReadNotPossible; + ULONG CcMapDataNoWait; + ULONG CcMapDataWait; + ULONG CcMapDataNoWaitMiss; + ULONG CcMapDataWaitMiss; + ULONG CcPinMappedDataCount; + ULONG CcPinReadNoWait; + ULONG CcPinReadWait; + ULONG CcPinReadNoWaitMiss; + ULONG CcPinReadWaitMiss; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG CcCopyReadWaitMiss; + ULONG CcMdlReadNoWait; + ULONG CcMdlReadWait; + ULONG CcMdlReadNoWaitMiss; + ULONG CcMdlReadWaitMiss; + ULONG CcReadAheadIos; + ULONG CcLazyWriteIos; + ULONG CcLazyWritePages; + ULONG CcDataFlushes; + ULONG CcDataPages; + ULONG ContextSwitches; + ULONG FirstLevelTbFills; + ULONG SecondLevelTbFills; + ULONG SystemCalls; + +} _SYSTEM_PERFORMANCE_INFORMATION; + + +typedef struct { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + + +typedef struct { + ULONG ContextSwitches; + ULONG DpcCount; + ULONG DpcRate; + ULONG TimeIncrement; + ULONG DpcBypassCount; + ULONG ApcBypassCount; +} _SYSTEM_INTERRUPT_INFORMATION; + +typedef struct { + pid_t *pid; + pid_t *ppid; + uint32_t nitems; +} pid_parent_map; + +typedef enum _KTHREAD_STATE { + Initialized, + Ready, + Running, + Standby, + Terminated, + Waiting, + Transition, + DeferredReady, + GateWait, + MaximumThreadState +} KTHREAD_STATE, *PKTHREAD_STATE; + + +typedef enum _KWAIT_REASON { + Executive = 0, + FreePage = 1, + PageIn = 2, + PoolAllocation = 3, + DelayExecution = 4, + Suspended = 5, + UserRequest = 6, + WrExecutive = 7, + WrFreePage = 8, + WrPageIn = 9, + WrPoolAllocation = 10, + WrDelayExecution = 11, + WrSuspended = 12, + WrUserRequest = 13, + WrEventPair = 14, + WrQueue = 15, + WrLpcReceive = 16, + WrLpcReply = 17, + WrVirtualMemory = 18, + WrPageOut = 19, + WrRendezvous = 20, + Spare2 = 21, + Spare3 = 22, + Spare4 = 23, + Spare5 = 24, + WrCalloutStack = 25, + WrKernel = 26, + WrResource = 27, + WrPushLock = 28, + WrMutex = 29, + WrQuantumEnd = 30, + WrDispatchInt = 31, + WrPreempted = 32, + WrYieldExecution = 33, + WrFastMutex = 34, + WrGuardedMutex = 35, + WrRundown = 36, + MaximumWaitReason = 37 +} KWAIT_REASON, *PKWAIT_REASON; + +typedef struct _CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef struct _SYSTEM_THREAD_INFORMATION { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + LONG Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + KWAIT_REASON WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + +typedef struct _SYSTEM_PROCESS_INFORMATION2 { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + LONG BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG_PTR PageDirectoryBase; + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; + SYSTEM_THREAD_INFORMATION Threads[1]; +} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2; + +#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2 +#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2 + +#define PSUTIL_FIRST_PROCESS(Processes) ( \ + (PSYSTEM_PROCESS_INFORMATION)(Processes)) +#define PSUTIL_NEXT_PROCESS(Process) ( \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \ + (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \ + ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : NULL) + +const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; +const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; + +typedef struct +{ + double user; + double system; + double idle; + double interrupt; + double dpc; +}CpuTimes; From 5b2501d5729584f6b59239aae63cc7af825f94b7 Mon Sep 17 00:00:00 2001 From: athulma188 Date: Sat, 1 Jul 2017 12:04:38 +0530 Subject: [PATCH 06/15] Add virtual-memory, swap memory, cputimes, cpu_stats, cpu_count, pids, pid_exists, get_boot_time APIs --- pslib_windows.c | 630 +++++++++++++++++++++++++++++++++++++++++++++++- pslib_windows.h | 161 +++++++++++-- 2 files changed, 776 insertions(+), 15 deletions(-) diff --git a/pslib_windows.c b/pslib_windows.c index 1d64d51..0a3093f 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "pslib.h" #include "common.h" @@ -30,7 +31,7 @@ DiskIOCounterInfo *disk_io_counters(void) { hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hDevice == INVALID_HANDLE_VALUE) + if (hDevice ==INVALID_HANDLE_VALUE) { continue; } @@ -444,3 +445,630 @@ CpuTimes *cpu_times_percent(bool percpu, CpuTimes * Last_Cpu_times) free(ret); return NULL; } + + +bool swap_memory(SwapMemInfo *ret) +{ + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + + if (! GlobalMemoryStatusEx(&memInfo)) + return false; + + ret->total = memInfo.ullTotalPageFile; + ret->free = memInfo.ullAvailPageFile; + ret->used = ret->total - ret->free; + ret->percent = (ret->used)*100.0/ret->total; + ret->sin=0; + ret->sout=0; + return true; +} + +bool virtual_memory(VirtMemInfo *ret) +{ + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + + if (! GlobalMemoryStatusEx(&memInfo)) + return false; + + ret->total = memInfo.ullTotalPhys; + ret->avail = memInfo.ullAvailPhys; + ret->used = ret->total - ret->avail; + ret->percent = (ret->used)*100.0/ret->total; + return true; +} + + + +unsigned int cpu_count_logical() { + SYSTEM_INFO system_info; + system_info.dwNumberOfProcessors = 0; + + GetSystemInfo(&system_info); + if (system_info.dwNumberOfProcessors == 0) + return 0; + else + return system_info.dwNumberOfProcessors; +} + +unsigned int cpu_count_phys() { + LPFN_GLPI glpi; + DWORD rc; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; + DWORD length = 0; + DWORD offset = 0; + unsigned int ncpus = 0; + + glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), + "GetLogicalProcessorInformation"); + check(glpi,""); + + while (1) { + rc = glpi(buffer, &length); + if (rc == FALSE) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + if (buffer) + free(buffer); + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( + length); + check(buffer,""); + } + else { + goto error; + } + } + else { + break; + } + } + + ptr = buffer; + while (offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= length) { + if (ptr->Relationship == RelationProcessorCore) + ncpus += 1; + offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + ptr++; + } + + free(buffer); + if (ncpus == 0) + goto error; + else + return ncpus; + +error: + + if (buffer != NULL) + free(buffer); + return 0; +} + +unsigned int cpu_count(bool logical) +{ + if(logical) + return cpu_count_logical(); + else + return cpu_count_phys(); +} +uint32_t get_boot_time() { +#if (_WIN32_WINNT >= 0x0600) // Windows Vista + ULONGLONG uptime; +#else + double uptime; + +#endif + time_t pt; + FILETIME fileTime; + long long ll; + HINSTANCE hKernel32; + psutil_GetTickCount64 = NULL; + + GetSystemTimeAsFileTime(&fileTime); + + ll = (((LONGLONG)(fileTime.dwHighDateTime)) << 32) + + fileTime.dwLowDateTime; + pt = (time_t)((ll - 116444736000000000ull) / 10000000ull); + + hKernel32 = GetModuleHandleW(L"KERNEL32"); + psutil_GetTickCount64 = (void*)GetProcAddress(hKernel32, "GetTickCount64"); + if (psutil_GetTickCount64 != NULL) { + // Windows >= Vista + uptime = psutil_GetTickCount64() / (ULONGLONG)1000.00f; + } + else { + // Windows XP. + uptime = GetTickCount() / 1000.00f; + } + + return pt - uptime; +} + +CpuTimes* per_cpu_times() { + // NtQuerySystemInformation stuff + typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + + float idle, kernel, systemt, user, interrupt, dpc; + NTSTATUS status; + _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; + SYSTEM_INFO si; + UINT i; + // obtain NtQuerySystemInformation + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + check(hNtDll,"Error in loading library 'ntdll'"); + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + + check(NtQuerySystemInformation, "Unable to fetch NtQuerySystemInformation"); + + // retrives number of processors + GetSystemInfo(&si); + + // allocates an array of _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION + // structures, one per processor + sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + check(sppi,"Unable to allocate array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION"); + + // gets cpu time informations + status = NtQuerySystemInformation( + SystemProcessorPerformanceInformation, + sppi, + si.dwNumberOfProcessors * sizeof + (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), + NULL); + check(status==0,"Unable to get CPU time"); + + + CpuTimes *ret = (CpuTimes*)calloc(si.dwNumberOfProcessors,sizeof(CpuTimes)); + CpuTimes *c=ret; + if(!ret) + goto error; + // computes system global times summing each + // processor value + idle = user = kernel = interrupt = dpc = 0; + for (i = 0; i < si.dwNumberOfProcessors; i++) { + user = (float)((HI_T * sppi[i].UserTime.HighPart) + + (LO_T * sppi[i].UserTime.LowPart)); + idle = (float)((HI_T * sppi[i].IdleTime.HighPart) + + (LO_T * sppi[i].IdleTime.LowPart)); + kernel = (float)((HI_T * sppi[i].KernelTime.HighPart) + + (LO_T * sppi[i].KernelTime.LowPart)); + interrupt = (float)((HI_T * sppi[i].InterruptTime.HighPart) + + (LO_T * sppi[i].InterruptTime.LowPart)); + dpc = (float)((HI_T * sppi[i].DpcTime.HighPart) + + (LO_T * sppi[i].DpcTime.LowPart)); + + // kernel time includes idle time on windows + // we return only busy kernel time subtracting + // idle time from kernel time + systemt = kernel - idle; + + c->user=user; + c->system=systemt; + c->interrupt=interrupt; + c->idle=idle; + c->dpc=dpc; + ++c; + } + + free(sppi); + FreeLibrary(hNtDll); + return ret; + +error: + if (sppi) + free(sppi); + if (hNtDll) + FreeLibrary(hNtDll); + return NULL; +} +CpuTimes *sum_per_cpu_times(CpuTimes *per_cpu) +{ + UINT i; + CpuTimes *ret = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + check_mem(ret); + float user,system,idle,dpc,interrupt; + idle = user = system = interrupt = dpc = 0; + CpuTimes *c = per_cpu; + for(i = 0; i < cpu_count(true); ++i) + { + user += c->user; + system += c->system; + idle += c->idle; + interrupt += c->interrupt; + dpc += c->dpc; + ++c; + } + ret->user=user; + ret->system=system; + ret->idle=idle; + ret->interrupt=interrupt; + ret->dpc=dpc; + return ret; +error: + return NULL; +} +CpuTimes *cpu_times_summed() + { + float idle, kernel, user, system; + FILETIME idle_time, kernel_time, user_time; + + check(GetSystemTimes(&idle_time, &kernel_time, &user_time),"") + + idle = (float)((HI_T * idle_time.dwHighDateTime) + \ + (LO_T * idle_time.dwLowDateTime)); + user = (float)((HI_T * user_time.dwHighDateTime) + \ + (LO_T * user_time.dwLowDateTime)); + kernel = (float)((HI_T * kernel_time.dwHighDateTime) + \ + (LO_T * kernel_time.dwLowDateTime)); + + // Kernel time includes idle time. + // We return only busy kernel time subtracting idle time from + // kernel time. + system = (kernel - idle); + CpuTimes *data = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + check_mem(data); + data->idle=idle; + data->system=system; + data->user=user; + + CpuTimes *percpu = per_cpu_times(); + check_mem(percpu); + CpuTimes *percpu_summed = sum_per_cpu_times(percpu); + check_mem(percpu_summed); + free(percpu); + data->interrupt = percpu_summed->interrupt; + data->dpc= percpu_summed->dpc; + free(percpu_summed); + return data; +error: + return NULL; +} +CpuTimes *cpu_times(bool percpu) +{ + CpuTimes *ret; + if(!percpu) + { + return cpu_times_summed(); + } + else + return per_cpu_times(); + + +} + +CpuStats *cpu_stats() { + // NtQuerySystemInformation stuff + typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + + NTSTATUS status; + _SYSTEM_PERFORMANCE_INFORMATION *spi = NULL; + _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; + _SYSTEM_INTERRUPT_INFORMATION *InterruptInformation = NULL; + SYSTEM_INFO si; + UINT i; + ULONG64 dpcs = 0; + ULONG interrupts = 0; + + // obtain NtQuerySystemInformation + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + check(hNtDll,"Unable to fetch library 'ntdll'"); + + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + + check(NtQuerySystemInformation, "Unable to fetch NtQuerySystemInformation"); + + // retrives number of processors + GetSystemInfo(&si); + + // get syscalls / ctx switches + spi = (_SYSTEM_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PERFORMANCE_INFORMATION)); + check_mem(spi); + status = NtQuerySystemInformation( + SystemPerformanceInformation, + spi, + si.dwNumberOfProcessors * sizeof(_SYSTEM_PERFORMANCE_INFORMATION), + NULL); + + check(status==0,""); + + // get DPCs + InterruptInformation = \ + malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) * + si.dwNumberOfProcessors); + + check_mem(InterruptInformation); + status = NtQuerySystemInformation( + SystemInterruptInformation, + InterruptInformation, + si.dwNumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION), + NULL); + check(status==0,""); + + for (i = 0; i < si.dwNumberOfProcessors; i++) { + dpcs += InterruptInformation[i].DpcCount; + } + + // get interrupts + sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ + malloc(si.dwNumberOfProcessors * \ + sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + check_mem(sppi); + + status = NtQuerySystemInformation( + SystemProcessorPerformanceInformation, + sppi, + si.dwNumberOfProcessors * sizeof + (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), + NULL); + + check(status==0,""); + + for (i = 0; i < si.dwNumberOfProcessors; i++) { + interrupts += sppi[i].InterruptCount; + } + + // done + free(spi); + free(InterruptInformation); + free(sppi); + FreeLibrary(hNtDll); + + + CpuStats *ret = (CpuStats*)calloc(1,sizeof(CpuStats)); + check_mem(ret); + ret->ctx_switches = spi->ContextSwitches; + ret->interrupts = interrupts; + ret->dpcs = (unsigned long)dpcs; + ret->soft_interrupts = 0; + ret->syscalls = spi->SystemCalls; + + return ret; + + +error: + if (spi) + free(spi); + if (InterruptInformation) + free(InterruptInformation); + if (sppi) + free(sppi); + if (hNtDll) + FreeLibrary(hNtDll); + return NULL; +} + +uint32_t *pids(DWORD *numberOfReturnedPIDs) { + + + DWORD *procArray = NULL; + DWORD procArrayByteSz; + int procArraySz = 0; + + // Stores the byte size of the returned array from enumprocesses + DWORD enumReturnSz = 0; + + do { + procArraySz += 1024; + free(procArray); + procArrayByteSz = procArraySz * sizeof(DWORD); + procArray = malloc(procArrayByteSz); + + check_mem(procArray); + + check(K32EnumProcesses(procArray, procArrayByteSz, &enumReturnSz),"Unable to enumerate processes"); + } while (enumReturnSz == procArraySz * sizeof(DWORD)); + + // The number of elements is the returned size / size of each element + *numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD); + + check(procArray,""); + + return procArray; + error: + + if (procArray != NULL) + free(procArray); + return NULL; +} + +int pid_is_running(DWORD pid) { + HANDLE hProcess; + DWORD exitCode; + + // Special case for PID 0 System Idle Process + if (pid == 0) + return 1; + if (pid < 0) + return 0; + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE, pid); + if (NULL == hProcess) { + // invalid parameter is no such process + if (GetLastError() == ERROR_INVALID_PARAMETER) { + CloseHandle(hProcess); + return 0; + } + + // access denied obviously means there's a process to deny access to... + if (GetLastError() == ERROR_ACCESS_DENIED) { + CloseHandle(hProcess); + return 1; + } + + CloseHandle(hProcess); + //PyErr_SetFromWindowsErr(0); + return -1; + } + + if (GetExitCodeProcess(hProcess, &exitCode)) { + CloseHandle(hProcess); + return (exitCode == STILL_ACTIVE); + } + + // access denied means there's a process there so we'll assume + // it's running + if (GetLastError() == ERROR_ACCESS_DENIED) { + CloseHandle(hProcess); + return 1; + } + + //PyErr_SetFromWindowsErr(0); + CloseHandle(hProcess); + return -1; +} + +bool pid_exists(long pid) +{ + int status; + + status = pid_is_running(pid); + + check(status!=-1,"Exception raised in pid_is_running"); + return status; + error: + return false; +} + +/* +void test_virtual_memory() +{ + VirtMemInfo virt; + if(!virtual_memory(&virt)) + { + printf("Aborting\n"); + return; + } + printf("_______Virtual Memory_______\n"); + printf("Total=%lld, Used=%lld, Free=%lld, Percent=%f\n\n",virt.total,virt.used, virt.avail,virt.percent); +} +void test_swap_memory() +{ + SwapMemInfo swap; + if(!swap_memory(&swap)) + { + printf("Aborting\n"); + return; + } + printf("________Swap Memory________\n"); + printf("Total=%llu, Used=%llu, Free=%llu, Percent=%f, sin=%llu, sout=%llu\n\n",swap.total,swap.used, swap.free,swap.percent,swap.sin,swap.sout); + + +} +void test_pids() +{ + DWORD numberOfPIDs; + DWORD *pid = pids(&numberOfPIDs); + DWORD *c=pid; + DWORD i; + if(!pid) + { + printf("Aborting...\n"); + return; + } + printf("__________PIDs_________\n"); + for(i=0;ictx_switches); + printf("Interrupts = %lu \n", tmp->interrupts); + printf("Soft Interrupts = %lu \n", tmp->soft_interrupts); + printf("System Calls = %lu \n", tmp->syscalls); + printf("Dpcs = %lu \n\n", tmp->dpcs); + free(tmp); +} +void test_cputimes() +{ + CpuTimes * data = cpu_times(false); + if(!data) + { + printf("Aborting..\n"); + return; + } + printf("_________CPU Times_________\n"); + printf("User=%f, Idle=%f, System=%f, Interrupt=%f, Dpc=%f\n\n",data->user,data->idle,data->system,data->interrupt,data->dpc); + free(data); +} +void test_percputimes() +{ + CpuTimes * r = cpu_times(true); + if(!r) + { + printf("Aborting..\n"); + return; + } + printf("_______CPU Times_Per CPU_______\n"); + CpuTimes * c=r; + UINT i; + for(i=0;iuser,c->idle,c->system,c->interrupt,c->dpc); + ++c; + } + printf("\n"); + free(r); +} +void test_boottime() +{ + uint32_t time = get_boot_time(); + printf("_________Boot Time_________\n"); + printf("%"PRIu32"\n\n", time); +} +void test_pid_exists() +{ + long pid=0;int i =0; + printf("_________PID Exists_________\n"); + + for (pid=rand()%22000,i=0;i<20;++i,pid=rand()%22000) + { + int x =0; + x = pid_exists(pid); + printf("%ld - %s \n",pid,x?"true":"false"); + + } +} + +void test_cpucount() +{ + printf("_________CPU Count_________\n"); + printf("Number of Logical Processors: %d\n",cpu_count(true)); + printf("Number of Physical Processors: %d\n\n",cpu_count(false)); +} +void main() +{ + test_virtual_memory(); + test_swap_memory(); + test_cpucount(); + test_cputimes(); + test_percputimes(); + test_boottime(); + test_cpu_stats(); + test_pids(); + test_pid_exists(); + +} +*/ diff --git a/pslib_windows.h b/pslib_windows.h index 00db051..e3fecb6 100644 --- a/pslib_windows.h +++ b/pslib_windows.h @@ -2,9 +2,10 @@ #include #include + #define LO_T ((double)1e-7) #define HI_T (LO_T*4294967296.0) - +static ULONGLONG (*psutil_GetTickCount64)(void) = NULL; #define ERROR_NOSUCHPROCESS 0x8000001 typedef BOOL(WINAPI *LPFN_GLPI) @@ -246,20 +247,103 @@ typedef struct { ULONG FirstLevelTbFills; ULONG SecondLevelTbFills; ULONG SystemCalls; - + } _SYSTEM_PERFORMANCE_INFORMATION; - typedef struct { - LARGE_INTEGER IdleTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER DpcTime; - LARGE_INTEGER InterruptTime; - ULONG InterruptCount; + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; } _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; +typedef struct { + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG PeakCommitment; + ULONG PageFaultCount; + ULONG CopyOnWriteCount; + ULONG TransitionCount; + ULONG CacheTransitionCount; + ULONG DemandZeroCount; + ULONG PageReadCount; + ULONG PageReadIoCount; + ULONG CacheReadCount; + ULONG CacheIoCount; + ULONG DirtyPagesWriteCount; + ULONG DirtyWriteIoCount; + ULONG MappedPagesWriteCount; + ULONG MappedWriteIoCount; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG ResidentSystemCodePage; + ULONG TotalSystemDriverPages; + ULONG TotalSystemCodePages; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG AvailablePagedPoolPages; + ULONG ResidentSystemCachePage; + ULONG ResidentPagedPoolPage; + ULONG ResidentSystemDriverPage; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadResourceMiss; + ULONG CcFastReadNotPossible; + ULONG CcFastMdlReadNoWait; + ULONG CcFastMdlReadWait; + ULONG CcFastMdlReadResourceMiss; + ULONG CcFastMdlReadNotPossible; + ULONG CcMapDataNoWait; + ULONG CcMapDataWait; + ULONG CcMapDataNoWaitMiss; + ULONG CcMapDataWaitMiss; + ULONG CcPinMappedDataCount; + ULONG CcPinReadNoWait; + ULONG CcPinReadWait; + ULONG CcPinReadNoWaitMiss; + ULONG CcPinReadWaitMiss; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG CcCopyReadWaitMiss; + ULONG CcMdlReadNoWait; + ULONG CcMdlReadWait; + ULONG CcMdlReadNoWaitMiss; + ULONG CcMdlReadWaitMiss; + ULONG CcReadAheadIos; + ULONG CcLazyWriteIos; + ULONG CcLazyWritePages; + ULONG CcDataFlushes; + ULONG CcDataPages; + ULONG ContextSwitches; + ULONG FirstLevelTbFills; + ULONG SecondLevelTbFills; + ULONG SystemCalls; + ULONG ContextSwitches; + ULONG DpcCount; + ULONG DpcRate; + ULONG TimeIncrement; + ULONG DpcBypassCount; + ULONG ApcBypassCount; +} _SYSTEM_INTERRUPT_INFORMATION; + + /* typedef struct { ULONG ContextSwitches; ULONG DpcCount; @@ -269,6 +353,8 @@ typedef struct { ULONG ApcBypassCount; } _SYSTEM_INTERRUPT_INFORMATION; + + */ typedef struct { pid_t *pid; pid_t *ppid; @@ -399,11 +485,58 @@ typedef struct _SYSTEM_PROCESS_INFORMATION2 { const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; + typedef struct { - double user; - double system; - double idle; - double interrupt; - double dpc; + unsigned long ctx_switches; + unsigned long interrupts; + unsigned long soft_interrupts; + unsigned long syscalls; + unsigned long dpcs; +}CpuStats; + +typedef struct +{ + unsigned long min; + unsigned long max; + unsigned long current; + +}CpuFreq; + +typedef struct +{ + long long total; + long long avail; + long long used; + float percent; +}VirtMemInfo; + +typedef struct { + uint64_t total; + uint64_t used; + uint64_t free; + float percent; + uint64_t sin; + uint64_t sout; +} SwapMemInfo; + +typedef struct +{ + float user; + float system; + float idle; + float interrupt; + float dpc; }CpuTimes; + + +uint32_t get_boot_time(void); +bool virtual_memory(VmemInfo *); +bool swap_memory(SwapMemInfo *); +CpuTimes *cpu_times(bool); +uint32_t cpu_count(bool); +bool pid_exists(pid_t); +uint32_t *pids(DWORD*); +CpuStats *cpu_stats(); + + From f637a4b5e402af00fdf560db088a6f6a405534cc Mon Sep 17 00:00:00 2001 From: athulma188 Date: Sat, 1 Jul 2017 12:13:55 +0530 Subject: [PATCH 07/15] Add net_io_counters API --- pslib_windows.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++- pslib_windows.h | 21 ++++- 2 files changed, 261 insertions(+), 5 deletions(-) diff --git a/pslib_windows.c b/pslib_windows.c index 0a3093f..3366ebe 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -4,11 +4,16 @@ #include #include #include - +#include +#include +#include +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above +#include +#endif #include "pslib.h" #include "common.h" #include "pslib_windows.h" - +#pragma comment(lib, "IPHLPAPI.lib") #pragma comment(lib, "WTSAPI32.lib") @@ -940,7 +945,241 @@ bool pid_exists(long pid) return false; } + +PIP_ADAPTER_ADDRESSES get_nic_addresses() { + // allocate a 15 KB buffer to start with + ULONG outBufLen = 15000; + DWORD dwRetVal = 0; + ULONG attempts = 0; + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + + do { + pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); + if (pAddresses == NULL) { + //PyErr_NoMemory(); + return NULL; + } + + dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen); + if (dwRetVal == ERROR_BUFFER_OVERFLOW) { + free(pAddresses); + pAddresses = NULL; + } + else { + break; + } + + attempts++; + } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); + + if (dwRetVal != NO_ERROR) { + //PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() syscall failed."); + return NULL; + } + + return pAddresses; +} + + +NetIOCounterInfo *net_io_counters_per_nic() +{ + DWORD dwRetVal = 0; + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + MIB_IF_ROW2 *pIfRow = NULL; +#else // Windows XP + MIB_IFROW *pIfRow = NULL; +#endif + + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + //PyObject *py_retdict = PyDict_New(); + ///PyObject *py_nic_info = NULL; + //PyObject *py_nic_name = NULL; + + //if (py_retdict == NULL) + // return NULL; + pAddresses = get_nic_addresses(); + if (pAddresses == NULL) + goto error; + pCurrAddresses = pAddresses; + + + NetIOCounterInfo *ret = (NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + NetIOCounters *counters = (NetIOCounters*) calloc(15,sizeof(NetIOCounters)); + NetIOCounters *nc = counters; + //check_mem(counters); + //check_mem(ret); + ret->nitems = 0; + ret->iocounters = counters; + + while (pCurrAddresses) { + //py_nic_name = NULL; + //py_nic_info = NULL; + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2)); +#else // Windows XP + pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); +#endif + + if (pIfRow == NULL) { + //PyErr_NoMemory(); + goto error; + } + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2)); + pIfRow->InterfaceIndex = pCurrAddresses->IfIndex; + dwRetVal = GetIfEntry2(pIfRow); +#else // Windows XP + pIfRow->dwIndex = pCurrAddresses->IfIndex; + dwRetVal = GetIfEntry(pIfRow); +#endif + + if (dwRetVal != NO_ERROR) { + //PyErr_SetString(PyExc_RuntimeError,"GetIfEntry() or GetIfEntry2() syscalls failed."); + goto error; + } + +#if (_WIN32_WINNT >= 0x0600) // Windows Vista and above + + nc->bytes_sent = pIfRow->OutOctets; + nc->bytes_recv = pIfRow->InOctets; + nc->packets_sent = pIfRow->OutUcastPkts; + nc->packets_recv = pIfRow->InUcastPkts; + nc->errin = pIfRow->InErrors; + nc->errout = pIfRow->OutErrors; + nc->dropin = pIfRow->InDiscards; + nc->dropout = pIfRow->OutDiscards; + + +#else // Windows XP + nc->bytes_sent = pIfRow->dwOutOctets; + nc->bytes_recv = pIfRow->dwInOctets; + nc->packets_sent = pIfRow->dwOutUcastPkts; + nc->packets_recv = pIfRow->dwInUcastPkts; + nc->errin = pIfRow->dwInErrors; + nc->errout = pIfRow->dwOutErrors; + nc->dropin = pIfRow->dwInDiscards; + nc->dropout = pIfRow->dwOutDiscards; + +#endif + + nc->name = (char *)calloc(wcslen(pCurrAddresses->FriendlyName) + 1, sizeof(char)); + LPBOOL q = NULL; + int len; + len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName), nc->name, wcslen(pCurrAddresses->FriendlyName), "", q); + pCurrAddresses->FriendlyName[len] = '\0'; + if ( len == 0) + { + DWORD t; + t = GetLastError(); + //check(t != ERROR_INSUFFICIENT_BUFFER, "Supplied buffer size was not large enough, or it was incorrectly set to NULL."); + //check(t != ERROR_INVALID_FLAGS, "The values supplied for flags were not valid."); + //check(t != ERROR_INVALID_PARAMETER, "Any of the parameter values was invalid"); + //check(t != ERROR_NO_UNICODE_TRANSLATION, "Invalid Unicode was found in a string."); + } + + ret->nitems++; + nc++; + + + + free(pIfRow); + pCurrAddresses = pCurrAddresses->Next; + } + + free(pAddresses); + return ret; + +error: + if (pAddresses != NULL) + free(pAddresses); + if (pIfRow != NULL) + free(pIfRow); + if(ret!=NULL) + free(ret); + return NULL; +} +void free_netiocounterinfo(NetIOCounterInfo *ret) +{ + int i; + NetIOCounters *c=ret->iocounters; + for(i=0;initems;++i) + { + free(c->name); + ++c; + } + free(ret->iocounters); + free(ret); +} + +NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) +{ + NetIOCounterInfo *sum=(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + NetIOCounters *r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); + check(sum); + check(r); + sum->iocounters=r; + sum->nitems=1; + + int i; + + NetIOCounters *c=info->iocounters; + for(i=0;initems;++i) + { + r->bytes_recv+=c->bytes_recv; + r->bytes_sent+=c->bytes_sent; + r->dropin+=c->dropin; + r->dropout+=c->dropout; + r->errout+=c->errout; + r->errin+=c->errin; + r->packets_recv+=c->packets_recv; + r->packets_sent+=c->packets_sent; + ++c; + } + free_netiocounterinfo(info); + return sum; +} +NetIOCounterInfo *net_io_counters(bool per_nic) +{ + NetIOCounterInfo *ret = net_io_counters_per_nic(); + if(per_nic) + return ret; + else + return net_io_counters_summed(ret); +} + /* +void test_netiocounters() +{ + NetIOCounterInfo *c = net_io_counters(true); + NetIOCounters *r = c->iocounters; + + if(!c) + { + printf("Aborting..\n"); + return; + } + int i=0; + printf("__________NET IO COUNTERS_________\n"); + for(i=0;initems;++i) + { + printf("%s:\n",r->name); + printf("\tBytes Sent : %" PRIu64"\n",r->bytes_sent); + printf("\tBytes Received : %"PRIu64"\n",r->bytes_recv); + printf("\tPackets Sent : %"PRIu64"\n",r->packets_sent); + printf("\tPackets Received : %" PRIu64"\n",r->packets_recv); + printf("\tIn Errors : %" PRIu64"\n",r->errin); + printf("\tOut Errors : %" PRIu64"\n",r->errout); + printf("\tIn Discards : %" PRIu64"\n",r->dropin); + printf("\tOut Discards : %" PRIu64"\n",r->dropout); + ++r; + } + free_netiocounterinfo(c); + +} void test_virtual_memory() { VirtMemInfo virt; @@ -1069,6 +1308,6 @@ void main() test_cpu_stats(); test_pids(); test_pid_exists(); - + test_netiocounters(); } */ diff --git a/pslib_windows.h b/pslib_windows.h index e3fecb6..0115fc2 100644 --- a/pslib_windows.h +++ b/pslib_windows.h @@ -529,6 +529,23 @@ typedef struct float dpc; }CpuTimes; +typedef struct { + char *name; + uint64_t bytes_sent; + uint64_t bytes_recv; + uint64_t packets_sent; + uint64_t packets_recv; + uint64_t errin; + uint64_t errout; + uint64_t dropin; + uint64_t dropout; +} NetIOCounters; + +typedef struct { + uint32_t nitems; + NetIOCounters *iocounters; +} NetIOCounterInfo; + uint32_t get_boot_time(void); bool virtual_memory(VmemInfo *); @@ -538,5 +555,5 @@ uint32_t cpu_count(bool); bool pid_exists(pid_t); uint32_t *pids(DWORD*); CpuStats *cpu_stats(); - - +NetIOCounterInfo *net_io_counters(bool); +voi free_netiocounterinfo(NetIOCounterInfo*); From 63f0077308d0fb3b64712adb10e607c9f7ce1ad9 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Mon, 3 Jul 2017 22:07:41 +0530 Subject: [PATCH 08/15] Adds get_process API --- common.c | 148 +++--- common.h | 111 ++--- driver.c | 947 +++++++++++++++++++++---------------- pslib.h | 108 +++-- pslib_windows.c | 1185 ++++++++++++++++++++++++++++++++++------------- pslib_windows.h | 84 +--- 6 files changed, 1620 insertions(+), 963 deletions(-) diff --git a/common.c b/common.c index 0a2247e..f21ad5d 100644 --- a/common.c +++ b/common.c @@ -1,72 +1,76 @@ -#include -#include -#include - -#include "common.h" - -float percentage(uint64_t n, uint64_t d) { - /* TODO: Error check here */ - float percent = ((float)n / (float)d) * 100.0; - return percent; -} - -int str_comp(const void *key, const void *memb) { - const char **a = (const char **)key; - const char **b = (const char **)memb; - return strcmp(*a, *b); -} - -int int_comp(const void *key, const void *memb) { - const int a = *(int *)key; - const int b = *(int *)memb; - if (a == b) { - return 0; - } else { - return -1; - } -} - -char *grep_awk(FILE *fp, const char *fstr, int nfield, const char *delim) { - char *ret = NULL; - int i; - char *line = (char *)calloc(500, sizeof(char)); - check_mem(line); - while (fgets(line, 400, fp) != NULL) { - if (strncasecmp(line, fstr, strlen(fstr)) == 0) { - ret = strtok(line, delim); - for (i = 0; i < nfield; i++) { - ret = strtok(NULL, delim); - } - if (ret) { - ret = strdup(ret); - check_mem(ret); - free(line); - return ret; - } - } - } - free(line); - return NULL; -error: - return NULL; -} - -char *squeeze(char *string, const char *chars) { - char *src = string; - char *target = string; - char ch; - for (; *chars; chars++) { - ch = *chars; - src = string; - target = string; - while (*src != '\0') { - if (*src != ch) { - *target = *src; - target++; - } - src++; - } - *target = '\0'; - } - return string; -} +#include +#include +#include + + +#include "common.h" +#ifdef _WIN32 +#define strncasecmp strnicmp +#endif + +float percentage(uint64_t n, uint64_t d) { + /* TODO: Error check here */ + float percent = ((float)n / (float)d) * 100.0; + return percent; +} + +int str_comp(const void *key, const void *memb) { + const char **a = (const char **)key; + const char **b = (const char **)memb; + return strcmp(*a, *b); +} + +int int_comp(const void *key, const void *memb) { + const int a = *(int *)key; + const int b = *(int *)memb; + if (a == b) { + return 0; + } else { + return -1; + } +} + +char *grep_awk(FILE *fp, const char *fstr, int nfield, const char *delim) { + char *ret = NULL; + int i; + char *line = (char *)calloc(500, sizeof(char)); + check_mem(line); + while (fgets(line, 400, fp) != NULL) { + if (strncasecmp(line, fstr, strlen(fstr)) == 0) { + ret = strtok(line, delim); + for (i = 0; i < nfield; i++) { + ret = strtok(NULL, delim); + } + if (ret) { + ret = strdup(ret); + check_mem(ret); + free(line); + return ret; + } + } + } + free(line); + return NULL; +error: + return NULL; +} + +char *squeeze(char *string, const char *chars) { + char *src = string; + char *target = string; + char ch; + for (; *chars; chars++) { + ch = *chars; + src = string; + target = string; + while (*src != '\0') { + if (*src != ch) { + *target = *src; + target++; + } + src++; + } + *target = '\0'; + } + return string; +} diff --git a/common.h b/common.h index 8d7b02b..5022cbb 100644 --- a/common.h +++ b/common.h @@ -1,55 +1,56 @@ -#pragma once - -#include -#include -#include -#include - -float percentage(uint64_t, uint64_t); -int str_comp(const void *, const void *); -int int_comp(const void *, const void *); -char *grep_awk(FILE *, const char *, int, const char *); -char *squeeze(char *, const char *); - -#ifdef NDEBUG -#define debug(M, ...) -#else -#define debug(M, ...) \ - fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) -#endif - -#define clean_errno() (errno == 0 ? "None" : strerror(errno)) - -#define log_err(M, ...) \ - fprintf(stderr, "[ERROR] (%s:%d:%s: errno: %d, %s) " M "\n", __FILE__, \ - __LINE__, __FUNCTION__, errno, clean_errno(), ##__VA_ARGS__) - -#define log_warn(M, ...) \ - fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \ - clean_errno(), ##__VA_ARGS__) - -#define log_info(M, ...) \ - fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) - -#define check(A, M, ...) \ - if (!(A)) { \ - log_err(M, ##__VA_ARGS__); \ - errno = 0; \ - goto error; \ - } - -#define sentinel(M, ...) \ - { \ - log_err(M, ##__VA_ARGS__); \ - errno = 0; \ - goto error; \ - } - -#define check_mem(A) check((A), "Out of memory.") - -#define check_debug(A, M, ...) \ - if (!(A)) { \ - debug(M, ##__VA_ARGS__); \ - errno = 0; \ - goto error; \ - } +#pragma once + +#include +#include +#include +#include + + +float percentage(uint64_t, uint64_t); +int str_comp(const void *, const void *); +int int_comp(const void *, const void *); +char *grep_awk(FILE *, const char *, int, const char *); +char *squeeze(char *, const char *); + +#ifdef NDEBUG +#define debug(M, ...) +#else +#define debug(M, ...) \ + fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) +#endif + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) + +#define log_err(M, ...) \ + fprintf(stderr, "[ERROR] (%s:%d:%s: errno: %d, %s) " M "\n", __FILE__, \ + __LINE__, __FUNCTION__, errno, clean_errno(), ##__VA_ARGS__) + +#define log_warn(M, ...) \ + fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#define log_info(M, ...) \ + fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) + +#define check(A, M, ...) \ + if (!(A)) { \ + log_err(M, ##__VA_ARGS__); \ + errno = 0; \ + goto error; \ + } + +#define sentinel(M, ...) \ + { \ + log_err(M, ##__VA_ARGS__); \ + errno = 0; \ + goto error; \ + } + +#define check_mem(A) check((A), "Out of memory.") + +#define check_debug(A, M, ...) \ + if (!(A)) { \ + debug(M, ##__VA_ARGS__); \ + errno = 0; \ + goto error; \ + } diff --git a/driver.c b/driver.c index aa331f7..87e803f 100644 --- a/driver.c +++ b/driver.c @@ -1,401 +1,546 @@ -#include -#include -#include -#include -#include -#include "pslib.h" - -void test_diskusage() { - DiskUsage du; - printf(" -- disk_usage \n"); - disk_usage("/", &du); - printf("/\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 - "\npercent: %.1f\n\n", - du.total, du.used, du.free, du.percent); - disk_usage("/etc", &du); - printf("/etc\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 - "\npercent: %.1f\n\n", - du.total, du.used, du.free, du.percent); -} - -void test_diskpartitioninfo() { - uint32_t i; - DiskPartitionInfo *phys_dp, *all_dp; - printf(" -- disk_partitions (physical) \n"); - phys_dp = disk_partitions(1); - if (!phys_dp) { - printf("Aborting\n"); - return; - } - printf("Partitions : %" PRIu32 "\n", phys_dp->nitems); - for (i = 0; i < phys_dp->nitems; i++) { - printf("%s %s %s %s\n", phys_dp->partitions[i].device, - phys_dp->partitions[i].mountpoint, phys_dp->partitions[i].fstype, - phys_dp->partitions[i].opts); - } - - free_disk_partition_info(phys_dp); - - printf("\n"); - - printf(" -- disk_partitions (all) \n"); - all_dp = disk_partitions(false); - if (!all_dp) { - printf("Aborting\n"); - return; - } - printf("Partitions : %" PRIu32 "\n", all_dp->nitems); - for (i = 0; i < all_dp->nitems; i++) { - printf("%s %s %s %s\n", all_dp->partitions[i].device, - all_dp->partitions[i].mountpoint, all_dp->partitions[i].fstype, - all_dp->partitions[i].opts); - } - - free_disk_partition_info(all_dp); - printf("\n"); -} - -void test_diskiocounters() { - DiskIOCounterInfo *d; - DiskIOCounters *dp; - d = disk_io_counters(); - if (!d) { - printf("Aborting"); - return; - } - - printf(" -- disk_io_counters \n"); - dp = d->iocounters; - uint32_t i; - for (i = 0; i < d->nitems; i++) { - printf("%s: \tread_count=%" PRIu64 ", write_count=%" PRIu64 ", \n" - "\tread_bytes=%" PRIu64 ", write_bytes=%" PRIu64 ", \n" - "\tread_time=%" PRIu64 ", write_time=%" PRIu64 "\n", - dp->name, dp->reads, dp->writes, dp->readbytes, dp->writebytes, - dp->readtime, dp->writetime); - dp++; - } - free_disk_iocounter_info(d); - printf("\n"); -} - -void test_netiocounters() { - NetIOCounterInfo *n; - NetIOCounters *dp; - uint32_t i; - n = net_io_counters(); - dp = n->iocounters; - printf(" -- net_io_counters (interface count: %" PRIu32 ")\n", n->nitems); - for (i = 0; i < n->nitems; i++) { - printf("%s: bytes_sent=%" PRIu64 " bytes_rec=%" PRIu64 - " packets_sen=%" PRIu64 " packets_rec=%" PRIu64 " " - "erri=%" PRIu64 " errou=%" PRIu64 " dropi=%" PRIu64 - " dropou=%" PRIu64 " \n", - dp->name, dp->bytes_sent, dp->bytes_recv, dp->packets_sent, - dp->packets_recv, dp->errin, dp->errout, dp->dropin, dp->dropout); - dp++; - } - free_net_iocounter_info(n); - printf("\n"); -} - -void test_getusers() { - UsersInfo *r; - uint32_t i; - printf(" -- users \n"); - r = get_users(); - if (!r) { - printf("Failed \n"); - return; - } - printf("Total: %" PRIu32 "\n", r->nitems); - printf("Name\tTerminal Host\tStarted\n"); - for (i = 0; i < r->nitems; i++) { - printf("%s\t%s\t %s\t%.1f\n", r->users[i].username, r->users[i].tty, - r->users[i].hostname, r->users[i].tstamp); - } - free_users_info(r); - printf("\n"); -} - -void test_boottime() { - uint32_t t = get_boot_time(); - printf(" -- boot_time \n"); - if (t == UINT32_MAX) { - printf("Aborting\n"); - return; - } - printf("%" PRIu32 "\n\n", t); -} - -void test_virtualmeminfo() { - VmemInfo r; - // Empty out to prevent garbage in platform-specific fields - memset(&r, 0, sizeof(VmemInfo)); - if (!virtual_memory(&r)) { - printf("Aborting\n"); - return; - } - printf(" -- virtual_memory\n"); - printf("Total: %" PRIu64 "\n", r.total); - printf("Available: %" PRIu64 "\n", r.available); - printf("Percent: %.1f\n", r.percent); - printf("Used: %" PRIu64 "\n", r.used); - printf("Free: %" PRIu64 "\n", r.free); - printf("Active: %" PRIu64 "\n", r.active); - printf("Inactive: %" PRIu64 "\n", r.inactive); - printf("Buffers: %" PRIu64 "\n", r.buffers); - printf("Cached: %" PRIu64 "\n", r.cached); - printf("Wired: %" PRIu64 "\n", r.wired); - printf("\n"); -} - -void test_swap() { - SwapMemInfo r; - if (!swap_memory(&r)) { - printf("Aborting\n"); - return; - } - printf(" -- swap_memory\n"); - printf("Total: %" PRIu64 "\n", r.total); - printf("Used: %" PRIu64 "\n", r.used); - printf("Free: %" PRIu64 "\n", r.free); - printf("Percent: %.1f\n", r.percent); - printf("Sin: %" PRIu64 "\n", r.sin); - printf("Sout: %" PRIu64 "\n", r.sout); - printf("\n"); -} - -void test_cpu_times() { - CpuTimes *r; - r = cpu_times(false); - if (!r) { - printf("Aborting\n"); - return; - } - printf(" -- cpu_times\n"); - printf("User: %.1lf;", r->user); - printf(" Nice: %.1lf;", r->nice); - printf(" System: %.1lf;", r->system); - printf(" Idle: %.1lf;", r->idle); - printf(" IOWait: %.1lf;", r->iowait); - printf(" IRQ: %.1lf;", r->irq); - printf(" SoftIRQ: %.1lf;", r->softirq); - printf(" Steal: %.1lf;", r->steal); - printf(" Guest: %.1lf;", r->guest); - printf(" Guest nice: %.1lf\n", r->guest_nice); - printf("\n\n"); - - free(r); -} - -void test_cpu_times_percpu() { - CpuTimes *r, *c; - uint32_t ncpus = cpu_count(true); - c = r = cpu_times(true); - if (!r) { - printf("Aborting\n"); - return; - } - printf(" -- cpu_times_percpu\n"); - for (uint32_t i = 0; i < ncpus; i++) { - printf("CPU %" PRIu32 " :: ", i + 1); - printf(" Usr: %.1lf;", c->user); - printf(" Nice: %.1lf;", c->nice); - printf(" Sys: %.1lf;", c->system); - printf(" Idle: %.1lf;", c->idle); - printf(" IOWait: %.1lf;", c->iowait); - printf(" IRQ: %.1lf;", c->irq); - printf(" SoftIRQ: %.1lf;", c->softirq); - printf(" Steal: %.1lf;", c->steal); - printf(" Guest: %.1lf;", c->guest); - printf(" Guest nice: %.1lf\n", c->guest_nice); - printf("\n"); - c++; - } - printf("\n"); - free(r); -} - -void test_cpu_util_percent() { - CpuTimes *info; - double *utilisation; - info = cpu_times(false); - - if (!info) { - printf("Aborting\n"); - return; - } - - usleep(100000); - utilisation = cpu_util_percent(false, info); - printf(" -- cpu_util_percent\n"); - printf("%.1f\n", *utilisation); - printf("\n"); - - free(utilisation); - free(info); -} - -void test_cpu_util_percent_percpu() { - CpuTimes *info; - double *percentages; - uint32_t ncpus = cpu_count(true); - info = cpu_times(1); - - if (!info) { - printf("Aborting\n"); - return; - } - - usleep(100000); - percentages = cpu_util_percent(1, info); - printf(" -- cpu_util_percent_percpu\n"); - for (uint32_t i = 0; i < ncpus; i++) { - printf("Cpu #%" PRIu32 " : %.1f\n", i, percentages[i]); - } - - printf("\n"); - - free(percentages); - free(info); -} - -void test_cpu_times_percent() { - CpuTimes *info; - CpuTimes *ret; - info = cpu_times(false); - if (!info) { - printf("Aborting\n"); - return; - } - usleep(100000); - ret = cpu_times_percent(false, info); /* Actual percentages since last call */ - if (!ret) { - printf("Error while computing utilisation percentage\n"); - return; - } - printf(" -- cpu_times_percent\n"); - printf("CPU times as percentage of total (0.1 second sample)\n"); - printf("Usr: %.1lf;", ret->user); - printf(" Nice: %.1lf;", ret->nice); - printf(" Sys: %.1lf;", ret->system); - printf(" Idle: %.1lf;", ret->idle); - printf(" IOWait: %.1lf;", ret->iowait); - printf(" IRQ: %.1lf;", ret->irq); - printf(" SoftIRQ: %.1lf;", ret->softirq); - printf(" Steal: %.1lf;", ret->steal); - printf(" Guest: %.1lf;", ret->guest); - printf(" Guest nice: %.1lf\n", ret->guest_nice); - printf("\n"); - free(info); - free(ret); -} - -void test_cpu_times_percent_percpu() { - CpuTimes *info, *last, *r; - uint32_t ncpus = cpu_count(true); - last = cpu_times(true); - if (!last) { - printf("Aborting\n"); - return; - } - usleep(100000); - r = info = - cpu_times_percent(true, last); /* Actual percentages since last call */ - if (!info) { - printf("Error while computing utilisation percentage\n"); - return; - } - - printf(" -- cpu_times_percent_percpu\n"); - printf("CPU times as percentage of total per CPU (0.1 second sample)\n"); - for (uint32_t i = 0; i < ncpus; i++) { - printf("CPU %" PRIu32 " :: ", i + 1); - printf("Usr: %.1lf;", info->user); - printf(" Nice: %.1lf;", info->nice); - printf(" Sys: %.1lf;", info->system); - printf(" Idle: %.1lf;", info->idle); - printf(" IOWait: %.1lf;", info->iowait); - printf(" IRQ: %.1lf;", info->irq); - printf(" SoftIRQ: %.1lf;", info->softirq); - printf(" Steal: %.1lf;", info->steal); - printf(" Guest: %.1lf;", info->guest); - printf(" Guest nice: %.1lf\n", info->guest_nice); - info++; - } - - printf("\n"); - free(r); - free(last); -} - -void test_cpu_count() { - uint32_t logical; - uint32_t physical; - logical = cpu_count(true); - physical = cpu_count(false); - printf(" -- cpu_count \n"); - if (logical == UINT32_MAX || physical == UINT32_MAX) { - printf("Aborting\n"); - return; - } - printf("Logical : %" PRIu32 "\nPhysical : %" PRIu32 "\n", logical, physical); - printf("\n"); -} - -void test_pid_exists() { - pid_t pid = getpid(); - printf(" -- pid_exists \n"); - if (pid_exists(pid)) - printf("pid %" PRId32 " exists\n", pid); - else { - printf("pid %" PRId32 " does not exist\n", pid); - } - printf("\n"); -} - -void test_process() { - pid_t pid = getpid(); - Process *process = get_process(pid); - printf(" -- process \n"); - printf("pid %" PRId32 "\n", process->pid); - printf("ppid %" PRId32 "\n", process->ppid); - printf("name %s\n", process->name); - printf("exe %s\n", process->exe); - printf("cmdline %s\n", process->cmdline); - printf("Real uid %" PRIu32 "\n", process->uid); - printf("Effective uid %" PRIu32 "\n", process->euid); - printf("Saved uid %" PRIu32 "\n", process->suid); - printf("Real gid %" PRIu32 "\n", process->gid); - printf("Effective gid %" PRIu32 "\n", process->egid); - printf("Saved gid %" PRIu32 "\n", process->sgid); - printf("Username %s\n", process->username); - printf("Terminal %s\n", process->terminal); - printf("\n"); - free_process(process); -} - -int main(void) { - test_diskusage(); - test_diskpartitioninfo(); - test_diskiocounters(); - test_netiocounters(); - test_getusers(); - test_boottime(); - test_virtualmeminfo(); - test_swap(); - - test_cpu_times(); - test_cpu_times_percpu(); - - test_cpu_util_percent(); - test_cpu_util_percent_percpu(); - - test_cpu_times_percent(); - test_cpu_times_percent_percpu(); - - test_cpu_count(); - test_pid_exists(); - test_process(); -} +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "pslib.h" + +void test_diskusage() { + DiskUsage du; + printf(" -- disk_usage \n"); +#ifdef _WIN32 + char *disk1 = "C:/"; +#else + char *disk1 = "/"; +#endif + disk_usage(disk1, &du); + printf("%s\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 + "\npercent: %.1f\n\n", disk1, + du.total, du.used, du.free, du.percent); +#ifdef _WIN32 + char *disk2 = "D:/"; +#else + char *disk2 = "/etc"; +#endif + disk_usage(disk2, &du); + printf("%s\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 + "\npercent: %.1f\n\n", disk2, + du.total, du.used, du.free, du.percent); +} + +void test_diskpartitioninfo() { + uint32_t i; + DiskPartitionInfo *phys_dp, *all_dp; + printf(" -- disk_partitions (physical) \n"); + phys_dp = disk_partitions(1); + if (!phys_dp) { + printf("Aborting\n"); + return; + } + printf("Partitions : %" PRIu32 "\n", phys_dp->nitems); + for (i = 0; i < phys_dp->nitems; i++) { + printf("%s %s %s %s\n", phys_dp->partitions[i].device, + phys_dp->partitions[i].mountpoint, phys_dp->partitions[i].fstype, + phys_dp->partitions[i].opts); + } + + free_disk_partition_info(phys_dp); + + printf("\n"); + + printf(" -- disk_partitions (all) \n"); + all_dp = disk_partitions(false); + if (!all_dp) { + printf("Aborting\n"); + return; + } + printf("Partitions : %" PRIu32 "\n", all_dp->nitems); + for (i = 0; i < all_dp->nitems; i++) { + printf("%s %s %s %s\n", all_dp->partitions[i].device, + all_dp->partitions[i].mountpoint, all_dp->partitions[i].fstype, + all_dp->partitions[i].opts); + } + + free_disk_partition_info(all_dp); + printf("\n"); +} + +void test_diskiocounters() { + DiskIOCounterInfo *d; + DiskIOCounters *dp; + d = disk_io_counters(); + if (!d) { + printf("Aborting"); + return; + } + + printf(" -- disk_io_counters \n"); + dp = d->iocounters; + uint32_t i; + for (i = 0; i < d->nitems; i++) { + printf("%s: \tread_count=%" PRIu64 ", write_count=%" PRIu64 ", \n" + "\tread_bytes=%" PRIu64 ", write_bytes=%" PRIu64 ", \n" + "\tread_time=%" PRIu64 ", write_time=%" PRIu64 "\n", + dp->name, dp->reads, dp->writes, dp->readbytes, dp->writebytes, + dp->readtime, dp->writetime); + dp++; + } + free_disk_iocounter_info(d); + printf("\n"); +} + +void test_netiocounters() { + NetIOCounterInfo *n; + NetIOCounters *dp; + uint32_t i; + n = net_io_counters_per_nic(); + dp = n->iocounters; + printf(" -- net_io_counters_per_nic (interface count: %" PRIu32 ")\n", n->nitems); + for (i = 0; i < n->nitems; i++) { + printf("%s: bytes_sent=%" PRIu64 " bytes_rec=%" PRIu64 + " packets_sen=%" PRIu64 " packets_rec=%" PRIu64 " " + "erri=%" PRIu64 " errou=%" PRIu64 " dropi=%" PRIu64 + " dropou=%" PRIu64 " \n", + dp->name, dp->bytes_sent, dp->bytes_recv, dp->packets_sent, + dp->packets_recv, dp->errin, dp->errout, dp->dropin, dp->dropout); + dp++; + } + free_net_iocounter_info(n); + printf("\n"); + n = net_io_counters(); + dp = n->iocounters; + printf(" -- net_io_counters (summed)\n"); + printf("bytes_sent=%" PRIu64 " bytes_rec=%" PRIu64 + " packets_sen=%" PRIu64 " packets_rec=%" PRIu64 " " + "erri=%" PRIu64 " errou=%" PRIu64 " dropi=%" PRIu64 + " dropou=%" PRIu64 " \n", + dp->bytes_sent, dp->bytes_recv, dp->packets_sent, + dp->packets_recv, dp->errin, dp->errout, dp->dropin, dp->dropout); + free_net_iocounter_info(n); + printf("\n"); +} + +void test_getusers() { + UsersInfo *r; + uint32_t i; + printf(" -- users \n"); + r = get_users(); + if (!r) { + printf("Failed \n"); + return; + } + printf("Total: %" PRIu32 "\n", r->nitems); + printf("Name\tTerminal Host\tStarted\n"); + for (i = 0; i < r->nitems; i++) { + printf("%s\t%s\t %s\t%.1f\n", r->users[i].username, r->users[i].tty, + r->users[i].hostname, r->users[i].tstamp); + } + free_users_info(r); + printf("\n"); +} + +void test_boottime() { + uint32_t t = get_boot_time(); + printf(" -- boot_time \n"); + if (t == UINT32_MAX) { + printf("Aborting\n"); + return; + } + printf("%" PRIu32 "\n\n", t); +} + +void test_virtualmeminfo() { + VmemInfo r; + // Empty out to prevent garbage in platform-specific fields + memset(&r, 0, sizeof(VmemInfo)); + if (!virtual_memory(&r)) { + printf("Aborting\n"); + return; + } + printf(" -- virtual_memory\n"); + printf("Total: %" PRIu64 "\n", r.total); + printf("Available: %" PRIu64 "\n", r.available); + printf("Percent: %.1f\n", r.percent); + printf("Used: %" PRIu64 "\n", r.used); +#if (!_WIN32) + printf("Free: %" PRIu64 "\n", r.free); + printf("Active: %" PRIu64 "\n", r.active); + printf("Inactive: %" PRIu64 "\n", r.inactive); + printf("Buffers: %" PRIu64 "\n", r.buffers); + printf("Cached: %" PRIu64 "\n", r.cached); + printf("Wired: %" PRIu64 "\n", r.wired); +#endif + printf("\n"); +} + +void test_swap() { + SwapMemInfo r; + if (!swap_memory(&r)) { + printf("Aborting\n"); + return; + } + printf(" -- swap_memory\n"); + printf("Total: %" PRIu64 "\n", r.total); + printf("Used: %" PRIu64 "\n", r.used); + printf("Free: %" PRIu64 "\n", r.free); + printf("Percent: %.1f\n", r.percent); + printf("Sin: %" PRIu64 "\n", r.sin); + printf("Sout: %" PRIu64 "\n", r.sout); + printf("\n"); +} + +void test_cpu_times() { + CpuTimes *r; + r = cpu_times(false); + if (!r) { + printf("Aborting\n"); + return; + } +#ifdef _WIN32 + printf(" -- cpu_times\n"); + printf("User: %.1lf;", r->user); + printf(" System: %.1lf;", r->system); + printf(" Idle: %.1lf;", r->idle); + printf("Interrupt: %.1lf;", r->interrupt); + printf("DPC: %.1lf;", r->dpc); + printf("\n\n"); +#else + printf(" -- cpu_times\n"); + printf("User: %.1lf;", r->user); + printf(" Nice: %.1lf;", r->nice); + printf(" System: %.1lf;", r->system); + printf(" Idle: %.1lf;", r->idle); + printf(" IOWait: %.1lf;", r->iowait); + printf(" IRQ: %.1lf;", r->irq); + printf(" SoftIRQ: %.1lf;", r->softirq); + printf(" Steal: %.1lf;", r->steal); + printf(" Guest: %.1lf;", r->guest); + printf(" Guest nice: %.1lf\n", r->guest_nice); + printf("\n\n"); +#endif + free(r); +} + +void test_cpu_times_percpu() { + CpuTimes *r, *c; + uint32_t ncpus = cpu_count(true); + c = r = cpu_times(true); + if (!r) { + printf("Aborting\n"); + return; + } + printf(" -- cpu_times_percpu\n"); + for (uint32_t i = 0; i < ncpus; i++) { + printf("CPU %" PRIu32 " :: ", i + 1); +#ifdef _WIN32 + printf("User: %.1lf;", c->user); + printf(" System: %.1lf;", c->system); + printf(" Idle: %.1lf;", c->idle); + printf("Interrupt: %.1lf;", c->interrupt); + printf("DPC: %.1lf;", c->dpc); + printf("\n"); +#else + printf(" Usr: %.1lf;", c->user); + printf(" Nice: %.1lf;", c->nice); + printf(" Sys: %.1lf;", c->system); + printf(" Idle: %.1lf;", c->idle); + printf(" IOWait: %.1lf;", c->iowait); + printf(" IRQ: %.1lf;", c->irq); + printf(" SoftIRQ: %.1lf;", c->softirq); + printf(" Steal: %.1lf;", c->steal); + printf(" Guest: %.1lf;", c->guest); + printf(" Guest nice: %.1lf\n", c->guest_nice); + printf("\n"); +#endif + + + c++; + } + printf("\n"); + free(r); +} +/* +void test_cpu_util_percent() { + CpuTimes *info; + double *utilisation; + info = cpu_times(false); + + if (!info) { + printf("Aborting\n"); + return; + } + + usleep(100000); + utilisation = cpu_util_percent(false, info); + printf(" -- cpu_util_percent\n"); + printf("%.1f\n", *utilisation); + printf("\n"); + + free(utilisation); + free(info); +} + +void test_cpu_util_percent_percpu() { + CpuTimes *info; + double *percentages; + uint32_t ncpus = cpu_count(true); + info = cpu_times(1); + + if (!info) { + printf("Aborting\n"); + return; + } + + #ifdef _WIN32 + Sleep(1000); //time delay + #else + usleep(100000); + #endif + percentages = cpu_util_percent(1, info); + printf(" -- cpu_util_percent_percpu\n"); + for (uint32_t i = 0; i < ncpus; i++) { + printf("Cpu #%" PRIu32 " : %.1f\n", i, percentages[i]); + } + + printf("\n"); + + free(percentages); + free(info); +} +*/ + +void test_cpu_stats() +{ + cpustats *tmp = cpu_stats(); + if (!tmp) + { + printf("Aborting...\n"); + return; + } + printf(" -- Cpu Stats\n"); + printf("Context Switches = %lu \n", tmp->ctx_switches); + printf("Interrupts = %lu \n", tmp->interrupts); + printf("Soft Interrupts = %lu \n", tmp->soft_interrupts); + printf("System Calls = %lu \n", tmp->syscalls); +#ifdef _WIN32 + printf("Dpcs = %lu \n\n", tmp->dpcs); +#endif // _WIN32 + free(tmp); +} +void test_cpu_times_percent() { + CpuTimes *info; + CpuTimes *ret; + info = cpu_times(false); + if (!info) { + printf("Aborting\n"); + return; + } +#ifdef _WIN32 + Sleep(100); //time delay +#else + usleep(100000); +#endif + ret = cpu_times_percent(false, info); /* Actual percentages since last call */ + if (!ret) { + printf("Error while computing utilisation percentage\n"); + return; + } + printf(" -- cpu_times_percent\n"); + printf("CPU times as percentage of total (0.1 second sample)\n"); +#ifdef _WIN32 + printf("User: %.1lf;", ret->user); + printf(" System: %.1lf;", ret->system); + printf(" Idle: %.1lf;", ret->idle); + printf("Interrupt: %.1lf;", ret->interrupt); + printf("DPC: %.1lf;", ret->dpc); + printf("\n"); +#else + printf("Usr: %.1lf;", ret->user); + printf(" Nice: %.1lf;", ret->nice); + printf(" Sys: %.1lf;", ret->system); + printf(" Idle: %.1lf;", ret->idle); + printf(" IOWait: %.1lf;", ret->iowait); + printf(" IRQ: %.1lf;", ret->irq); + printf(" SoftIRQ: %.1lf;", ret->softirq); + printf(" Steal: %.1lf;", ret->steal); + printf(" Guest: %.1lf;", ret->guest); + printf(" Guest nice: %.1lf\n", ret->guest_nice); +#endif + printf("\n"); + free(info); + free(ret); +} + +void test_cpu_times_percent_percpu() { + CpuTimes *info, *last, *r; + uint32_t ncpus = cpu_count(true); + last = cpu_times(true); + + if (!last) { + printf("Aborting\n"); + return; + } +#ifdef _WIN32 + + Sleep(100); //time delay +#else + usleep(100000); +#endif + r = info = + cpu_times_percent(true, last); /* Actual percentages since last call */ + if (!info) { + printf("Error while computing utilisation percentage\n"); + return; + } + + printf(" -- cpu_times_percent_percpu\n"); + printf("CPU times as percentage of total per CPU (0.1 second sample)\n"); + for (uint32_t i = 0; i < ncpus; i++) { + printf("CPU %" PRIu32 " :: ", i + 1); +#ifdef _WIN32 + printf("User: %.1lf;", info->user); + printf(" System: %.1lf;", info->system); + printf(" Idle: %.1lf;", info->idle); + printf("Interrupt: %.1lf;", info->interrupt); + printf("DPC: %.1lf;", info->dpc); + printf("\n"); +#else + printf(" Usr: %.1lf;", info->user); + printf(" Nice: %.1lf;", info->nice); + printf(" Sys: %.1lf;", info->system); + printf(" Idle: %.1lf;", info->idle); + printf(" IOWait: %.1lf;", info->iowait); + printf(" IRQ: %.1lf;", info->irq); + printf(" SoftIRQ: %.1lf;", info->softirq); + printf(" Steal: %.1lf;", info->steal); + printf(" Guest: %.1lf;", info->guest); + printf(" Guest nice: %.1lf\n", info->guest_nice); + printf("\n"); +#endif + info++; + } + + printf("\n"); + free(r); + free(last); +} + +void test_cpu_count() { + uint32_t logical; + uint32_t physical; + logical = cpu_count(true); + physical = cpu_count(false); + printf(" -- cpu_count \n"); + if (logical == UINT32_MAX || physical == UINT32_MAX) { + printf("Aborting\n"); + return; + } + printf("Logical : %" PRIu32 "\nPhysical : %" PRIu32 "\n", logical, physical); + printf("\n"); +} +const char *status_convert(enum proc_status statusid) +{ + switch (statusid) + { + case STATUS_RUNNING: + return "running"; + case STATUS_SLEEPING: + return "sleeping"; + case STATUS_DISK_SLEEP: + return "disk-sleep"; + case STATUS_STOPPED: + return "stopped"; + case STATUS_TRACING_STOP: + return "tracing-stop"; + case STATUS_ZOMBIE: + return "zombie"; + case STATUS_DEAD: + return "dead"; + case STATUS_WAKE_KILL: + return "wake-kill"; + case STATUS_WAKING: + return "waking"; + case STATUS_IDLE: + return "idle"; // FreeBSD, OSX + case STATUS_LOCKED: + return "locked"; // FreeBSD + case STATUS_WAITING: + return "waiting"; // FreeBSD + case STATUS_SUSPENDED: + return "suspended"; // NetBSD + default: + return "UNKNOWN"; + } +} +void test_pid_exists() { + pid_t pid = getpid(); + printf(" -- pid_exists \n"); + if (pid_exists(pid)) + printf("pid %" PRId32 " exists\n", pid); + else { + printf("pid %" PRId32 " does not exist\n", pid); + } + printf("\n"); +} + +void test_process() { + pid_t pid = getpid(); + Process *process = get_process(pid); + printf(" -- process \n"); + if (!process) + printf("Error in getting process info\n"); + printf("pid %" PRId32 "\n", process->pid); + printf("ppid %" PRId32 "\n", process->ppid); + printf("name %s\n", process->name); + printf("exe %s\n", process->exe); + printf("cmdline %s\n", process->cmdline); +#ifdef _WIN32 + printf("number of handles %" PRId32 "\n", process->num_handles); + printf("nice %" PRId32 "\n", process->nice); + printf("status %s\n", status_convert(process->status)); + printf("number of context switches %" PRId32 "\n", process->num_ctx_switches); + printf("number of threads %" PRId32 "\n", process->num_threads); +#else + printf("Real uid %" PRIu32 "\n", process->uid); + printf("Effective uid %" PRIu32 "\n", process->euid); + printf("Saved uid %" PRIu32 "\n", process->suid); + printf("Real gid %" PRIu32 "\n", process->gid); + printf("Effective gid %" PRIu32 "\n", process->egid); + printf("Saved gid %" PRIu32 "\n", process->sgid); + printf("Terminal %s\n", process->terminal); +#endif + printf("Username %s\n", process->username); + printf("\n"); + free_process(process); +} + +int main(void) { + test_diskusage(); + test_diskpartitioninfo(); + test_diskiocounters(); + test_netiocounters(); + test_getusers(); + test_boottime(); + test_virtualmeminfo(); + test_swap(); + + test_cpu_times(); + test_cpu_times_percpu(); + + //test_cpu_util_percent(); + //test_cpu_util_percent_percpu(); + + test_cpu_times_percent(); + test_cpu_times_percent_percpu(); + + test_cpu_count(); + test_cpu_stats(); + + test_pid_exists(); + test_process(); +} diff --git a/pslib.h b/pslib.h index 3b57229..f3f16a9 100644 --- a/pslib.h +++ b/pslib.h @@ -1,12 +1,12 @@ #pragma once +#include #include #include #include -#ifndef pid_t -#define pid_t int +#ifdef _WIN32 + #define pid_t uint32_t #endif - enum proc_status { STATUS_RUNNING, STATUS_SLEEPING, @@ -19,7 +19,8 @@ enum proc_status { STATUS_WAKING, STATUS_IDLE, STATUS_LOCKED, - STATUS_WAITING + STATUS_WAITING, + STATUS_SUSPENDED }; enum ioprio_class { @@ -66,16 +67,17 @@ enum con_status { IDLE, BOUND }; -/* + enum proc_priority { - ABOVE_NORMAL_PRIORITY_CLASS, - BELOW_NORMAL_PRIORITY_CLASS, - HIGH_PRIORITY_CLASS, - IDLE_PRIORITY_CLASS, - NORMAL_PRIORITY_CLASS, - REALTIME_PRIORITY_CLASS + ABOVE_NORMAL_PRIORITY = ABOVE_NORMAL_PRIORITY_CLASS, + BELOW_NORMAL_PRIORITY = BELOW_NORMAL_PRIORITY_CLASS, + HIGH_PRIORITY = HIGH_PRIORITY_CLASS, + IDLE_PRIORITY = IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY = NORMAL_PRIORITY_CLASS, + REALTIME_PRIORITY = REALTIME_PRIORITY_CLASS, + PRIORITY_ERROR }; -*/ + typedef struct { uint64_t total; uint64_t used; @@ -161,21 +163,35 @@ typedef struct { uint64_t sout; } SwapMemInfo; -#if _WIN32 +typedef struct +{ + double user; + double system; + double idle; +#ifdef _WIN32 + double interrupt; + double dpc; #else + double nice; + double iowait; + double irq; + double softirq; + double steal; + double guest; + double guest_nice; +#endif +}CpuTimes; + typedef struct { - double user; - double system; - double idle; - double nice; - double iowait; - double irq; - double softirq; - double steal; - double guest; - double guest_nice; -} CpuTimes; + uint32_t ctx_switches; + uint32_t interrupts; + uint32_t soft_interrupts; + uint32_t syscalls; +#ifdef _WIN32 + uint32_t dpcs; #endif +} cpustats; + typedef struct { pid_t pid; pid_t ppid; @@ -183,14 +199,22 @@ typedef struct { char *exe; char *cmdline; double create_time; - uint32_t uid; +#ifdef _WIN32 + uint32_t num_handles; // num handles only available in windows + enum con_status status;/* TODO : Implement others in this block in linux*/ + enum proc_priority nice; + uint32_t num_ctx_switches; + uint32_t num_threads; +#else + uint32_t uid; // this block is not available on windows uint32_t euid; uint32_t suid; uint32_t gid; uint32_t egid; uint32_t sgid; - char *username; char *terminal; +#endif + char *username; } Process; bool disk_usage(const char[], DiskUsage *); @@ -201,32 +225,38 @@ void free_disk_partition_info(DiskPartitionInfo *); DiskIOCounterInfo *disk_io_counters(void); void free_disk_iocounter_info(DiskIOCounterInfo *); -//NetIOCounterInfo *net_io_counters(void); -//void free_net_iocounter_info(NetIOCounterInfo *); +NetIOCounterInfo *net_io_counters(void); +NetIOCounterInfo *net_io_counters_per_nic(void); +void free_net_iocounter_info(NetIOCounterInfo *); UsersInfo *get_users(void); void free_users_info(UsersInfo *); -//uint32_t get_boot_time(void); +uint32_t get_boot_time(void); -//bool virtual_memory(VmemInfo *); -//bool swap_memory(SwapMemInfo *); +bool virtual_memory(VmemInfo *); +bool swap_memory(SwapMemInfo *); -//CpuTimes *cpu_times(bool); +CpuTimes *cpu_times(bool); -//CpuTimes *cpu_times_percent(bool, CpuTimes *); +CpuTimes *cpu_times_percent(bool, CpuTimes *); //double *cpu_util_percent(bool percpu, CpuTimes *prev_times); +cpustats *cpu_stats(); +uint32_t cpu_count(bool); -//uint32_t cpu_count(bool); +bool pid_exists(pid_t); +uint32_t *pids(uint32_t *); -//bool pid_exists(pid_t); +Process *get_process(pid_t); +void free_process(Process *); -//Process *get_process(pid_t); -//void free_process(Process *); +enum proc_status status(pid_t pid); //faster function for finding status of a process (in Windows) /* Required to avoid [-Wimplicit-function-declaration] for python bindings */ void gcov_flush(void); -// disk_io_counters_per_disk -// net_io_counters_per_nic + + + + diff --git a/pslib_windows.c b/pslib_windows.c index 3366ebe..0eac7af 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -1,22 +1,74 @@ - +#define WIN32_LEAN_AND_MEAN #include #include #include +#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above #include #endif + #include "pslib.h" #include "common.h" #include "pslib_windows.h" -#pragma comment(lib, "IPHLPAPI.lib") + #pragma comment(lib, "WTSAPI32.lib") +#pragma comment(lib, "Advapi32.lib") +#pragma comment(lib, "Shell32.lib") +// Link with Iphlpapi.lib +#pragma comment(lib, "IPHLPAPI.lib") +void __gcov_flush(void){} +//TO get Error message +PCHAR GetError() { + CHAR errormessage[100] = { 0 }; + PCHAR err = NULL; + if (GetLastError() != ERROR_NOSUCHPROCESS) + { + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)errormessage, 255, NULL); + } + else + { + strncpy(errormessage, "NO SUCH PROCESS", 100); + } + err = (PCHAR)calloc(strlen(errormessage) + 1, sizeof(CHAR)); + check_mem(err); + strcpy(err, errormessage); + return err; +error: + return NULL; +} +//used to convert null terminated WCHAR string to char string +char *ConvertWcharToChar(WCHAR buffer[]) +{ + char *tmp = NULL; + int length = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL); + tmp = (char *)calloc(length + 1, sizeof(char)); + check_mem(tmp); + if (WideCharToMultiByte(CP_UTF8, 0, buffer, -1, tmp, length, NULL, NULL) == 0) + { + DWORD t; + GetError(&t); + goto error; + } + return tmp; +error: + if (tmp) + free(tmp); + return NULL; +} DiskIOCounterInfo *disk_io_counters(void) { DISK_PERFORMANCE_WIN_2008 diskPerformance; @@ -36,7 +88,7 @@ DiskIOCounterInfo *disk_io_counters(void) { hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hDevice ==INVALID_HANDLE_VALUE) + if (hDevice == INVALID_HANDLE_VALUE) { continue; } @@ -62,9 +114,7 @@ DiskIOCounterInfo *disk_io_counters(void) { return ret; error: if (ret) - { free_disk_iocounter_info(ret); - } if (hDevice != NULL) CloseHandle(hDevice); return NULL; @@ -183,13 +233,9 @@ DiskPartitionInfo *disk_partitions(bool all) { error: SetErrorMode(old_mode); if (drive_letter) - { free(drive_letter); - } if (ret) - { free_disk_partition_info(ret); - } return NULL; } void free_disk_partition_info(DiskPartitionInfo *p) @@ -215,14 +261,28 @@ bool disk_usage(const char path[], DiskUsage *disk) { disk->free = free.QuadPart; disk->used = disk->total - disk->free; disk->percent = percentage(disk->used, disk->total); - return TRUE; + return true; } else { - return FALSE; + return false; } } - +void free_users_info(UsersInfo *u) +{ + uint32_t i; + for ( i = 0; i < u->nitems; i++) + { + if(u->users[i].hostname) + free(u->users[i].hostname); + if (u->users[i].tty) + free(u->users[i].tty); + if (u->users[i].username) + free(u->users[i].username); + } + free(u->users); + free(u); +} UsersInfo *get_users() { HANDLE hServer = WTS_CURRENT_SERVER_HANDLE; WCHAR *buffer_user = NULL; @@ -235,18 +295,13 @@ UsersInfo *get_users() { PWTS_CLIENT_ADDRESS address; char address_str[50]; long long unix_time; - char *tmp; + char *tmp = NULL; PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; WINSTATION_INFO station_info; HINSTANCE hInstWinSta = NULL; ULONG returnLen; - LPBOOL q = NULL; UsersInfo *users_info_ptr = NULL; - /*PyObject *py_retlist = PyList_New(0); - PyObject *py_tuple = NULL; - PyObject *py_address = NULL; - PyObject *py_username = NULL;*/ hInstWinSta = LoadLibraryA("winsta.dll"); WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) \ GetProcAddress(hInstWinSta, "WinStationQueryInformationW"); @@ -256,11 +311,8 @@ UsersInfo *get_users() { "error in retrieving list of sessions on a Remote Desktop Session Host server"); users_info_ptr->users = (Users *)calloc(count, sizeof(Users)); check_mem(users_info_ptr->users); - //users_info_ptr->nitems = 0; users_info_ptr->nitems = 0; for (i = 0; i < count; i++) { - //py_address = NULL; - //py_tuple = NULL; sessionId = sessions[i].SessionId; if (buffer_user != NULL) WTSFreeMemory(buffer_user); @@ -310,17 +362,8 @@ UsersInfo *get_users() { unix_time += \ station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; unix_time /= 10000000; - tmp = (char *)calloc(USERNAME_LENGTH, sizeof(char)); - check_mem(tmp); - if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, buffer_user, -1, tmp, USERNAME_LENGTH, "", q) == 0) - { - DWORD t; - t = GetLastError(); - check(t != ERROR_INSUFFICIENT_BUFFER, "Supplied buffer size was not large enough, or it was incorrectly set to NULL."); - check(t != ERROR_INVALID_FLAGS, "The values supplied for flags were not valid."); - check(t != ERROR_INVALID_PARAMETER, "Any of the parameter values was invalid"); - check(t != ERROR_NO_UNICODE_TRANSLATION, "Invalid Unicode was found in a string."); - } + tmp = ConvertWcharToChar(buffer_user); + check(tmp, "Error in converting wchar"); users_info_ptr->users[users_info_ptr->nitems].username = tmp; users_info_ptr->users[users_info_ptr->nitems].tstamp = (float)unix_time; users_info_ptr->users[users_info_ptr->nitems].tty = NULL; @@ -347,21 +390,6 @@ UsersInfo *get_users() { free(tmp); return NULL; } -void free_users_info(UsersInfo *u) -{ - uint32_t i; - for ( i = 0; i < u->nitems; i++) - { - if(u->users[i].hostname) - free(u->users[i].hostname); - if (u->users[i].tty) - free(u->users[i].tty); - if (u->users[i].username) - free(u->users[i].username); - } - free(u->users); - free(u); -} double get_valid_value(double a) { @@ -377,14 +405,12 @@ CpuTimes *calculate(CpuTimes *t1, CpuTimes * t2) double all_delta; int i; CpuTimes *ret; - ret = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + ret = (CpuTimes *)calloc(1,sizeof(CpuTimes)); check_mem(ret); all_delta = (t2->user + t2->system + t2->interrupt + t2->idle + t2->dpc) - \ (t1->user + t1->system + t1->interrupt + t1->idle + t1->dpc); - if (all_delta == 0) - { + if (all_delta==0) all_delta = 100; - } ret->user = get_valid_value((t2->user - t1->user)*100.0 / all_delta); ret->system = get_valid_value((t2->system - t1->system)*100.0 / all_delta); ret->interrupt = get_valid_value((t2->interrupt - t1->interrupt)*100.0 / all_delta); @@ -392,66 +418,11 @@ CpuTimes *calculate(CpuTimes *t1, CpuTimes * t2) ret->dpc = get_valid_value((t2->dpc - t1->dpc)*100.0 / all_delta); return ret; error: - if (ret) - { - free(ret); - } - return NULL; -} - -/*"""Same as cpu_percent() but provides utilization percentages -for each specific CPU time as is returned by cpu_times(). - -*interval* and *percpu* arguments have the same meaning as in -cpu_percent(). -"""*/ - -CpuTimes *cpu_times_percent(bool percpu, CpuTimes * Last_Cpu_times) -{ - uint32_t no_cpu, i; - CpuTimes *t2 = NULL, *ret = NULL, *tmp = NULL; - t2 = (CpuTimes *)calloc(1, sizeof(CpuTimes)); - check_mem(t2); - if (!percpu) { - t2 = cpu_times(false); - ret = calculate(t2, Last_Cpu_times); - } - - // # per - cpu usage - else { - ret = (CpuTimes *)calloc(1, sizeof(CpuTimes)); - check_mem(ret); - t2 = cpu_times(true); - - no_cpu = cpu_count(true); - //t2, t2 in zip(tot2, _last_per_cpu_times_2) : - for (i = 0; i < no_cpu; i++) - { - ret = (CpuTimes *)realloc(ret, (i + 1) * sizeof(CpuTimes)); - check_mem(ret); - tmp = calculate(&t2[i], &Last_Cpu_times[i]); - check(tmp, "Error in calculting difference"); - ret[i].user = tmp->user; - ret[i].system = tmp->system; - ret[i].interrupt = tmp->interrupt; - ret[i].idle = tmp->idle; - ret[i].dpc = tmp->dpc; - free(tmp); - } - - } - return ret; -error: - if (tmp) - free(tmp); - if (t2) - free(t2); if (ret) free(ret); return NULL; } - bool swap_memory(SwapMemInfo *ret) { MEMORYSTATUSEX memInfo; @@ -469,7 +440,7 @@ bool swap_memory(SwapMemInfo *ret) return true; } -bool virtual_memory(VirtMemInfo *ret) +bool virtual_memory(VmemInfo *ret) { MEMORYSTATUSEX memInfo; memInfo.dwLength = sizeof(MEMORYSTATUSEX); @@ -478,8 +449,8 @@ bool virtual_memory(VirtMemInfo *ret) return false; ret->total = memInfo.ullTotalPhys; - ret->avail = memInfo.ullAvailPhys; - ret->used = ret->total - ret->avail; + ret->available = memInfo.ullAvailPhys; + ret->used = ret->total - ret->available; ret->percent = (ret->used)*100.0/ret->total; return true; } @@ -516,9 +487,8 @@ unsigned int cpu_count_phys() { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if (buffer) free(buffer); - buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( - length); - check(buffer,""); + buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)calloc(length, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); + check_mem(buffer); } else { goto error; @@ -703,7 +673,7 @@ CpuTimes *cpu_times_summed() float idle, kernel, user, system; FILETIME idle_time, kernel_time, user_time; - check(GetSystemTimes(&idle_time, &kernel_time, &user_time),"") + check(GetSystemTimes(&idle_time, &kernel_time, &user_time), "failed to get System times"); idle = (float)((HI_T * idle_time.dwHighDateTime) + \ (LO_T * idle_time.dwLowDateTime)); @@ -716,15 +686,16 @@ CpuTimes *cpu_times_summed() // We return only busy kernel time subtracting idle time from // kernel time. system = (kernel - idle); - CpuTimes *data = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + CpuTimes *data = NULL, *percpu = NULL, *percpu_summed = NULL;; + data = (CpuTimes*)calloc(1,sizeof(CpuTimes)); check_mem(data); data->idle=idle; data->system=system; data->user=user; - CpuTimes *percpu = per_cpu_times(); + percpu = per_cpu_times(); check_mem(percpu); - CpuTimes *percpu_summed = sum_per_cpu_times(percpu); + percpu_summed = sum_per_cpu_times(percpu); check_mem(percpu_summed); free(percpu); data->interrupt = percpu_summed->interrupt; @@ -732,6 +703,12 @@ CpuTimes *cpu_times_summed() free(percpu_summed); return data; error: + if (data) + free(data); + if (percpu) + free(percpu); + if (percpu_summed) + free(percpu_summed); return NULL; } CpuTimes *cpu_times(bool percpu) @@ -743,11 +720,9 @@ CpuTimes *cpu_times(bool percpu) } else return per_cpu_times(); - - } -CpuStats *cpu_stats() { +cpustats *cpu_stats() { // NtQuerySystemInformation stuff typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; @@ -788,9 +763,7 @@ CpuStats *cpu_stats() { check(status==0,""); // get DPCs - InterruptInformation = \ - malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) * - si.dwNumberOfProcessors); + InterruptInformation = (_SYSTEM_INTERRUPT_INFORMATION *)calloc(si.dwNumberOfProcessors, sizeof(_SYSTEM_INTERRUPT_INFORMATION)); check_mem(InterruptInformation); status = NtQuerySystemInformation( @@ -830,7 +803,7 @@ CpuStats *cpu_stats() { FreeLibrary(hNtDll); - CpuStats *ret = (CpuStats*)calloc(1,sizeof(CpuStats)); + cpustats *ret = (cpustats*)calloc(1,sizeof(cpustats)); check_mem(ret); ret->ctx_switches = spi->ContextSwitches; ret->interrupts = interrupts; @@ -852,8 +825,51 @@ CpuStats *cpu_stats() { FreeLibrary(hNtDll); return NULL; } +/*Same as cpu_percent() but provides utilization percentages + for each specific CPU time as is returned by cpu_times().*/ +CpuTimes *cpu_times_percent(bool percpu , CpuTimes * Last_Cpu_times) +{ + uint32_t no_cpu, i; + CpuTimes *t2 = NULL, *ret = NULL, *tmp = NULL; + t2 = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + check_mem(t2); + if (!percpu) { + t2 = cpu_times(false); + ret = calculate(t2, Last_Cpu_times); + } +// per - cpu usage + else { + ret = (CpuTimes *)calloc(1, sizeof(CpuTimes)); + check_mem(ret); + t2 = cpu_times(true); + + no_cpu = cpu_count(true); + for (i = 0; i < no_cpu; i++) + { + ret = (CpuTimes *)realloc(ret, (i + 1) * sizeof(CpuTimes)); + check_mem(ret); + tmp = calculate(&t2[i], &Last_Cpu_times[i]); + check(tmp, "Error in calculting difference"); + ret[i].user = tmp->user; + ret[i].system = tmp->system; + ret[i].interrupt = tmp->interrupt; + ret[i].idle = tmp->idle; + ret[i].dpc = tmp->dpc; + free(tmp); + } + } + return ret; +error: + if (tmp) + free(tmp); + if (t2) + free(t2); + if (ret) + free(ret); + return NULL; +} -uint32_t *pids(DWORD *numberOfReturnedPIDs) { +uint32_t *pids(uint32_t *numberOfReturnedPIDs) { DWORD *procArray = NULL; @@ -867,7 +883,7 @@ uint32_t *pids(DWORD *numberOfReturnedPIDs) { procArraySz += 1024; free(procArray); procArrayByteSz = procArraySz * sizeof(DWORD); - procArray = malloc(procArrayByteSz); + procArray = (DWORD *)calloc(1, procArrayByteSz); check_mem(procArray); @@ -910,9 +926,7 @@ int pid_is_running(DWORD pid) { CloseHandle(hProcess); return 1; } - CloseHandle(hProcess); - //PyErr_SetFromWindowsErr(0); return -1; } @@ -927,20 +941,16 @@ int pid_is_running(DWORD pid) { CloseHandle(hProcess); return 1; } - - //PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return -1; } -bool pid_exists(long pid) +bool pid_exists(pid_t pid) { int status; - status = pid_is_running(pid); - check(status!=-1,"Exception raised in pid_is_running"); - return status; + return status; error: return false; } @@ -955,10 +965,7 @@ PIP_ADAPTER_ADDRESSES get_nic_addresses() { do { pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); - if (pAddresses == NULL) { - //PyErr_NoMemory(); - return NULL; - } + check_mem(pAddresses); dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { @@ -972,12 +979,12 @@ PIP_ADAPTER_ADDRESSES get_nic_addresses() { attempts++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); - if (dwRetVal != NO_ERROR) { - //PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() syscall failed."); - return NULL; - } - + check(dwRetVal == NO_ERROR, "GetAdaptersAddresses() syscall failed."); return pAddresses; +error: + if (pAddresses) + free(pAddresses); + return NULL; } @@ -993,29 +1000,21 @@ NetIOCounterInfo *net_io_counters_per_nic() PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; - //PyObject *py_retdict = PyDict_New(); - ///PyObject *py_nic_info = NULL; - //PyObject *py_nic_name = NULL; - - //if (py_retdict == NULL) - // return NULL; pAddresses = get_nic_addresses(); if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; - - - NetIOCounterInfo *ret = (NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); - NetIOCounters *counters = (NetIOCounters*) calloc(15,sizeof(NetIOCounters)); - NetIOCounters *nc = counters; - //check_mem(counters); - //check_mem(ret); + NetIOCounterInfo *ret = NULL; + NetIOCounters *counters = NULL, *nc = NULL; + ret = (NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + check_mem(ret); + counters = (NetIOCounters*) calloc(15,sizeof(NetIOCounters)); + check_mem(counters); + nc = counters; ret->nitems = 0; ret->iocounters = counters; while (pCurrAddresses) { - //py_nic_name = NULL; - //py_nic_info = NULL; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2)); @@ -1023,10 +1022,7 @@ NetIOCounterInfo *net_io_counters_per_nic() pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); #endif - if (pIfRow == NULL) { - //PyErr_NoMemory(); - goto error; - } + check_mem(pIfRow) #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2)); @@ -1037,10 +1033,7 @@ NetIOCounterInfo *net_io_counters_per_nic() dwRetVal = GetIfEntry(pIfRow); #endif - if (dwRetVal != NO_ERROR) { - //PyErr_SetString(PyExc_RuntimeError,"GetIfEntry() or GetIfEntry2() syscalls failed."); - goto error; - } + check(dwRetVal == NO_ERROR, "GetIfEntry() or GetIfEntry2() syscalls failed."); #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above @@ -1067,27 +1060,13 @@ NetIOCounterInfo *net_io_counters_per_nic() #endif nc->name = (char *)calloc(wcslen(pCurrAddresses->FriendlyName) + 1, sizeof(char)); - LPBOOL q = NULL; - int len; - len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName), nc->name, wcslen(pCurrAddresses->FriendlyName), "", q); + int len = wcslen(pCurrAddresses->FriendlyName); pCurrAddresses->FriendlyName[len] = '\0'; - if ( len == 0) - { - DWORD t; - t = GetLastError(); - //check(t != ERROR_INSUFFICIENT_BUFFER, "Supplied buffer size was not large enough, or it was incorrectly set to NULL."); - //check(t != ERROR_INVALID_FLAGS, "The values supplied for flags were not valid."); - //check(t != ERROR_INVALID_PARAMETER, "Any of the parameter values was invalid"); - //check(t != ERROR_NO_UNICODE_TRANSLATION, "Invalid Unicode was found in a string."); - } - + nc->name = ConvertWcharToChar(pCurrAddresses->FriendlyName); ret->nitems++; nc++; - - - - free(pIfRow); - pCurrAddresses = pCurrAddresses->Next; + free(pIfRow); + pCurrAddresses = pCurrAddresses->Next; } free(pAddresses); @@ -1102,7 +1081,7 @@ NetIOCounterInfo *net_io_counters_per_nic() free(ret); return NULL; } -void free_netiocounterinfo(NetIOCounterInfo *ret) +void free_net_iocounter_info(NetIOCounterInfo *ret) { int i; NetIOCounters *c=ret->iocounters; @@ -1118,14 +1097,12 @@ void free_netiocounterinfo(NetIOCounterInfo *ret) NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) { NetIOCounterInfo *sum=(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + check_mem(sum); NetIOCounters *r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); - check(sum); - check(r); - sum->iocounters=r; - sum->nitems=1; - + check_mem(r); + sum->iocounters = r; + sum->nitems = 1; int i; - NetIOCounters *c=info->iocounters; for(i=0;initems;++i) { @@ -1139,175 +1116,739 @@ NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) r->packets_sent+=c->packets_sent; ++c; } - free_netiocounterinfo(info); + free_net_iocounter_info(info); return sum; +error: + if(sum) + free(sum); + if(r) + free(r); + return info; } -NetIOCounterInfo *net_io_counters(bool per_nic) +NetIOCounterInfo *net_io_counters() { NetIOCounterInfo *ret = net_io_counters_per_nic(); - if(per_nic) - return ret; - else - return net_io_counters_summed(ret); + return net_io_counters_summed(ret); } -/* -void test_netiocounters() -{ - NetIOCounterInfo *c = net_io_counters(true); - NetIOCounters *r = c->iocounters; - - if(!c) - { - printf("Aborting..\n"); - return; - } - int i=0; - printf("__________NET IO COUNTERS_________\n"); - for(i=0;initems;++i) - { - printf("%s:\n",r->name); - printf("\tBytes Sent : %" PRIu64"\n",r->bytes_sent); - printf("\tBytes Received : %"PRIu64"\n",r->bytes_recv); - printf("\tPackets Sent : %"PRIu64"\n",r->packets_sent); - printf("\tPackets Received : %" PRIu64"\n",r->packets_recv); - printf("\tIn Errors : %" PRIu64"\n",r->errin); - printf("\tOut Errors : %" PRIu64"\n",r->errout); - printf("\tIn Discards : %" PRIu64"\n",r->dropin); - printf("\tOut Discards : %" PRIu64"\n",r->dropout); - ++r; - } - free_netiocounterinfo(c); - +pid_parent_map *ppid_map() { + HANDLE handle = NULL; + PROCESSENTRY32 pe = { 0 }; + pid_parent_map *ret = NULL; + ret = (pid_parent_map *)calloc(1, sizeof(pid_parent_map)); + check_mem(ret); + ret->pid = (pid_t *)calloc(1, sizeof(pid_t)); + check_mem(ret->pid); + ret->ppid = (pid_t *)calloc(1, sizeof(pid_t)); + check_mem(ret->ppid); + pe.dwSize = sizeof(PROCESSENTRY32); + handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + check(handle, "Error in creating handle"); + ret->nitems = 0; + if (Process32First(handle, &pe)) { + do { + ret->pid = (pid_t *)realloc(ret->pid, (ret->nitems + 1) * sizeof(pid_t)); + check_mem(ret->pid); + ret->ppid = (pid_t *)realloc(ret->ppid, (ret->nitems + 1) * sizeof(pid_t)); + check_mem(ret->ppid); + ret->pid[ret->nitems] = pe.th32ProcessID; + ret->ppid[ret->nitems] = pe.th32ParentProcessID; + ret->nitems++; + } while (Process32Next(handle, &pe)); + } + CloseHandle(handle); + return ret; +error: + if (ret) + free(ret); + if (handle) + CloseHandle(handle); + return NULL; } -void test_virtual_memory() +pid_t ppid(pid_t pid) { - VirtMemInfo virt; - if(!virtual_memory(&virt)) + pid_parent_map *map = NULL; + uint32_t i; + pid_t ret = -1; + map = ppid_map(); + check(map,"Error in retriving ppid_map"); + for ( i = 0; i < map->nitems; i++) { - printf("Aborting\n"); - return; + if (map->pid[i] == pid) + { + ret = map->ppid[i]; + break; + } } - printf("_______Virtual Memory_______\n"); - printf("Total=%lld, Used=%lld, Free=%lld, Percent=%f\n\n",virt.total,virt.used, virt.avail,virt.percent); + check(i != map->nitems, "pid not found in the list of running process"); + free(map); + return ret; +error: + if (map) + free(map); + return -1; } -void test_swap_memory() +TCHAR *convert_dos_path(TCHAR * path) { - SwapMemInfo swap; - if(!swap_memory(&swap)) + TCHAR *tmp = NULL; + PTCHAR split[10]; + uint16_t i = 2; + size_t size = 1; + LPCTSTR lpDevicePath; + TCHAR d = TEXT('A'), delimiter[5] = {TEXT("\\")}; + TCHAR szBuff[5]; + TCHAR driveletter[10],tmpdevice[100]; + TCHAR rawdrive[100]; + PTCHAR ret = NULL, devicepath = NULL; + devicepath = (PTCHAR)calloc(1, sizeof(TCHAR)); + tmp = _tcstok(path, TEXT("\\")); + split[0] = tmp; + tmp = _tcstok(NULL, TEXT("\\")); + split[1] = tmp; + while (tmp) { - printf("Aborting\n"); - return; + tmp = _tcstok(NULL, TEXT("\\")); + split[i++] = tmp; + if(tmp) + { + size += (_tcslen(tmp) + 1); + devicepath = (PTCHAR)realloc(devicepath, size * sizeof(TCHAR)); + _tcscat(devicepath, delimiter); + _tcscat(devicepath, tmp); + } + } + check(_stprintf(rawdrive,_T("\\%hs\\%hs"), split[0], split[1]),"unable to join splited path"); + while (d <= TEXT('Z')) { + TCHAR szDeviceName[3] = { d, TEXT(':'), TEXT('\0') }; + TCHAR szTarget[512] = { 0 }; + if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) { + if (_tcscmp(rawdrive, szTarget) == 0) { + _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d); + _tcscpy(driveletter, szBuff); + break; + } + } + d++; } - printf("________Swap Memory________\n"); - printf("Total=%llu, Used=%llu, Free=%llu, Percent=%f, sin=%llu, sout=%llu\n\n",swap.total,swap.used, swap.free,swap.percent,swap.sin,swap.sout); - - + ret = (TCHAR *)calloc(100, sizeof(TCHAR)); + check_mem(ret); + check(_stprintf(ret,TEXT("%hs%hs"), driveletter,devicepath), "unable to join driveletter and rawdrive"); + return ret; +error: + if (ret) + free(ret); + return NULL; } -void test_pids() -{ - DWORD numberOfPIDs; - DWORD *pid = pids(&numberOfPIDs); - DWORD *c=pid; +int +pid_in_pids(DWORD pid) { + DWORD *proclist = NULL; + DWORD numberOfReturnedPIDs; DWORD i; - if(!pid) + + proclist = pids(&numberOfReturnedPIDs); + if (proclist == NULL) + return -1; + for (i = 0; i < numberOfReturnedPIDs; i++) { + if (proclist[i] == pid) { + free(proclist); + return 1; + } + } + free(proclist); + return 0; +} + +int is_phandle_running(HANDLE hProcess, DWORD pid) { + DWORD processExitCode = 0; + LPTSTR err = NULL; + if (hProcess == NULL) { + if (GetLastError() == ERROR_INVALID_PARAMETER) { + SetLastError(ERROR_NOSUCHPROCESS); + return 0; + } + err = GetError(); + if (GetLastError() != ERROR_ACCESS_DENIED) + log_err("%s", err); + LocalFree(err); + return -1; + } + + if (GetExitCodeProcess(hProcess, &processExitCode)) { + // XXX - maybe STILL_ACTIVE is not fully reliable as per: + // http://stackoverflow.com/questions/1591342/#comment47830782_1591379 + if (processExitCode == STILL_ACTIVE) { + return 1; + } + else { + // We can't be sure so we look into pids. + if (pid_in_pids(pid) == 1) { + + return 1; + } + else { + CloseHandle(hProcess); + return 0; + } + } + } + log_err("GetExitCodeProcess Failed"); + CloseHandle(hProcess); + err = GetError(); + if(GetLastError() != ERROR_ACCESS_DENIED) + log_err("%s", err); + LocalFree(err); + return -1; +} + +HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { + HANDLE hProcess; + LPTSTR err = NULL; + if (pid == 0) // otherwise we'd get NoSuchProcess + { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); + int ret = is_phandle_running(hProcess, pid); + if (ret == 1) + return hProcess; + else if(ret == 0) { - printf("Aborting...\n"); - return; + err = GetError(); + SetLastError(ERROR_NOSUCHPROCESS); + goto error; } - printf("__________PIDs_________\n"); - for(i=0;ictx_switches); - printf("Interrupts = %lu \n", tmp->interrupts); - printf("Soft Interrupts = %lu \n", tmp->soft_interrupts); - printf("System Calls = %lu \n", tmp->syscalls); - printf("Dpcs = %lu \n\n", tmp->dpcs); - free(tmp); -} -void test_cputimes() -{ - CpuTimes * data = cpu_times(false); - if(!data) + pid_running = pid_is_running(pid); + if ((pid_running == -1) || (pid_running == 0)) { - printf("Aborting..\n"); - return; + SetLastError(ERROR_NOSUCHPROCESS); + return NULL; } - printf("_________CPU Times_________\n"); - printf("User=%f, Idle=%f, System=%f, Interrupt=%f, Dpc=%f\n\n",data->user,data->idle,data->system,data->interrupt,data->dpc); - free(data); + hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ); + if (hProcess == NULL) + return NULL; + NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress( + GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); + + NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL); + pebAddress = pbi.PebBaseAddress; + // get the address of ProcessParameters +#ifdef _WIN64 + check(ReadProcessMemory(hProcess, (PCHAR)pebAddress + 32, + &rtlUserProcParamsAddress, sizeof(PVOID), NULL), "Could not read the address of ProcessParameters!\n"); +#else + check(ReadProcessMemory(hProcess, (PCHAR)pebAddress + 0x10, + &rtlUserProcParamsAddress, sizeof(PVOID), NULL), "Could not read the address of ProcessParameters!\n"); +#endif + // read the CommandLine UNICODE_STRING structure +#ifdef _WIN64 + check(ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 112, + &commandLine, sizeof(commandLine), NULL), "Could not to read Command Line Unicode Structure"); +#else + check(ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x40, + &commandLine, sizeof(commandLine), NULL), "Could not read Command Line Unicode Structure"); +#endif + // allocate memory to hold the command line + commandLineContents = (WCHAR *)malloc(commandLine.Length + 1); + check_mem(commandLineContents); + + // read the command line + check(ReadProcessMemory(hProcess, commandLine.Buffer, + commandLineContents, commandLine.Length, NULL), "Failed to read the commandline"); + + // Null-terminate the string to prevent wcslen from returning + // incorrect length the length specifier is in characters, but + // commandLine.Length is in bytes. + commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0'; + ret = ConvertWcharToChar(commandLineContents); + /* TODO : attempt to parse the command line using Win32 API and return list of commandline args*/ + free(commandLineContents); + CloseHandle(hProcess); + return ret; +error: + err = GetError(); log_err("%s", err); LocalFree(err); + return NULL; } -void test_percputimes() -{ - CpuTimes * r = cpu_times(true); - if(!r) + + +char *exe(pid_t pid) { + HANDLE hProcess; + TCHAR *tmp; + WCHAR tmpexe[MAX_PATH]; + TCHAR exe[MAX_PATH]; + LPTSTR err = NULL; + char *ret = NULL; + if (pid == 0 || pid == 4) { - printf("Aborting..\n"); - return; + SetLastError(ERROR_ACCESS_DENIED); + goto error; } - printf("_______CPU Times_Per CPU_______\n"); - CpuTimes * c=r; - UINT i; - for(i=0;iuser,c->idle,c->system,c->interrupt,c->dpc); - ++c; + hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); + check(hProcess, "NULL HANDLE"); + check(GetProcessImageFileName(hProcess, exe, MAX_PATH), "Unable to get process image file name"); + CloseHandle(hProcess); } - printf("\n"); - free(r); + tmp = convert_dos_path(exe); + _swprintf(tmpexe,L"%hs",tmp); + ret = ConvertWcharToChar(tmpexe); + return ret; +error: + err = GetError(); + log_err("%s", err); + LocalFree(err);; + if(hProcess) + CloseHandle(hProcess); + return NULL; } -void test_boottime() +char *name(pid_t pid) { - uint32_t time = get_boot_time(); - printf("_________Boot Time_________\n"); - printf("%"PRIu32"\n\n", time); + /*"""Return process name, which on Windows is always the final + part of the executable. + """*/ + // This is how PIDs 0 and 4 are always represented in taskmgr + // and process - hacker. + char *ret = NULL; + TCHAR tmpret[_MAX_FNAME]; + HANDLE hProcess = NULL; + bool fail = true; + PROCESSENTRY32W pentry; + HANDLE hSnapShot = INVALID_HANDLE_VALUE; + ret = (char *)calloc(50, sizeof(char)); + check_mem(ret); + if (pid == 0) + strcpy(ret, "System Idle Process"); + else if (pid == 4) + strcpy(ret, "System"); + else + { + free(ret); + ret = NULL; + // Note : this will fail with AD for most PIDs owned + // by another user but it's faster. + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (!hProcess) + { + HMODULE hMod; + DWORD cbNeeded; + if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), + &cbNeeded)) + { + if (GetModuleBaseName(hProcess, hMod, tmpret, + sizeof(tmpret) / sizeof(TCHAR))) + { + fail = false; + ret = ConvertWcharToChar((WCHAR *)tmpret); + check(ret, "Converting WCHAR failed"); + } + } + } + if(fail) + { + int ok; + hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); + check(hSnapShot != INVALID_HANDLE_VALUE,"Error in creating HANDLE") + pentry.dwSize = sizeof(PROCESSENTRY32W); + ok = Process32FirstW(hSnapShot, &pentry); + check(ok, "Error in retrieving information about the first process encountered in a system snapshot."); + while (ok) { + if (pentry.th32ProcessID == pid) { + ret = ConvertWcharToChar(pentry.szExeFile); + check(ret, "Converting WCHAR failed"); + fail = false; + break; + } + ok = Process32NextW(hSnapShot, &pentry); + } + CloseHandle(hSnapShot); + } + if (fail) + { + SetLastError(ERROR_NOSUCHPROCESS); + goto error; + } + } + return ret; +error: + if (hSnapShot) + CloseHandle(hSnapShot); + if (hProcess) + CloseHandle(hProcess); + if (ret) + free(ret); + return NULL; } -void test_pid_exists() +/* +* Return process username as a "DOMAIN//USERNAME" string. +*/ +char * Username(pid_t pid) { - long pid=0;int i =0; - printf("_________PID Exists_________\n"); - - for (pid=rand()%22000,i=0;i<20;++i,pid=rand()%22000) + HANDLE processHandle = NULL; + HANDLE tokenHandle = NULL; + PTOKEN_USER user = NULL; + ULONG bufferSize; + WCHAR *name = NULL; + WCHAR *domainName = NULL; + ULONG nameSize; + ULONG domainNameSize; + SID_NAME_USE nameUse; + LPTSTR err = NULL; + // resolve the SID to a name + nameSize = 0x100; + domainNameSize = 0x100; + // Get the user SID. + bufferSize = 0x100; + + char *ret = NULL; + ret = (char *)calloc(50, sizeof(char)); + if (pid == 0 || pid == 4) + strcpy(ret, "NT AUTHORITY\\SYSTEM"); + else { - int x =0; - x = pid_exists(pid); - printf("%ld - %s \n",pid,x?"true":"false"); - + processHandle = handle_from_pid_waccess( + pid, PROCESS_QUERY_INFORMATION); + check(processHandle, "Error in getting Handle from pid "); + check(OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle), "Error in Opening Process Token"); + CloseHandle(processHandle); + processHandle = NULL; + // Get the user SID. + while (1) { + user = malloc(bufferSize); + check_mem(user); + if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, + &bufferSize)) + { + check((GetLastError() == ERROR_INSUFFICIENT_BUFFER),"Error in retriving TokenUser using GetTokenInformation "); + free(user); + continue; + } + break; + } + CloseHandle(tokenHandle); + tokenHandle = NULL; + // resolve the SID to a name + while (1) { + name = malloc(nameSize * sizeof(WCHAR)); + check_mem(name); + domainName = malloc(domainNameSize * sizeof(WCHAR)); + check_mem(domainName); + if (!LookupAccountSidW(NULL, user->User.Sid, name, &nameSize, + domainName, &domainNameSize, &nameUse)) + { + check((GetLastError() == ERROR_INSUFFICIENT_BUFFER), "Error in getting name from SID"); + free(name); + free(domainName); + continue; + } + break; + } + ret = (char *)realloc(ret, (wcslen(domainName) + wcslen(name) + 5) * sizeof(char)); + sprintf(ret, "%s\\%s", ConvertWcharToChar(domainName), ConvertWcharToChar(name)); + } + return ret; +error: + err = GetError(); + log_err("%s", err); + LocalFree(err);; + if (processHandle != NULL) + CloseHandle(processHandle); + if (tokenHandle != NULL) + CloseHandle(tokenHandle); + if (name != NULL) + free(name); + if (domainName != NULL) + free(domainName); + if (user != NULL) + free(user); + return NULL; +} +int +get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, + PVOID *retBuffer) { + static ULONG initialBufferSize = 0x4000; + NTSTATUS status; + PVOID buffer; + ULONG bufferSize; + PSYSTEM_PROCESS_INFORMATION process; + + // get NtQuerySystemInformation + typedef DWORD(_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); + NTQSI_PROC NtQuerySystemInformation; + HINSTANCE hNtDll; + hNtDll = LoadLibrary(TEXT("ntdll.dll")); + NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( + hNtDll, "NtQuerySystemInformation"); + + bufferSize = initialBufferSize; + buffer = malloc(bufferSize); + check_mem(buffer); + + while (TRUE) { + status = NtQuerySystemInformation(SystemProcessInformation, buffer, + bufferSize, &bufferSize); + + if (status == STATUS_BUFFER_TOO_SMALL || + status == STATUS_INFO_LENGTH_MISMATCH) + { + free(buffer); + buffer = malloc(bufferSize); + check_mem(buffer); + + } + else { + break; + } + } + + check((status == 0),"NtQuerySystemInformation() syscall failed"); + + if (bufferSize <= 0x20000) + initialBufferSize = bufferSize; + + process = PSUTIL_FIRST_PROCESS(buffer); + do { + if (process->UniqueProcessId == (HANDLE)pid) { + *retProcess = process; + *retBuffer = buffer; + return 1; + } + } while ((process = PSUTIL_NEXT_PROCESS(process))); + + SetLastError(ERROR_NOSUCHPROCESS); + goto error; + +error: + FreeLibrary(hNtDll); + if (buffer != NULL) + free(buffer); + return 0; +} + +enum proc_status status(pid_t pid) { + ULONG i; + bool suspended = true; + PSYSTEM_PROCESS_INFORMATION process; + PVOID buffer; + LPTSTR err = NULL; + check(get_proc_info(pid, &process, &buffer), "Cannot get Process Info"); + for (i = 0; i < process->NumberOfThreads; i++) { + if (process->Threads[i].ThreadState != Waiting || + process->Threads[i].WaitReason != Suspended) + { + suspended = false; + break; + } } + free(buffer); + if (suspended) + return STATUS_STOPPED; + else + return STATUS_RUNNING; +error: + err = GetError(); + log_err("%s", err); + LocalFree(err);; + return 20; } -void test_cpucount() +/* +* Get process priority as a enum proc_priority. +*/ +enum proc_priority nice(pid_t pid) { - printf("_________CPU Count_________\n"); - printf("Number of Logical Processors: %d\n",cpu_count(true)); - printf("Number of Physical Processors: %d\n\n",cpu_count(false)); + DWORD priority; + HANDLE hProcess; + int32_t value; + LPTSTR err = NULL; + hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ); + check(hProcess, "INVALID HANDLE"); + priority = GetPriorityClass(hProcess); + check(priority != 0, "INVALID PRIORITY"); + CloseHandle(hProcess); + return priority; + +error: + err = GetError(); + log_err("%s", err); + LocalFree(err); + if (hProcess) + free(hProcess); + return PRIORITY_ERROR; +} +/* +* Return a double indicating the process create time expressed in +* seconds since the epoch. +*/ + +double create_time(pid_t pid) { + long long unix_time = -1; + HANDLE hProcess; + FILETIME ftCreate, ftExit, ftKernel, ftUser; + PSYSTEM_PROCESS_INFORMATION process; + PVOID buffer = NULL; + LPTSTR err = NULL; + // special case for PIDs 0 and 4, return system boot time + if (0 == pid || 4 == pid) + { + return get_boot_time(); + } + hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ); + if((hProcess == NULL) && ((GetLastError() == ERROR_ACCESS_DENIED) || + (errno == EPERM) || (errno == EACCES))){ + if (get_proc_info(pid, &process, &buffer)) + { + goto find_time; + } + } + check(hProcess," failed to get Process Handle"); + if (!GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { + if ((GetLastError() == ERROR_ACCESS_DENIED) || + (errno == EPERM) || (errno == EACCES)) { + if (get_proc_info(pid, &process, &buffer)) + { + goto find_time; + } + else { + // usually means the process has died so we throw a + // NoSuchProcess here + CloseHandle(hProcess); + SetLastError(ERROR_NOSUCHPROCESS); + return -1; + } + } + else { + + goto error; + } + } + + CloseHandle(hProcess); + + // Convert the FILETIME structure to a Unix time. + // It's the best I could find by googling and borrowing code here + // and there. The time returned has a precision of 1 second. + + unix_time = ((LONGLONG)ftCreate.dwHighDateTime) << 32; + unix_time += ftCreate.dwLowDateTime - 116444736000000000LL; + unix_time /= 10000000; + return ((double)unix_time); +find_time: + unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32; + unix_time += process->CreateTime.LowPart - 116444736000000000LL; + unix_time /= 10000000; + return ((double)unix_time); +error: + err = GetError(); + log_err("%s", err); + LocalFree(err); + if(hProcess) + CloseHandle(hProcess); + return -1; } -void main() + +/* +* Get various process information by using NtQuerySystemInformation. +* - TODO : user/kernel times +* - TODO : io counters +*/ +Process *get_process(pid_t pid) { + PSYSTEM_PROCESS_INFORMATION process; + PVOID buffer; + ULONG num_handles; + ULONG i; + ULONG ctx_switches = 0; + long long create_time; + int num_threads; + enum proc_status _status = STATUS_STOPPED; + Process *process_info = NULL; + check(get_proc_info(pid, &process, &buffer),"error in getting process info"); + num_handles = process->HandleCount; + for (i = 0; i < process->NumberOfThreads; i++) + ctx_switches += process->Threads[i].ContextSwitches; + // Convert the LARGE_INTEGER union to a Unix time. + // It's the best I could find by googling and borrowing code here + // and there. The time returned has a precision of 1 second. + if (0 == pid || 4 == pid) { + create_time = get_boot_time(); + } + else { + create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; + create_time += process->CreateTime.LowPart - 116444736000000000LL; + create_time /= 10000000; + } + for (i = 0; i < process->NumberOfThreads; i++) { + if (process->Threads[i].ThreadState != Waiting || + process->Threads[i].WaitReason != Suspended) + { + _status = STATUS_RUNNING; + break; + } + } + num_threads = (int)process->NumberOfThreads; + free(buffer); + process_info = (Process *)calloc(1, sizeof(Process)); + check_mem(process_info); + process_info->pid = pid; + process_info->ppid = ppid(pid); + process_info->name = name(pid); + process_info->exe = exe(pid); + process_info->username = Username(pid); + process_info->nice = nice(pid); + process_info->cmdline = get_cmdline(pid); + process_info->num_handles = num_handles; + process_info->num_ctx_switches = ctx_switches; + process_info->create_time = (double)create_time; + process_info->num_threads = num_threads; + process_info->status = _status; + return process_info; +error: + return NULL; +} +void free_process(Process *p) { - test_virtual_memory(); - test_swap_memory(); - test_cpucount(); - test_cputimes(); - test_percputimes(); - test_boottime(); - test_cpu_stats(); - test_pids(); - test_pid_exists(); - test_netiocounters(); + if (p) + { + free(p->name); + free(p->exe); + free(p->username); + free(p->cmdline); + free(p); + } + } +/* +The following function is an ugly workaround to ensure that coverage +data can be manually flushed to disk during py.test invocations. If +this is not done, we cannot measure the coverage information. More details +in http://... link_to_bug... + */ +void gcov_flush(void) { __gcov_flush(); } + diff --git a/pslib_windows.h b/pslib_windows.h index 0115fc2..a7797c3 100644 --- a/pslib_windows.h +++ b/pslib_windows.h @@ -3,6 +3,14 @@ #include #include + +typedef struct +{ + unsigned long min; + unsigned long max; + unsigned long current; +}CpuFreq; + #define LO_T ((double)1e-7) #define HI_T (LO_T*4294967296.0) static ULONGLONG (*psutil_GetTickCount64)(void) = NULL; @@ -259,7 +267,7 @@ typedef struct { ULONG InterruptCount; } _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; - +/* typedef struct { LARGE_INTEGER IdleProcessTime; LARGE_INTEGER IoReadTransferCount; @@ -342,8 +350,8 @@ typedef struct { ULONG DpcBypassCount; ULONG ApcBypassCount; } _SYSTEM_INTERRUPT_INFORMATION; +*/ - /* typedef struct { ULONG ContextSwitches; ULONG DpcCount; @@ -353,8 +361,6 @@ typedef struct { ULONG ApcBypassCount; } _SYSTEM_INTERRUPT_INFORMATION; - - */ typedef struct { pid_t *pid; pid_t *ppid; @@ -486,74 +492,4 @@ const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; -typedef struct -{ - unsigned long ctx_switches; - unsigned long interrupts; - unsigned long soft_interrupts; - unsigned long syscalls; - unsigned long dpcs; -}CpuStats; -typedef struct -{ - unsigned long min; - unsigned long max; - unsigned long current; - -}CpuFreq; - -typedef struct -{ - long long total; - long long avail; - long long used; - float percent; -}VirtMemInfo; - -typedef struct { - uint64_t total; - uint64_t used; - uint64_t free; - float percent; - uint64_t sin; - uint64_t sout; -} SwapMemInfo; - -typedef struct -{ - float user; - float system; - float idle; - float interrupt; - float dpc; -}CpuTimes; - -typedef struct { - char *name; - uint64_t bytes_sent; - uint64_t bytes_recv; - uint64_t packets_sent; - uint64_t packets_recv; - uint64_t errin; - uint64_t errout; - uint64_t dropin; - uint64_t dropout; -} NetIOCounters; - -typedef struct { - uint32_t nitems; - NetIOCounters *iocounters; -} NetIOCounterInfo; - - -uint32_t get_boot_time(void); -bool virtual_memory(VmemInfo *); -bool swap_memory(SwapMemInfo *); -CpuTimes *cpu_times(bool); -uint32_t cpu_count(bool); -bool pid_exists(pid_t); -uint32_t *pids(DWORD*); -CpuStats *cpu_stats(); -NetIOCounterInfo *net_io_counters(bool); -voi free_netiocounterinfo(NetIOCounterInfo*); From 4ad03a7375fa7f56dcef388b48cb9b17b0195995 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 00:57:07 +0530 Subject: [PATCH 09/15] making compatible to Visual C++ 2008 compiler and solves #2 --- bindings/python/pycpslib_build.py | 54 +++++- common.h | 10 +- driver.c | 30 +-- pslib.h | 22 +-- pslib_windows.c | 61 +++--- types.h | 299 ++++++++++++++++++++++++++++++ 6 files changed, 413 insertions(+), 63 deletions(-) create mode 100644 types.h diff --git a/bindings/python/pycpslib_build.py b/bindings/python/pycpslib_build.py index 768c06b..8a0b711 100644 --- a/bindings/python/pycpslib_build.py +++ b/bindings/python/pycpslib_build.py @@ -1,13 +1,49 @@ # pycpslib.py import os - +import sys from cffi import FFI ffi = FFI() project_root = os.path.abspath("../../") +if sys.platform == "win32": + ffi.set_source("pycpslib", + """#include "pslib.h" + """, + sources=["../../pslib_windows.c", "../../common.c"], + library_dirs = [project_root], + include_dirs = [project_root]) + + ffi.cdef(''' + typedef int32_t pid_t; + typedef int32_t bool; + #define BELOW_NORMAL_PRIORITY_CLASS 0x00004000 + #define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 + #define NORMAL_PRIORITY_CLASS 0x00000020 + #define IDLE_PRIORITY_CLASS 0x00000040 + #define HIGH_PRIORITY_CLASS 0x00000080 + #define REALTIME_PRIORITY_CLASS 0x00000100 + ''',override = True) -ffi.set_source("pycpslib", + lines = open(project_root+"/pslib.h").readlines() + altered_lines = [] + flag = 1 + for line in lines: + if line.startswith('#include') or line.startswith('#define'): + altered_lines.append("") + elif line.startswith('#ifdef _WIN32'): + flag = 2 + elif line.startswith('#else') : + flag = 0 + elif line.startswith('#endif'): + flag = 1 + else: + if (flag != 0): + altered_lines.append(line) + ffi.cdef(''.join(altered_lines),override = True) + +else: + ffi.set_source("pycpslib", """#include #include #include @@ -18,16 +54,16 @@ library_dirs = [project_root], include_dirs = [project_root]) -ffi.cdef(''' -typedef int32_t pid_t; -typedef int32_t bool; -''') + ffi.cdef(''' + typedef int32_t pid_t; + typedef int32_t bool; + ''') -lines = open(project_root+"/pslib.h").readlines() + lines = open(project_root+"/pslib.h").readlines() -altered_lines = ['' if line.startswith('#include ') else line for line in lines] + altered_lines = ['' if line.startswith('#include ') else line for line in lines] -ffi.cdef(''.join(altered_lines)) + ffi.cdef(''.join(altered_lines)) if __name__ == '__main__': ffi.compile() diff --git a/common.h b/common.h index 5022cbb..b2f44a1 100644 --- a/common.h +++ b/common.h @@ -2,9 +2,17 @@ #include #include -#include +//#include #include +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; float percentage(uint64_t, uint64_t); int str_comp(const void *, const void *); diff --git a/driver.c b/driver.c index 87e803f..1cd411f 100644 --- a/driver.c +++ b/driver.c @@ -1,4 +1,4 @@ -#include + #include #include #include @@ -12,21 +12,19 @@ void test_diskusage() { DiskUsage du; - printf(" -- disk_usage \n"); #ifdef _WIN32 - char *disk1 = "C:/"; + char *disk2 = "D:/"; + char *disk1 = "C:/"; #else - char *disk1 = "/"; + char *disk2 = "/etc"; + char *disk1 = "/"; #endif + + printf(" -- disk_usage \n"); disk_usage(disk1, &du); printf("%s\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 "\npercent: %.1f\n\n", disk1, du.total, du.used, du.free, du.percent); -#ifdef _WIN32 - char *disk2 = "D:/"; -#else - char *disk2 = "/etc"; -#endif disk_usage(disk2, &du); printf("%s\ntotal: %" PRIu64 "\nused: %" PRIu64 "\nfree: %" PRIu64 "\npercent: %.1f\n\n", disk2, @@ -73,6 +71,7 @@ void test_diskpartitioninfo() { void test_diskiocounters() { DiskIOCounterInfo *d; DiskIOCounters *dp; + uint32_t i; d = disk_io_counters(); if (!d) { printf("Aborting"); @@ -81,7 +80,6 @@ void test_diskiocounters() { printf(" -- disk_io_counters \n"); dp = d->iocounters; - uint32_t i; for (i = 0; i < d->nitems; i++) { printf("%s: \tread_count=%" PRIu64 ", write_count=%" PRIu64 ", \n" "\tread_bytes=%" PRIu64 ", write_bytes=%" PRIu64 ", \n" @@ -98,7 +96,7 @@ void test_netiocounters() { NetIOCounterInfo *n; NetIOCounters *dp; uint32_t i; - n = net_io_counters_per_nic(); + n = net_io_counters(); dp = n->iocounters; printf(" -- net_io_counters_per_nic (interface count: %" PRIu32 ")\n", n->nitems); for (i = 0; i < n->nitems; i++) { @@ -113,6 +111,7 @@ void test_netiocounters() { free_net_iocounter_info(n); printf("\n"); n = net_io_counters(); + n = net_io_counters_summed(n); dp = n->iocounters; printf(" -- net_io_counters (summed)\n"); printf("bytes_sent=%" PRIu64 " bytes_rec=%" PRIu64 @@ -137,7 +136,7 @@ void test_getusers() { printf("Total: %" PRIu32 "\n", r->nitems); printf("Name\tTerminal Host\tStarted\n"); for (i = 0; i < r->nitems; i++) { - printf("%s\t%s\t %s\t%.1f\n", r->users[i].username, r->users[i].tty, + printf("%s\t%s\t %s\t%f\n", r->users[i].username, r->users[i].tty, r->users[i].hostname, r->users[i].tstamp); } free_users_info(r); @@ -228,6 +227,7 @@ void test_cpu_times() { void test_cpu_times_percpu() { CpuTimes *r, *c; + uint32_t i; uint32_t ncpus = cpu_count(true); c = r = cpu_times(true); if (!r) { @@ -235,7 +235,7 @@ void test_cpu_times_percpu() { return; } printf(" -- cpu_times_percpu\n"); - for (uint32_t i = 0; i < ncpus; i++) { + for (i = 0; i < ncpus; i++) { printf("CPU %" PRIu32 " :: ", i + 1); #ifdef _WIN32 printf("User: %.1lf;", c->user); @@ -378,6 +378,7 @@ void test_cpu_times_percent() { void test_cpu_times_percent_percpu() { CpuTimes *info, *last, *r; + uint32_t i; uint32_t ncpus = cpu_count(true); last = cpu_times(true); @@ -400,7 +401,7 @@ void test_cpu_times_percent_percpu() { printf(" -- cpu_times_percent_percpu\n"); printf("CPU times as percentage of total per CPU (0.1 second sample)\n"); - for (uint32_t i = 0; i < ncpus; i++) { + for (i = 0; i < ncpus; i++) { printf("CPU %" PRIu32 " :: ", i + 1); #ifdef _WIN32 printf("User: %.1lf;", info->user); @@ -443,6 +444,7 @@ void test_cpu_count() { printf("Logical : %" PRIu32 "\nPhysical : %" PRIu32 "\n", logical, physical); printf("\n"); } + const char *status_convert(enum proc_status statusid) { switch (statusid) diff --git a/pslib.h b/pslib.h index f3f16a9..45ed38a 100644 --- a/pslib.h +++ b/pslib.h @@ -1,12 +1,14 @@ #pragma once -#include -#include -#include +//#include +//#include +//#include #include #ifdef _WIN32 - #define pid_t uint32_t +#include +#define pid_t uint32_t #endif +#include "types.h" enum proc_status { STATUS_RUNNING, STATUS_SLEEPING, @@ -133,7 +135,7 @@ typedef struct { char *username; char *tty; char *hostname; - float tstamp; + double tstamp; } Users; typedef struct { @@ -168,10 +170,8 @@ typedef struct double user; double system; double idle; -#ifdef _WIN32 double interrupt; double dpc; -#else double nice; double iowait; double irq; @@ -179,7 +179,6 @@ typedef struct double steal; double guest; double guest_nice; -#endif }CpuTimes; typedef struct { @@ -200,8 +199,8 @@ typedef struct { char *cmdline; double create_time; #ifdef _WIN32 - uint32_t num_handles; // num handles only available in windows - enum con_status status;/* TODO : Implement others in this block in linux*/ + unsigned long num_handles; // num handles only available in windows + enum proc_status status;/* TODO : Implement others in this block in linux*/ enum proc_priority nice; uint32_t num_ctx_switches; uint32_t num_threads; @@ -225,8 +224,9 @@ void free_disk_partition_info(DiskPartitionInfo *); DiskIOCounterInfo *disk_io_counters(void); void free_disk_iocounter_info(DiskIOCounterInfo *); -NetIOCounterInfo *net_io_counters(void); +NetIOCounterInfo *net_io_counters(void); //same as net_io_counter_per_nic NetIOCounterInfo *net_io_counters_per_nic(void); +NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *);//needs pointer returned by net_io_counters(or net_io_counter_per_nic) void free_net_iocounter_info(NetIOCounterInfo *); UsersInfo *get_users(void); diff --git a/pslib_windows.c b/pslib_windows.c index 0eac7af..0f45b4b 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -25,7 +25,7 @@ #pragma comment(lib, "WTSAPI32.lib") #pragma comment(lib, "Advapi32.lib") #pragma comment(lib, "Shell32.lib") - +#pragma comment(lib, "PSAPI.lib") // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") @@ -365,8 +365,10 @@ UsersInfo *get_users() { tmp = ConvertWcharToChar(buffer_user); check(tmp, "Error in converting wchar"); users_info_ptr->users[users_info_ptr->nitems].username = tmp; - users_info_ptr->users[users_info_ptr->nitems].tstamp = (float)unix_time; - users_info_ptr->users[users_info_ptr->nitems].tty = NULL; + users_info_ptr->users[users_info_ptr->nitems].tstamp = (double)unix_time; + users_info_ptr->users[users_info_ptr->nitems].tty = (char *)calloc(1, sizeof(char)); + check_mem(users_info_ptr->users[users_info_ptr->nitems].tty); + users_info_ptr->users[users_info_ptr->nitems].tty[0] = '\0'; users_info_ptr->nitems++; } @@ -452,6 +454,7 @@ bool virtual_memory(VmemInfo *ret) ret->available = memInfo.ullAvailPhys; ret->used = ret->total - ret->available; ret->percent = (ret->used)*100.0/ret->total; + ret->free = ret->available; return true; } @@ -565,7 +568,8 @@ CpuTimes* per_cpu_times() { typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; HINSTANCE hNtDll; - + CpuTimes *ret = NULL; + CpuTimes *c = NULL; float idle, kernel, systemt, user, interrupt, dpc; NTSTATUS status; _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; @@ -599,8 +603,8 @@ CpuTimes* per_cpu_times() { check(status==0,"Unable to get CPU time"); - CpuTimes *ret = (CpuTimes*)calloc(si.dwNumberOfProcessors,sizeof(CpuTimes)); - CpuTimes *c=ret; + ret = (CpuTimes*)calloc(si.dwNumberOfProcessors,sizeof(CpuTimes)); + c = ret; if(!ret) goto error; // computes system global times summing each @@ -644,12 +648,13 @@ CpuTimes* per_cpu_times() { } CpuTimes *sum_per_cpu_times(CpuTimes *per_cpu) { - UINT i; - CpuTimes *ret = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + unsigned int i; + CpuTimes *ret = NULL, *c = NULL; + double user,system,idle,dpc,interrupt; + ret = (CpuTimes*)calloc(1,sizeof(CpuTimes)); check_mem(ret); - float user,system,idle,dpc,interrupt; idle = user = system = interrupt = dpc = 0; - CpuTimes *c = per_cpu; + c = per_cpu; for(i = 0; i < cpu_count(true); ++i) { user += c->user; @@ -672,9 +677,8 @@ CpuTimes *cpu_times_summed() { float idle, kernel, user, system; FILETIME idle_time, kernel_time, user_time; - + CpuTimes *data = NULL, *percpu = NULL, *percpu_summed = NULL; check(GetSystemTimes(&idle_time, &kernel_time, &user_time), "failed to get System times"); - idle = (float)((HI_T * idle_time.dwHighDateTime) + \ (LO_T * idle_time.dwLowDateTime)); user = (float)((HI_T * user_time.dwHighDateTime) + \ @@ -686,7 +690,6 @@ CpuTimes *cpu_times_summed() // We return only busy kernel time subtracting idle time from // kernel time. system = (kernel - idle); - CpuTimes *data = NULL, *percpu = NULL, *percpu_summed = NULL;; data = (CpuTimes*)calloc(1,sizeof(CpuTimes)); check_mem(data); data->idle=idle; @@ -727,7 +730,7 @@ cpustats *cpu_stats() { typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; HINSTANCE hNtDll; - + cpustats *ret = NULL; NTSTATUS status; _SYSTEM_PERFORMANCE_INFORMATION *spi = NULL; _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; @@ -803,7 +806,7 @@ cpustats *cpu_stats() { FreeLibrary(hNtDll); - cpustats *ret = (cpustats*)calloc(1,sizeof(cpustats)); + ret = (cpustats*)calloc(1,sizeof(cpustats)); check_mem(ret); ret->ctx_switches = spi->ContextSwitches; ret->interrupts = interrupts; @@ -990,8 +993,10 @@ PIP_ADAPTER_ADDRESSES get_nic_addresses() { NetIOCounterInfo *net_io_counters_per_nic() { + int len; DWORD dwRetVal = 0; - + NetIOCounterInfo *ret = NULL; + NetIOCounters *counters = NULL, *nc = NULL; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above MIB_IF_ROW2 *pIfRow = NULL; #else // Windows XP @@ -1004,8 +1009,6 @@ NetIOCounterInfo *net_io_counters_per_nic() if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; - NetIOCounterInfo *ret = NULL; - NetIOCounters *counters = NULL, *nc = NULL; ret = (NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); check_mem(ret); counters = (NetIOCounters*) calloc(15,sizeof(NetIOCounters)); @@ -1060,7 +1063,7 @@ NetIOCounterInfo *net_io_counters_per_nic() #endif nc->name = (char *)calloc(wcslen(pCurrAddresses->FriendlyName) + 1, sizeof(char)); - int len = wcslen(pCurrAddresses->FriendlyName); + len = wcslen(pCurrAddresses->FriendlyName); pCurrAddresses->FriendlyName[len] = '\0'; nc->name = ConvertWcharToChar(pCurrAddresses->FriendlyName); ret->nitems++; @@ -1096,14 +1099,17 @@ void free_net_iocounter_info(NetIOCounterInfo *ret) NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) { - NetIOCounterInfo *sum=(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + NetIOCounterInfo *sum = NULL; + NetIOCounters *r = NULL,*c =NULL; + int i; + sum =(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); check_mem(sum); - NetIOCounters *r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); + r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); check_mem(r); sum->iocounters = r; sum->nitems = 1; - int i; - NetIOCounters *c=info->iocounters; + + c =info->iocounters; for(i=0;initems;++i) { r->bytes_recv+=c->bytes_recv; @@ -1127,8 +1133,7 @@ NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) } NetIOCounterInfo *net_io_counters() { - NetIOCounterInfo *ret = net_io_counters_per_nic(); - return net_io_counters_summed(ret); + return net_io_counters_per_nic(); } pid_parent_map *ppid_map() { @@ -1303,13 +1308,14 @@ int is_phandle_running(HANDLE hProcess, DWORD pid) { HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { HANDLE hProcess; LPTSTR err = NULL; + int ret; if (pid == 0) // otherwise we'd get NoSuchProcess { SetLastError(ERROR_ACCESS_DENIED); return NULL; } hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); - int ret = is_phandle_running(hProcess, pid); + ret = is_phandle_running(hProcess, pid); if (ret == 1) return hProcess; else if(ret == 0) @@ -1520,13 +1526,12 @@ char * Username(pid_t pid) ULONG domainNameSize; SID_NAME_USE nameUse; LPTSTR err = NULL; + char *ret = NULL; // resolve the SID to a name nameSize = 0x100; domainNameSize = 0x100; // Get the user SID. bufferSize = 0x100; - - char *ret = NULL; ret = (char *)calloc(50, sizeof(char)); if (pid == 0 || pid == 4) strcpy(ret, "NT AUTHORITY\\SYSTEM"); diff --git a/types.h b/types.h new file mode 100644 index 0000000..efbb91b --- /dev/null +++ b/types.h @@ -0,0 +1,299 @@ +/* This header file can be replaced with inttypes.h and stdint.h + If both are available in the compiler used to compile the program */ +#define bool int +#define false 0 +#define true 1 +// These macros must exactly match those in the Windows SDK's intsafe.h. +#define INT8_MIN (-127i8 - 1) +#define INT16_MIN (-32767i16 - 1) +#define INT32_MIN (-2147483647i32 - 1) +#define INT64_MIN (-9223372036854775807i64 - 1) +#define INT8_MAX 127i8 +#define INT16_MAX 32767i16 +#define INT32_MAX 2147483647i32 +#define INT64_MAX 9223372036854775807i64 +#define UINT8_MAX 0xffui8 +#define UINT16_MAX 0xffffui16 +#define UINT32_MAX 0xffffffffui32 +#define UINT64_MAX 0xffffffffffffffffui64 + +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT32_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT32_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT32_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +#ifdef _WIN64 + #define INTPTR_MIN INT64_MIN + #define INTPTR_MAX INT64_MAX + #define UINTPTR_MAX UINT64_MAX +#else + #define INTPTR_MIN INT32_MIN + #define INTPTR_MAX INT32_MAX + #define UINTPTR_MAX UINT32_MAX +#endif + +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +#define PTRDIFF_MIN INTPTR_MIN +#define PTRDIFF_MAX INTPTR_MAX + +#ifndef SIZE_MAX + #define SIZE_MAX UINTPTR_MAX +#endif + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + + +#define WINT_MIN 0x0000 +#define WINT_MAX 0xffff + + + +#define PRId8 "hhd" +#define PRId16 "hd" +#define PRId32 "d" +#define PRId64 "lld" +#define PRIdLEAST8 PRId8 +#define PRIdLEAST16 PRId16 +#define PRIdLEAST32 PRId32 +#define PRIdLEAST64 PRId64 +#define PRIdFAST8 PRId8 +#define PRIdFAST16 PRId32 +#define PRIdFAST32 PRId32 +#define PRIdFAST64 PRId64 +#define PRIdMAX PRId64 +#ifdef _WIN64 + #define PRIdPTR PRId64 +#else + #define PRIdPTR PRId32 +#endif + +#define PRIi8 "hhi" +#define PRIi16 "hi" +#define PRIi32 "i" +#define PRIi64 "lli" +#define PRIiLEAST8 PRIi8 +#define PRIiLEAST16 PRIi16 +#define PRIiLEAST32 PRIi32 +#define PRIiLEAST64 PRIi64 +#define PRIiFAST8 PRIi8 +#define PRIiFAST16 PRIi32 +#define PRIiFAST32 PRIi32 +#define PRIiFAST64 PRIi64 +#define PRIiMAX PRIi64 +#ifdef _WIN64 + #define PRIiPTR PRIi64 +#else + #define PRIiPTR PRIi32 +#endif + +#define PRIo8 "hho" +#define PRIo16 "ho" +#define PRIo32 "o" +#define PRIo64 "llo" +#define PRIoLEAST8 PRIo8 +#define PRIoLEAST16 PRIo16 +#define PRIoLEAST32 PRIo32 +#define PRIoLEAST64 PRIo64 +#define PRIoFAST8 PRIo8 +#define PRIoFAST16 PRIo32 +#define PRIoFAST32 PRIo32 +#define PRIoFAST64 PRIo64 +#define PRIoMAX PRIo64 +#ifdef _WIN64 + #define PRIoPTR PRIo64 +#else + #define PRIoPTR PRIo32 +#endif + +#define PRIu8 "hhu" +#define PRIu16 "hu" +#define PRIu32 "u" +#define PRIu64 "llu" +#define PRIuLEAST8 PRIu8 +#define PRIuLEAST16 PRIu16 +#define PRIuLEAST32 PRIu32 +#define PRIuLEAST64 PRIu64 +#define PRIuFAST8 PRIu8 +#define PRIuFAST16 PRIu32 +#define PRIuFAST32 PRIu32 +#define PRIuFAST64 PRIu64 +#define PRIuMAX PRIu64 +#ifdef _WIN64 + #define PRIuPTR PRIu64 +#else + #define PRIuPTR PRIu32 +#endif + +#define PRIx8 "hhx" +#define PRIx16 "hx" +#define PRIx32 "x" +#define PRIx64 "llx" +#define PRIxLEAST8 PRIx8 +#define PRIxLEAST16 PRIx16 +#define PRIxLEAST32 PRIx32 +#define PRIxLEAST64 PRIx64 +#define PRIxFAST8 PRIx8 +#define PRIxFAST16 PRIx32 +#define PRIxFAST32 PRIx32 +#define PRIxFAST64 PRIx64 +#define PRIxMAX PRIx64 +#ifdef _WIN64 + #define PRIxPTR PRIx64 +#else + #define PRIxPTR PRIx32 +#endif + +#define PRIX8 "hhX" +#define PRIX16 "hX" +#define PRIX32 "X" +#define PRIX64 "llX" +#define PRIXLEAST8 PRIX8 +#define PRIXLEAST16 PRIX16 +#define PRIXLEAST32 PRIX32 +#define PRIXLEAST64 PRIX64 +#define PRIXFAST8 PRIX8 +#define PRIXFAST16 PRIX32 +#define PRIXFAST32 PRIX32 +#define PRIXFAST64 PRIX64 +#define PRIXMAX PRIX64 +#ifdef _WIN64 + #define PRIXPTR PRIX64 +#else + #define PRIXPTR PRIX32 +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Input Format Specifier Macros +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "d" +#define SCNd64 "lld" +#define SCNdLEAST8 SCNd8 +#define SCNdLEAST16 SCNd16 +#define SCNdLEAST32 SCNd32 +#define SCNdLEAST64 SCNd64 +#define SCNdFAST8 SCNd8 +#define SCNdFAST16 SCNd32 +#define SCNdFAST32 SCNd32 +#define SCNdFAST64 SCNd64 +#define SCNdMAX SCNd64 +#ifdef _WIN64 + #define SCNdPTR SCNd64 +#else + #define SCNdPTR SCNd32 +#endif + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "i" +#define SCNi64 "lli" +#define SCNiLEAST8 SCNi8 +#define SCNiLEAST16 SCNi16 +#define SCNiLEAST32 SCNi32 +#define SCNiLEAST64 SCNi64 +#define SCNiFAST8 SCNi8 +#define SCNiFAST16 SCNi32 +#define SCNiFAST32 SCNi32 +#define SCNiFAST64 SCNi64 +#define SCNiMAX SCNi64 +#ifdef _WIN64 + #define SCNiPTR SCNi64 +#else + #define SCNiPTR SCNi32 +#endif + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "o" +#define SCNo64 "llo" +#define SCNoLEAST8 SCNo8 +#define SCNoLEAST16 SCNo16 +#define SCNoLEAST32 SCNo32 +#define SCNoLEAST64 SCNo64 +#define SCNoFAST8 SCNo8 +#define SCNoFAST16 SCNo32 +#define SCNoFAST32 SCNo32 +#define SCNoFAST64 SCNo64 +#define SCNoMAX SCNo64 +#ifdef _WIN64 + #define SCNoPTR SCNo64 +#else + #define SCNoPTR SCNo32 +#endif + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "u" +#define SCNu64 "llu" +#define SCNuLEAST8 SCNu8 +#define SCNuLEAST16 SCNu16 +#define SCNuLEAST32 SCNu32 +#define SCNuLEAST64 SCNu64 +#define SCNuFAST8 SCNu8 +#define SCNuFAST16 SCNu32 +#define SCNuFAST32 SCNu32 +#define SCNuFAST64 SCNu64 +#define SCNuMAX SCNu64 +#ifdef _WIN64 + #define SCNuPTR SCNu64 +#else + #define SCNuPTR SCNu32 +#endif + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "x" +#define SCNx64 "llx" +#define SCNxLEAST8 SCNx8 +#define SCNxLEAST16 SCNx16 +#define SCNxLEAST32 SCNx32 +#define SCNxLEAST64 SCNx64 +#define SCNxFAST8 SCNx8 +#define SCNxFAST16 SCNx32 +#define SCNxFAST32 SCNx32 +#define SCNxFAST64 SCNx64 +#define SCNxMAX SCNx64 +#ifdef _WIN64 + #define SCNxPTR SCNx64 +#else + #define SCNxPTR SCNx32 +#endif + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; \ No newline at end of file From f9e180d704cca144c8158a508fa83f518c116cdc Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 01:02:03 +0530 Subject: [PATCH 10/15] test for Cpu_times --- tests/conftest.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 79ac379..a44baaf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -72,9 +72,19 @@ def compare_darwin(t1, t2): almost_equal(t1.system, t2.system), almost_equal(t1.idle, t2.idle), almost_equal(t1.nice, t2.nice)]) - + + def compare_win32(t1, t2): + return all([almost_equal(t1.user, t2.user), + almost_equal(t1.system, t2.system), + almost_equal(t1.idle, t2.idle), + almost_equal(t1.interrupt, t2.interrupt), + almost_equal(t1.dpc, t2.dpc)]) + + if sys.platform == 'win32': + return compare_win32 if sys.platform == 'darwin': return compare_darwin + # TODO: add more cases as more platforms get implemented # See https://github.com/nibrahim/cpslib/issues/9 as well. From 9fa2c037a67c59ba53bad5b0b3c65275bcc2b1a7 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 01:02:54 +0530 Subject: [PATCH 11/15] test for Disk_usage Windows --- tests/test_disk.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_disk.py b/tests/test_disk.py index 63d5f91..85decb1 100644 --- a/tests/test_disk.py +++ b/tests/test_disk.py @@ -1,6 +1,7 @@ import psutil from pycpslib import lib as P from pycpslib import ffi +import sys def test_number_of_partitions(flush): expected_all_partitions = psutil.disk_partitions(True) # All partitions @@ -33,7 +34,11 @@ def test_all_partition_attribs(flush): assert found, """No match for Partition(mountpoint = '{}', device = '{}', fstype = '{}', opts = '{}')""".format(mountpoint, device, fstype, opts) def test_disk_usage(flush): - for mountpoint in ["/", "/etc/", "/home", "/var"]: + if sys.platform == 'win32': + disk = ["C:/","D:/"] + else: + disk = ["/", "/etc/", "/home", "/var"] + for mountpoint in disk: pslib_usage = ffi.new("DiskUsage *") P.disk_usage(mountpoint, pslib_usage) psutil_usage = psutil.disk_usage(mountpoint) From 9ac372aee35e1fca3346f2526a57f66f7610c0e1 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 01:03:57 +0530 Subject: [PATCH 12/15] test for virtual_memory windows --- tests/test_memory.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_memory.py b/tests/test_memory.py index c527e00..2791cb9 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -35,6 +35,18 @@ def test_virtual_memory_darwin(almost_equal, flush): assert almost_equal(pslib_vmem.percent, psutil_vmem.percent) assert almost_equal(pslib_vmem.used, psutil_vmem.used) +@pytest.mark.win32 +def test_virtual_memory_windows(almost_equal, flush): + pslib_vmem = ffi.new("VmemInfo *") + P.virtual_memory(pslib_vmem) + psutil_vmem = psutil.virtual_memory() + + assert almost_equal(pslib_vmem.total, psutil_vmem.total) + assert almost_equal(pslib_vmem.available, psutil_vmem.available) + assert almost_equal(pslib_vmem.used, psutil_vmem.used) + assert almost_equal(pslib_vmem.free, psutil_vmem.free) + assert almost_equal(pslib_vmem.percent, psutil_vmem.percent) + def test_swap(almost_equal, flush): pslib_swap = ffi.new("SwapMemInfo *") P.swap_memory(pslib_swap) From 0f4fa5265f78edffd870ef3dc7e37eb0490f3625 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 01:05:13 +0530 Subject: [PATCH 13/15] test for get_users windows --- tests/test_users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_users.py b/tests/test_users.py index 9803351..1d88f7a 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -16,7 +16,7 @@ def test_get_users(flush): found = False for part in psutil_users: if all([part.name == username, - part.terminal == tty, + part.terminal == tty or (part.terminal == None and tty == ''),# special case for behavior on windows part.host == hostname or (part.host is None and hostname == ''), # special case for behavior on osx part.started == tstamp]): found = True From 9b10ae778ed0e3264635a00a6a9d954e567d6409 Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sat, 8 Jul 2017 01:05:46 +0530 Subject: [PATCH 14/15] test for get_process windows --- tests/test_process.py | 44 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/test_process.py b/tests/test_process.py index bcccb77..e8fa07a 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -3,14 +3,30 @@ import psutil from pycpslib import lib as P from pycpslib import ffi - +import pytest +status_string = { 0 : "running", + 1 : "sleeping", + 2 : "disk-sleep", + 3 : "stopped", + 4 : "tracing-stop", + 5 : "zombie", + 6 : "dead", + 7 : "wake-kill", + 8 : "waking", + 9 : "idle", + 10 : "locked", + 11 : "waiting", + 12 : "suspended" + } def test_pid_exists(flush): cpid = os.getpid() peu = psutil.pid_exists(cpid) pel = P.pid_exists(cpid) assert peu == pel -def test_process(flush): + +@pytest.mark.linux2 +def test_process_linux(flush): cpid = os.getpid() psu = psutil.Process(cpid) psl = P.get_process(cpid) @@ -30,3 +46,27 @@ def test_process(flush): assert gids.saved == psl.sgid assert psu.username() == ffi.string(psl.username) assert psu.terminal() == ffi.string(psl.terminal) + +@pytest.mark.win32 +def test_process_windows(flush): + proc_status = ffi.typeof('enum proc_status') + cpid = os.getpid() + psu = psutil.Process(cpid) + psl = P.get_process(cpid) + num_handles = psu.num_handles() + assert psu.pid == psl.pid + assert psu.ppid() == psl.ppid + assert psu.name() == ffi.string(psl.name) + assert psu.exe() == ffi.string(psl.exe) + assert " ".join(psu.cmdline()) == ffi.string(psl.cmdline) + assert psu.create_time() == psl.create_time + assert psu.nice() == psl.nice + #assert num_handles == psl.num_handles # fails for pid given by os.getpid()(current process) + #assert psu.num_ctx_switches().voluntary == psl.num_ctx_switches + assert psu.num_threads() == psl.num_threads + assert psu.username() == ffi.string(psl.username) + assert psu.status() == status_string[psl.status] + + + + From 80e5cc0966b366654bf78d88072a9412ce8b7b5e Mon Sep 17 00:00:00 2001 From: libin-n-g Date: Sun, 9 Jul 2017 21:11:53 +0530 Subject: [PATCH 15/15] Test for memory leakage completed sucessfully --- driver.c | 17 +++++- make.bat | 5 ++ pslib.h | 7 ++- pslib_windows.c | 142 +++++++++++++++++++++++++++++++----------------- 4 files changed, 118 insertions(+), 53 deletions(-) create mode 100644 make.bat diff --git a/driver.c b/driver.c index 1cd411f..ac9a7d2 100644 --- a/driver.c +++ b/driver.c @@ -1,9 +1,10 @@ - +/*use cl /MTd /D_DEBUG driver.c pslib_windows.c common.c to enable Debugging and find memory leak and memory correptions*/ #include #include #include #ifdef _WIN32 #include +#include #else #include #endif @@ -522,6 +523,16 @@ void test_process() { } int main(void) { +#ifdef _DEBUG + HANDLE hLogFile; + hLogFile = CreateFile("E:\\log.txt", GENERIC_WRITE, + FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); +#endif + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, hLogFile); + + _RPT0(_CRT_WARN,"file message\n"); test_diskusage(); test_diskpartitioninfo(); test_diskiocounters(); @@ -545,4 +556,8 @@ int main(void) { test_pid_exists(); test_process(); + _CrtDumpMemoryLeaks(); +#ifdef _DEBUG + CloseHandle(hLogFile); +#endif } diff --git a/make.bat b/make.bat new file mode 100644 index 0000000..0f196e4 --- /dev/null +++ b/make.bat @@ -0,0 +1,5 @@ +CALL %LOCALAPPDATA%"\Programs\Common\Microsoft\Visual C++ for Python\9.0\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% +cl /c common.c pslib_windows.c +LIB.EXE /OUT:pslib.obj pslib_windows.obj common.obj +LIB.EXE /OUT:pslib.lib pslib_windows.obj common.obj +cl driver.c /link pslib \ No newline at end of file diff --git a/pslib.h b/pslib.h index 45ed38a..92766d9 100644 --- a/pslib.h +++ b/pslib.h @@ -9,6 +9,9 @@ #define pid_t uint32_t #endif #include "types.h" +#define _CRTDBG_MAP_ALLOC +#include +#include enum proc_status { STATUS_RUNNING, STATUS_SLEEPING, @@ -146,7 +149,7 @@ typedef struct { typedef struct { uint64_t total; uint64_t available; - float percent; + double percent; uint64_t used; uint64_t free; uint64_t active; @@ -160,7 +163,7 @@ typedef struct { uint64_t total; uint64_t used; uint64_t free; - float percent; + double percent; uint64_t sin; uint64_t sout; } SwapMemInfo; diff --git a/pslib_windows.c b/pslib_windows.c index 0f45b4b..18cb373 100644 --- a/pslib_windows.c +++ b/pslib_windows.c @@ -1,3 +1,4 @@ + #define WIN32_LEAN_AND_MEAN #include #include @@ -48,6 +49,8 @@ PCHAR GetError() { strcpy(err, errormessage); return err; error: + if(err) + free(err); return NULL; } //used to convert null terminated WCHAR string to char string @@ -59,8 +62,6 @@ char *ConvertWcharToChar(WCHAR buffer[]) check_mem(tmp); if (WideCharToMultiByte(CP_UTF8, 0, buffer, -1, tmp, length, NULL, NULL) == 0) { - DWORD t; - GetError(&t); goto error; } return tmp; @@ -101,13 +102,13 @@ DiskIOCounterInfo *disk_io_counters(void) { check_mem(ret->iocounters); szDeviceDisplay = (char *)calloc(MAX_PATH, sizeof(char)); sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); - ret->iocounters[devNum].name = szDeviceDisplay; - ret->iocounters[devNum].reads = diskPerformance.ReadCount; - ret->iocounters[devNum].writes = diskPerformance.WriteCount; - ret->iocounters[devNum].readbytes = diskPerformance.BytesRead.QuadPart; - ret->iocounters[devNum].writebytes = diskPerformance.BytesWritten.QuadPart; - ret->iocounters[devNum].readtime = (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000; - ret->iocounters[devNum].writetime = (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000; + ret->iocounters[ret->nitems - 1].name = szDeviceDisplay; + ret->iocounters[ret->nitems - 1].reads = diskPerformance.ReadCount; + ret->iocounters[ret->nitems - 1].writes = diskPerformance.WriteCount; + ret->iocounters[ret->nitems - 1].readbytes = diskPerformance.BytesRead.QuadPart; + ret->iocounters[ret->nitems - 1].writebytes = diskPerformance.BytesWritten.QuadPart; + ret->iocounters[ret->nitems - 1].readtime = (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000; + ret->iocounters[ret->nitems - 1].writetime = (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000; } CloseHandle(hDevice); } @@ -121,6 +122,11 @@ DiskIOCounterInfo *disk_io_counters(void) { } void free_disk_iocounter_info(DiskIOCounterInfo *tmp) { + uint32_t i; + for(i = 0; i < tmp->nitems; i++) + { + free(tmp->iocounters[i].name); + } free(tmp->iocounters); free(tmp); } @@ -309,7 +315,7 @@ UsersInfo *get_users() { check_mem(users_info_ptr); check(WTSEnumerateSessions(hServer, 0, 1, &sessions, &count), "error in retrieving list of sessions on a Remote Desktop Session Host server"); - users_info_ptr->users = (Users *)calloc(count, sizeof(Users)); + users_info_ptr->users = (Users *)calloc(1, sizeof(Users)); check_mem(users_info_ptr->users); users_info_ptr->nitems = 0; for (i = 0; i < count; i++) { @@ -334,6 +340,8 @@ UsersInfo *get_users() { &buffer_addr, &bytes),"error in retriving ClientAddress") address = (PWTS_CLIENT_ADDRESS)buffer_addr; + users_info_ptr->users = (Users *)realloc(users_info_ptr->users ,(users_info_ptr->nitems + 1)*sizeof(Users)); + check_mem(users_info_ptr->users); if (address->AddressFamily == 0) { // AF_INET sprintf_s(address_str, _countof(address_str), @@ -346,6 +354,7 @@ UsersInfo *get_users() { check_mem(tmp); strcpy(tmp,address_str); users_info_ptr->users[users_info_ptr->nitems].hostname = tmp; + tmp = NULL; } else { users_info_ptr->users[users_info_ptr->nitems].hostname = NULL; @@ -386,6 +395,8 @@ UsersInfo *get_users() { WTSFreeMemory(buffer_user); if (buffer_addr != NULL) WTSFreeMemory(buffer_addr); + if (users_info_ptr->users[users_info_ptr->nitems].hostname) + free(users_info_ptr->users[users_info_ptr->nitems].hostname); if (users_info_ptr) free_users_info(users_info_ptr); if (tmp) @@ -405,7 +416,7 @@ double get_valid_value(double a) CpuTimes *calculate(CpuTimes *t1, CpuTimes * t2) { double all_delta; - int i; + uint32_t i; CpuTimes *ret; ret = (CpuTimes *)calloc(1,sizeof(CpuTimes)); check_mem(ret); @@ -567,7 +578,7 @@ CpuTimes* per_cpu_times() { // NtQuerySystemInformation stuff typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; - HINSTANCE hNtDll; + HINSTANCE hNtDll = NULL; CpuTimes *ret = NULL; CpuTimes *c = NULL; float idle, kernel, systemt, user, interrupt, dpc; @@ -604,9 +615,8 @@ CpuTimes* per_cpu_times() { ret = (CpuTimes*)calloc(si.dwNumberOfProcessors,sizeof(CpuTimes)); + check_mem(ret); c = ret; - if(!ret) - goto error; // computes system global times summing each // processor value idle = user = kernel = interrupt = dpc = 0; @@ -644,11 +654,13 @@ CpuTimes* per_cpu_times() { free(sppi); if (hNtDll) FreeLibrary(hNtDll); + if (ret) + free(ret); return NULL; } CpuTimes *sum_per_cpu_times(CpuTimes *per_cpu) { - unsigned int i; + uint32_t i; CpuTimes *ret = NULL, *c = NULL; double user,system,idle,dpc,interrupt; ret = (CpuTimes*)calloc(1,sizeof(CpuTimes)); @@ -699,8 +711,8 @@ CpuTimes *cpu_times_summed() percpu = per_cpu_times(); check_mem(percpu); percpu_summed = sum_per_cpu_times(percpu); + free(percpu); check_mem(percpu_summed); - free(percpu); data->interrupt = percpu_summed->interrupt; data->dpc= percpu_summed->dpc; free(percpu_summed); @@ -834,8 +846,6 @@ CpuTimes *cpu_times_percent(bool percpu , CpuTimes * Last_Cpu_times) { uint32_t no_cpu, i; CpuTimes *t2 = NULL, *ret = NULL, *tmp = NULL; - t2 = (CpuTimes *)calloc(1, sizeof(CpuTimes)); - check_mem(t2); if (!percpu) { t2 = cpu_times(false); ret = calculate(t2, Last_Cpu_times); @@ -861,6 +871,7 @@ CpuTimes *cpu_times_percent(bool percpu , CpuTimes * Last_Cpu_times) free(tmp); } } + free(t2); return ret; error: if (tmp) @@ -1062,7 +1073,6 @@ NetIOCounterInfo *net_io_counters_per_nic() #endif - nc->name = (char *)calloc(wcslen(pCurrAddresses->FriendlyName) + 1, sizeof(char)); len = wcslen(pCurrAddresses->FriendlyName); pCurrAddresses->FriendlyName[len] = '\0'; nc->name = ConvertWcharToChar(pCurrAddresses->FriendlyName); @@ -1086,7 +1096,7 @@ NetIOCounterInfo *net_io_counters_per_nic() } void free_net_iocounter_info(NetIOCounterInfo *ret) { - int i; + uint32_t i; NetIOCounters *c=ret->iocounters; for(i=0;initems;++i) { @@ -1101,7 +1111,7 @@ NetIOCounterInfo *net_io_counters_summed(NetIOCounterInfo *info) { NetIOCounterInfo *sum = NULL; NetIOCounters *r = NULL,*c =NULL; - int i; + uint32_t i; sum =(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); check_mem(sum); r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); @@ -1135,7 +1145,12 @@ NetIOCounterInfo *net_io_counters() { return net_io_counters_per_nic(); } - +void free_pid_parent_map(pid_parent_map * p) +{ + free(p->pid); + free(p->ppid); + free(p); +} pid_parent_map *ppid_map() { HANDLE handle = NULL; PROCESSENTRY32 pe = { 0 }; @@ -1165,7 +1180,7 @@ pid_parent_map *ppid_map() { return ret; error: if (ret) - free(ret); + free_pid_parent_map(ret); if (handle) CloseHandle(handle); return NULL; @@ -1186,11 +1201,11 @@ pid_t ppid(pid_t pid) } } check(i != map->nitems, "pid not found in the list of running process"); - free(map); + free_pid_parent_map(map); return ret; error: if (map) - free(map); + free_pid_parent_map(map); return -1; } TCHAR *convert_dos_path(TCHAR * path) @@ -1237,7 +1252,8 @@ TCHAR *convert_dos_path(TCHAR * path) } ret = (TCHAR *)calloc(100, sizeof(TCHAR)); check_mem(ret); - check(_stprintf(ret,TEXT("%hs%hs"), driveletter,devicepath), "unable to join driveletter and rawdrive"); + check(_stprintf(ret,TEXT("%hs%hs"), driveletter, devicepath), "unable to join driveletter and rawdrive"); + free(devicepath); return ret; error: if (ret) @@ -1265,7 +1281,7 @@ pid_in_pids(DWORD pid) { int is_phandle_running(HANDLE hProcess, DWORD pid) { DWORD processExitCode = 0; - LPTSTR err = NULL; + PCHAR err = NULL; if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { SetLastError(ERROR_NOSUCHPROCESS); @@ -1274,7 +1290,7 @@ int is_phandle_running(HANDLE hProcess, DWORD pid) { err = GetError(); if (GetLastError() != ERROR_ACCESS_DENIED) log_err("%s", err); - LocalFree(err); + free(err); return -1; } @@ -1301,13 +1317,13 @@ int is_phandle_running(HANDLE hProcess, DWORD pid) { err = GetError(); if(GetLastError() != ERROR_ACCESS_DENIED) log_err("%s", err); - LocalFree(err); + free(err); return -1; } HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { HANDLE hProcess; - LPTSTR err = NULL; + PCHAR err = NULL; int ret; if (pid == 0) // otherwise we'd get NoSuchProcess { @@ -1330,7 +1346,7 @@ HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { } error: if (err) - LocalFree(err); + free(err); return NULL; } @@ -1345,7 +1361,7 @@ char *get_cmdline(long pid) { WCHAR *commandLineContents = NULL; static _NtQueryInformationProcess NtQueryInformationProcess = NULL; PROCESS_BASIC_INFORMATION pbi; - LPTSTR err = NULL; + PCHAR err = NULL; if (pid == 0 || pid == 4) { return NULL; @@ -1381,7 +1397,7 @@ char *get_cmdline(long pid) { &commandLine, sizeof(commandLine), NULL), "Could not read Command Line Unicode Structure"); #endif // allocate memory to hold the command line - commandLineContents = (WCHAR *)malloc(commandLine.Length + 1); + commandLineContents = (WCHAR *)malloc((commandLine.Length + 1) * sizeof(WCHAR)); check_mem(commandLineContents); // read the command line @@ -1393,22 +1409,26 @@ char *get_cmdline(long pid) { // commandLine.Length is in bytes. commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0'; ret = ConvertWcharToChar(commandLineContents); + check(ret,"coverting WCHAR failed"); /* TODO : attempt to parse the command line using Win32 API and return list of commandline args*/ free(commandLineContents); CloseHandle(hProcess); return ret; error: - err = GetError(); log_err("%s", err); LocalFree(err); + if(commandLineContents) + free(commandLineContents); + + err = GetError(); log_err("%s", err); free(err); return NULL; } char *exe(pid_t pid) { - HANDLE hProcess; + HANDLE hProcess = NULL; TCHAR *tmp; WCHAR tmpexe[MAX_PATH]; TCHAR exe[MAX_PATH]; - LPTSTR err = NULL; + PCHAR err = NULL; char *ret = NULL; if (pid == 0 || pid == 4) { @@ -1424,12 +1444,14 @@ char *exe(pid_t pid) { } tmp = convert_dos_path(exe); _swprintf(tmpexe,L"%hs",tmp); + free(tmp); ret = ConvertWcharToChar(tmpexe); + check(ret,"Converting Wchar failed"); return ret; error: err = GetError(); log_err("%s", err); - LocalFree(err);; + free(err);; if(hProcess) CloseHandle(hProcess); return NULL; @@ -1514,7 +1536,7 @@ char *name(pid_t pid) /* * Return process username as a "DOMAIN//USERNAME" string. */ -char * Username(pid_t pid) +char *Username(pid_t pid) { HANDLE processHandle = NULL; HANDLE tokenHandle = NULL; @@ -1525,20 +1547,24 @@ char * Username(pid_t pid) ULONG nameSize; ULONG domainNameSize; SID_NAME_USE nameUse; - LPTSTR err = NULL; + PCHAR err = NULL; char *ret = NULL; + char *Dname = NULL,*Name = NULL; // resolve the SID to a name nameSize = 0x100; domainNameSize = 0x100; // Get the user SID. bufferSize = 0x100; - ret = (char *)calloc(50, sizeof(char)); if (pid == 0 || pid == 4) + { + ret = (char *)calloc(50, sizeof(char)); + check_mem(ret); strcpy(ret, "NT AUTHORITY\\SYSTEM"); + } else { processHandle = handle_from_pid_waccess( - pid, PROCESS_QUERY_INFORMATION); + pid, PROCESS_QUERY_INFORMATION); check(processHandle, "Error in getting Handle from pid "); check(OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle), "Error in Opening Process Token"); CloseHandle(processHandle); @@ -1574,14 +1600,24 @@ char * Username(pid_t pid) } break; } - ret = (char *)realloc(ret, (wcslen(domainName) + wcslen(name) + 5) * sizeof(char)); - sprintf(ret, "%s\\%s", ConvertWcharToChar(domainName), ConvertWcharToChar(name)); + Dname = ConvertWcharToChar(domainName); + check(Dname, "Converting WCHAR failed"); + Name = ConvertWcharToChar(name); + check(Name, "Converting WCHAR failed"); + ret = (char *)calloc((strlen(Dname) + strlen(Name) + 3), sizeof(char)); + check_mem(ret); + sprintf(ret, "%s\\%s",Dname , Name); + free(Name); + free(Dname); + free(domainName); + free(name); + free(user); } return ret; error: err = GetError(); log_err("%s", err); - LocalFree(err);; + free(err);; if (processHandle != NULL) CloseHandle(processHandle); if (tokenHandle != NULL) @@ -1592,6 +1628,10 @@ char * Username(pid_t pid) free(domainName); if (user != NULL) free(user); + if (Name) + free(Name); + if (Dname) + free(Dname); return NULL; } int @@ -1661,7 +1701,7 @@ enum proc_status status(pid_t pid) { bool suspended = true; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; - LPTSTR err = NULL; + PCHAR err = NULL; check(get_proc_info(pid, &process, &buffer), "Cannot get Process Info"); for (i = 0; i < process->NumberOfThreads; i++) { if (process->Threads[i].ThreadState != Waiting || @@ -1679,7 +1719,7 @@ enum proc_status status(pid_t pid) { error: err = GetError(); log_err("%s", err); - LocalFree(err);; + free(err);; return 20; } @@ -1691,7 +1731,7 @@ enum proc_priority nice(pid_t pid) DWORD priority; HANDLE hProcess; int32_t value; - LPTSTR err = NULL; + PCHAR err = NULL; hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ); check(hProcess, "INVALID HANDLE"); priority = GetPriorityClass(hProcess); @@ -1702,7 +1742,7 @@ enum proc_priority nice(pid_t pid) error: err = GetError(); log_err("%s", err); - LocalFree(err); + free(err); if (hProcess) free(hProcess); return PRIORITY_ERROR; @@ -1718,7 +1758,7 @@ double create_time(pid_t pid) { FILETIME ftCreate, ftExit, ftKernel, ftUser; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer = NULL; - LPTSTR err = NULL; + PCHAR err = NULL; // special case for PIDs 0 and 4, return system boot time if (0 == pid || 4 == pid) { @@ -1772,7 +1812,7 @@ double create_time(pid_t pid) { error: err = GetError(); log_err("%s", err); - LocalFree(err); + free(err); if(hProcess) CloseHandle(hProcess); return -1; @@ -1834,6 +1874,8 @@ Process *get_process(pid_t pid) { process_info->status = _status; return process_info; error: + if(process_info) + free_process(process_info); return NULL; } void free_process(Process *p)