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.c b/common.c index 54d8f5e..72e7be2 100644 --- a/common.c +++ b/common.c @@ -1,73 +1,78 @@ -#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: - free(line); - 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: + free(line); + 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..b2f44a1 100644 --- a/common.h +++ b/common.h @@ -1,55 +1,64 @@ -#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 + +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 *); +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..ac9a7d2 100644 --- a/driver.c +++ b/driver.c @@ -1,401 +1,563 @@ -#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(); -} +/*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 + +#include "pslib.h" + +void test_diskusage() { + DiskUsage du; +#ifdef _WIN32 + char *disk2 = "D:/"; + char *disk1 = "C:/"; +#else + 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); + 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; + uint32_t i; + d = disk_io_counters(); + if (!d) { + printf("Aborting"); + return; + } + + printf(" -- disk_io_counters \n"); + dp = d->iocounters; + 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_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(); + n = net_io_counters_summed(n); + 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%f\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 i; + uint32_t ncpus = cpu_count(true); + c = r = cpu_times(true); + if (!r) { + printf("Aborting\n"); + return; + } + printf(" -- cpu_times_percpu\n"); + for (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 i; + 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 (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) { +#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(); + 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(); + _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 538d1c7..92766d9 100644 --- a/pslib.h +++ b/pslib.h @@ -1,9 +1,17 @@ #pragma once -#include -#include +//#include +//#include +//#include #include - +#ifdef _WIN32 +#include +#define pid_t uint32_t +#endif +#include "types.h" +#define _CRTDBG_MAP_ALLOC +#include +#include enum proc_status { STATUS_RUNNING, STATUS_SLEEPING, @@ -16,7 +24,8 @@ enum proc_status { STATUS_WAKING, STATUS_IDLE, STATUS_LOCKED, - STATUS_WAITING + STATUS_WAITING, + STATUS_SUSPENDED }; enum ioprio_class { @@ -65,12 +74,13 @@ enum con_status { }; 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 { @@ -128,7 +138,7 @@ typedef struct { char *username; char *tty; char *hostname; - float tstamp; + double tstamp; } Users; typedef struct { @@ -139,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; @@ -153,23 +163,36 @@ typedef struct { uint64_t total; uint64_t used; uint64_t free; - float percent; + double percent; uint64_t sin; uint64_t sout; } SwapMemInfo; +typedef struct +{ + double user; + double system; + double idle; + double interrupt; + double dpc; + double nice; + double iowait; + double irq; + double softirq; + double steal; + double guest; + double guest_nice; +}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; @@ -178,14 +201,22 @@ typedef struct { char *exe; char *cmdline; double create_time; - uint32_t uid; +#ifdef _WIN32 + 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; +#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 *); @@ -196,7 +227,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); @@ -211,17 +244,22 @@ CpuTimes *cpu_times(bool); CpuTimes *cpu_times_percent(bool, CpuTimes *); -double *cpu_util_percent(bool percpu, CpuTimes *prev_times); - +//double *cpu_util_percent(bool percpu, CpuTimes *prev_times); +cpustats *cpu_stats(); uint32_t cpu_count(bool); bool pid_exists(pid_t); +uint32_t *pids(uint32_t *); 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 new file mode 100644 index 0000000..18cb373 --- /dev/null +++ b/pslib_windows.c @@ -0,0 +1,1901 @@ + +#define WIN32_LEAN_AND_MEAN +#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, "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") + +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: + if(err) + free(err); + 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) + { + goto error; + } + return tmp; +error: + if (tmp) + free(tmp); + return NULL; +} + +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[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); + } + return ret; +error: + if (ret) + free_disk_iocounter_info(ret); + if (hDevice != NULL) + CloseHandle(hDevice); + return NULL; +} +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); +} + +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); +} + +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; + } +} +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; + 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 = NULL; + PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; + WINSTATION_INFO station_info; + HINSTANCE hInstWinSta = NULL; + ULONG returnLen; + + UsersInfo *users_info_ptr = 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(1, sizeof(Users)); + check_mem(users_info_ptr->users); + users_info_ptr->nitems = 0; + for (i = 0; i < count; i++) { + 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; + 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), + "%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; + tmp = NULL; + } + 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 = 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 = (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++; + } + + 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->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) + free(tmp); + return NULL; +} + +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; + uint32_t 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; +} + +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(VmemInfo *ret) +{ + MEMORYSTATUSEX memInfo; + memInfo.dwLength = sizeof(MEMORYSTATUSEX); + + if (! GlobalMemoryStatusEx(&memInfo)) + return false; + + ret->total = memInfo.ullTotalPhys; + ret->available = memInfo.ullAvailPhys; + ret->used = ret->total - ret->available; + ret->percent = (ret->used)*100.0/ret->total; + ret->free = ret->available; + 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)calloc(length, sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); + check_mem(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 = NULL; + CpuTimes *ret = NULL; + CpuTimes *c = NULL; + 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"); + + + ret = (CpuTimes*)calloc(si.dwNumberOfProcessors,sizeof(CpuTimes)); + check_mem(ret); + c = ret; + // 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); + if (ret) + free(ret); + return NULL; +} +CpuTimes *sum_per_cpu_times(CpuTimes *per_cpu) +{ + uint32_t i; + CpuTimes *ret = NULL, *c = NULL; + double user,system,idle,dpc,interrupt; + ret = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + check_mem(ret); + idle = user = system = interrupt = dpc = 0; + 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; + 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) + \ + (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); + data = (CpuTimes*)calloc(1,sizeof(CpuTimes)); + check_mem(data); + data->idle=idle; + data->system=system; + data->user=user; + + percpu = per_cpu_times(); + check_mem(percpu); + percpu_summed = sum_per_cpu_times(percpu); + free(percpu); + check_mem(percpu_summed); + data->interrupt = percpu_summed->interrupt; + data->dpc= percpu_summed->dpc; + 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) +{ + 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; + cpustats *ret = NULL; + 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 = (_SYSTEM_INTERRUPT_INFORMATION *)calloc(si.dwNumberOfProcessors, sizeof(_SYSTEM_INTERRUPT_INFORMATION)); + + 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); + + + 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; +} +/*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; + 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); + } + } + free(t2); + return ret; +error: + if (tmp) + free(tmp); + if (t2) + free(t2); + if (ret) + free(ret); + return NULL; +} + +uint32_t *pids(uint32_t *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 = (DWORD *)calloc(1, 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); + 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; + } + CloseHandle(hProcess); + return -1; +} + +bool pid_exists(pid_t pid) +{ + int status; + status = pid_is_running(pid); + check(status!=-1,"Exception raised in pid_is_running"); + return status; + error: + 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); + check_mem(pAddresses); + + 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)); + + check(dwRetVal == NO_ERROR, "GetAdaptersAddresses() syscall failed."); + return pAddresses; +error: + if (pAddresses) + free(pAddresses); + return NULL; +} + + +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 + MIB_IFROW *pIfRow = NULL; +#endif + + PIP_ADAPTER_ADDRESSES pAddresses = NULL; + PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; + pAddresses = get_nic_addresses(); + if (pAddresses == NULL) + goto error; + pCurrAddresses = pAddresses; + 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) { + +#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 + + check_mem(pIfRow) + +#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 + + check(dwRetVal == NO_ERROR, "GetIfEntry() or GetIfEntry2() syscalls failed."); + +#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 + + len = wcslen(pCurrAddresses->FriendlyName); + pCurrAddresses->FriendlyName[len] = '\0'; + nc->name = ConvertWcharToChar(pCurrAddresses->FriendlyName); + 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_net_iocounter_info(NetIOCounterInfo *ret) +{ + uint32_t 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 = NULL; + NetIOCounters *r = NULL,*c =NULL; + uint32_t i; + sum =(NetIOCounterInfo*) calloc(1,sizeof(NetIOCounterInfo)); + check_mem(sum); + r = (NetIOCounters*) calloc(1,sizeof(NetIOCounters)); + check_mem(r); + sum->iocounters = r; + sum->nitems = 1; + + 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_net_iocounter_info(info); + return sum; +error: + if(sum) + free(sum); + if(r) + free(r); + return info; +} +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 }; + 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_pid_parent_map(ret); + if (handle) + CloseHandle(handle); + return NULL; +} +pid_t ppid(pid_t pid) +{ + 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++) + { + if (map->pid[i] == pid) + { + ret = map->ppid[i]; + break; + } + } + check(i != map->nitems, "pid not found in the list of running process"); + free_pid_parent_map(map); + return ret; +error: + if (map) + free_pid_parent_map(map); + return -1; +} +TCHAR *convert_dos_path(TCHAR * path) +{ + 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) + { + 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++; + } + ret = (TCHAR *)calloc(100, sizeof(TCHAR)); + check_mem(ret); + check(_stprintf(ret,TEXT("%hs%hs"), driveletter, devicepath), "unable to join driveletter and rawdrive"); + free(devicepath); + return ret; +error: + if (ret) + free(ret); + return NULL; +} +int +pid_in_pids(DWORD pid) { + DWORD *proclist = NULL; + DWORD numberOfReturnedPIDs; + DWORD i; + + 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; + PCHAR 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); + free(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); + free(err); + return -1; +} + +HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { + HANDLE hProcess; + PCHAR err = NULL; + int ret; + if (pid == 0) // otherwise we'd get NoSuchProcess + { + SetLastError(ERROR_ACCESS_DENIED); + return NULL; + } + hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); + ret = is_phandle_running(hProcess, pid); + if (ret == 1) + return hProcess; + else if(ret == 0) + { + err = GetError(); + SetLastError(ERROR_NOSUCHPROCESS); + goto error; + } + else + { + goto error; + } +error: + if (err) + free(err); + return NULL; + +} + +char *get_cmdline(long pid) { + char *ret = NULL; + int32_t pid_running; + HANDLE hProcess = NULL; + PVOID pebAddress; + PVOID rtlUserProcParamsAddress; + UNICODE_STRING commandLine; + WCHAR *commandLineContents = NULL; + static _NtQueryInformationProcess NtQueryInformationProcess = NULL; + PROCESS_BASIC_INFORMATION pbi; + PCHAR err = NULL; + if (pid == 0 || pid == 4) + { + return NULL; + } + pid_running = pid_is_running(pid); + if ((pid_running == -1) || (pid_running == 0)) + { + SetLastError(ERROR_NOSUCHPROCESS); + return NULL; + } + 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) * sizeof(WCHAR)); + 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); + 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: + if(commandLineContents) + free(commandLineContents); + + err = GetError(); log_err("%s", err); free(err); + return NULL; +} + + +char *exe(pid_t pid) { + HANDLE hProcess = NULL; + TCHAR *tmp; + WCHAR tmpexe[MAX_PATH]; + TCHAR exe[MAX_PATH]; + PCHAR err = NULL; + char *ret = NULL; + if (pid == 0 || pid == 4) + { + SetLastError(ERROR_ACCESS_DENIED); + goto error; + } + else + { + 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); + } + 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); + free(err);; + if(hProcess) + CloseHandle(hProcess); + return NULL; +} +char *name(pid_t pid) +{ + /*"""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; +} +/* +* Return process username as a "DOMAIN//USERNAME" string. +*/ +char *Username(pid_t pid) +{ + 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; + 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; + 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); + 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; + } + 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); + free(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); + if (Name) + free(Name); + if (Dname) + free(Dname); + 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; + 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 || + 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); + free(err);; + return 20; +} + +/* +* Get process priority as a enum proc_priority. +*/ +enum proc_priority nice(pid_t pid) +{ + DWORD priority; + HANDLE hProcess; + int32_t value; + PCHAR 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); + free(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; + PCHAR 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); + free(err); + if(hProcess) + CloseHandle(hProcess); + return -1; +} + +/* +* 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: + if(process_info) + free_process(process_info); + return NULL; +} +void free_process(Process *p) +{ + 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 new file mode 100644 index 0000000..a7797c3 --- /dev/null +++ b/pslib_windows.h @@ -0,0 +1,495 @@ +#pragma once + +#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; +#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 { + 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; + 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; + + + 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. 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) 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) 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] + + + + 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 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