| /* |
| * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Windows platform-specific module methods for _psutil_mswindows |
| */ |
| |
| // Fixes clash between winsock2.h and windows.h |
| #define WIN32_LEAN_AND_MEAN |
| |
| #include <Python.h> |
| #include <windows.h> |
| #include <Psapi.h> |
| #include <time.h> |
| #include <lm.h> |
| #include <WinIoCtl.h> |
| #include <tchar.h> |
| #include <tlhelp32.h> |
| #include <winsock2.h> |
| #include <iphlpapi.h> |
| #include <wtsapi32.h> |
| |
| // Link with Iphlpapi.lib |
| #pragma comment(lib, "IPHLPAPI.lib") |
| |
| #include "_psutil_mswindows.h" |
| #include "_psutil_common.h" |
| #include "arch/mswindows/security.h" |
| #include "arch/mswindows/process_info.h" |
| #include "arch/mswindows/process_handles.h" |
| #include "arch/mswindows/ntextapi.h" |
| |
| |
| /* |
| * Return a Python float representing the system uptime expressed in seconds |
| * since the epoch. |
| */ |
| static PyObject* |
| get_system_boot_time(PyObject* self, PyObject* args) |
| { |
| double uptime; |
| time_t pt; |
| FILETIME fileTime; |
| long long ll; |
| |
| GetSystemTimeAsFileTime(&fileTime); |
| |
| /* |
| HUGE thanks to: |
| http://johnstewien.spaces.live.com/blog/cns!E6885DB5CEBABBC8!831.entry |
| |
| This function converts the FILETIME structure to the 32 bit |
| Unix time structure. |
| The time_t is a 32-bit value for the number of seconds since |
| January 1, 1970. A FILETIME is a 64-bit for the number of |
| 100-nanosecond periods since January 1, 1601. Convert by |
| subtracting the number of 100-nanosecond period betwee 01-01-1970 |
| and 01-01-1601, from time_t the divide by 1e+7 to get to the same |
| base granularity. |
| */ |
| ll = (((LONGLONG)(fileTime.dwHighDateTime)) << 32) + fileTime.dwLowDateTime; |
| pt = (time_t)((ll - 116444736000000000ull) / 10000000ull); |
| |
| // XXX - By using GetTickCount() time will wrap around to zero if the |
| // system is run continuously for 49.7 days. |
| uptime = GetTickCount() / 1000.00f; |
| return Py_BuildValue("d", (double)pt - uptime); |
| } |
| |
| |
| /* |
| * Return 1 if PID exists in the current process list, else 0. |
| */ |
| static PyObject* |
| pid_exists(PyObject* self, PyObject* args) |
| { |
| long pid; |
| int status; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| status = psutil_pid_is_running(pid); |
| if (-1 == status) { |
| return NULL; // exception raised in psutil_pid_is_running() |
| } |
| return PyBool_FromLong(status); |
| } |
| |
| |
| /* |
| * Return a Python list of all the PIDs running on the system. |
| */ |
| static PyObject* |
| get_pid_list(PyObject* self, PyObject* args) |
| { |
| DWORD *proclist = NULL; |
| DWORD numberOfReturnedPIDs; |
| DWORD i; |
| PyObject* pid = NULL; |
| PyObject* retlist = PyList_New(0); |
| |
| if (retlist == NULL) { |
| return NULL; |
| } |
| proclist = psutil_get_pids(&numberOfReturnedPIDs); |
| if (NULL == proclist) { |
| goto error; |
| } |
| |
| for (i = 0; i < numberOfReturnedPIDs; i++) { |
| pid = Py_BuildValue("I", proclist[i]); |
| if (!pid) |
| goto error; |
| if (PyList_Append(retlist, pid)) |
| goto error; |
| Py_DECREF(pid); |
| } |
| |
| // free C array allocated for PIDs |
| free(proclist); |
| return retlist; |
| |
| error: |
| Py_XDECREF(pid); |
| Py_DECREF(retlist); |
| if (proclist != NULL) |
| free(proclist); |
| return NULL; |
| } |
| |
| |
| /* |
| * Kill a process given its PID. |
| */ |
| static PyObject* |
| kill_process(PyObject* self, PyObject* args) |
| { |
| HANDLE hProcess; |
| long pid; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (pid == 0) { |
| return AccessDenied(); |
| } |
| |
| hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); |
| if (hProcess == NULL) { |
| if (GetLastError() == ERROR_INVALID_PARAMETER) { |
| // see http://code.google.com/p/psutil/issues/detail?id=24 |
| NoSuchProcess(); |
| } |
| else { |
| PyErr_SetFromWindowsErr(0); |
| } |
| return NULL; |
| } |
| |
| // kill the process |
| if (! TerminateProcess(hProcess, 0)) { |
| PyErr_SetFromWindowsErr(0); |
| CloseHandle(hProcess); |
| return NULL; |
| } |
| |
| CloseHandle(hProcess); |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| |
| /* |
| * Wait for process to terminate and return its exit code. |
| */ |
| static PyObject* |
| process_wait(PyObject* self, PyObject* args) |
| { |
| HANDLE hProcess; |
| DWORD ExitCode; |
| DWORD retVal; |
| long pid; |
| long timeout; |
| |
| if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) { |
| return NULL; |
| } |
| if (pid == 0) { |
| return AccessDenied(); |
| } |
| |
| hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); |
| if (hProcess == NULL) { |
| if (GetLastError() == ERROR_INVALID_PARAMETER) { |
| // no such process; we do not want to raise NSP but |
| // return None instead. |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| else { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| } |
| |
| // wait until the process has terminated |
| Py_BEGIN_ALLOW_THREADS |
| retVal = WaitForSingleObject(hProcess, timeout); |
| Py_END_ALLOW_THREADS |
| |
| if (retVal == WAIT_FAILED) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(GetLastError()); |
| } |
| if (retVal == WAIT_TIMEOUT) { |
| CloseHandle(hProcess); |
| return Py_BuildValue("l", WAIT_TIMEOUT); |
| } |
| |
| // get the exit code; note: subprocess module (erroneously?) uses |
| // what returned by WaitForSingleObject |
| if (GetExitCodeProcess(hProcess, &ExitCode) == 0) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(GetLastError()); |
| } |
| CloseHandle(hProcess); |
| #if PY_MAJOR_VERSION >= 3 |
| return PyLong_FromLong((long) ExitCode); |
| #else |
| return PyInt_FromLong((long) ExitCode); |
| #endif |
| } |
| |
| |
| /* |
| * Return a Python tuple (user_time, kernel_time) |
| */ |
| static PyObject* |
| get_process_cpu_times(PyObject* self, PyObject* args) |
| { |
| long pid; |
| HANDLE hProcess; |
| FILETIME ftCreate, ftExit, ftKernel, ftUser; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| hProcess = psutil_handle_from_pid(pid); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { |
| CloseHandle(hProcess); |
| if (GetLastError() == ERROR_ACCESS_DENIED) { |
| // usually means the process has died so we throw a NoSuchProcess |
| // here |
| return NoSuchProcess(); |
| } |
| else { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| } |
| |
| CloseHandle(hProcess); |
| |
| /* |
| user and kernel times are represented as a FILETIME structure wich contains |
| a 64-bit value representing the number of 100-nanosecond intervals since |
| January 1, 1601 (UTC). |
| http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx |
| |
| To convert it into a float representing the seconds that the process has |
| executed in user/kernel mode I borrowed the code below from Python's |
| Modules/posixmodule.c |
| */ |
| |
| return Py_BuildValue( |
| "(dd)", |
| (double)(ftUser.dwHighDateTime*429.4967296 + \ |
| ftUser.dwLowDateTime*1e-7), |
| (double)(ftKernel.dwHighDateTime*429.4967296 + \ |
| ftKernel.dwLowDateTime*1e-7) |
| ); |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject* |
| get_process_cpu_times_2(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| double user, kernel; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| user = (double)process->UserTime.HighPart * 429.4967296 + \ |
| (double)process->UserTime.LowPart * 1e-7; |
| kernel = (double)process->KernelTime.HighPart * 429.4967296 + \ |
| (double)process->KernelTime.LowPart * 1e-7; |
| free(buffer); |
| return Py_BuildValue("(dd)", user, kernel); |
| } |
| |
| |
| /* |
| * Return a Python float indicating the process create time expressed in |
| * seconds since the epoch. |
| */ |
| static PyObject* |
| get_process_create_time(PyObject* self, PyObject* args) |
| { |
| long pid; |
| long long unix_time; |
| DWORD exitCode; |
| HANDLE hProcess; |
| BOOL ret; |
| FILETIME ftCreate, ftExit, ftKernel, ftUser; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| // special case for PIDs 0 and 4, return BOOT_TIME |
| if (0 == pid || 4 == pid) { |
| return get_system_boot_time(NULL, NULL); |
| } |
| |
| hProcess = psutil_handle_from_pid(pid); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { |
| CloseHandle(hProcess); |
| if (GetLastError() == ERROR_ACCESS_DENIED) { |
| // usually means the process has died so we throw a NoSuchProcess here |
| return NoSuchProcess(); |
| } |
| else { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| } |
| |
| // Make sure the process is not gone as OpenProcess alone seems to be |
| // unreliable in doing so (it seems a previous call to p.wait() makes |
| // it unreliable). |
| // This check is important as creation time is used to make sure the |
| // process is still running. |
| ret = GetExitCodeProcess(hProcess, &exitCode); |
| CloseHandle(hProcess); |
| if (ret != 0) { |
| if (exitCode != STILL_ACTIVE) { |
| return NoSuchProcess(); |
| } |
| } |
| else { |
| // Ignore access denied as it means the process is still alive. |
| // For all other errors, we want an exception. |
| if (GetLastError() != ERROR_ACCESS_DENIED) { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| } |
| |
| /* |
| 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 Py_BuildValue("d", (double)unix_time); |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject* |
| get_process_create_time_2(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| long long unix_time; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| // special case for PIDs 0 and 4, return BOOT_TIME |
| if (0 == pid || 4 == pid) { |
| return get_system_boot_time(NULL, NULL); |
| } |
| /* |
| 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. |
| */ |
| unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32; |
| unix_time += process->CreateTime.LowPart - 116444736000000000LL; |
| unix_time /= 10000000; |
| free(buffer); |
| return Py_BuildValue("d", (double)unix_time); |
| } |
| |
| |
| /* |
| * Return a Python integer indicating the number of CPUs on the system. |
| */ |
| static PyObject* |
| get_num_cpus(PyObject* self, PyObject* args) |
| { |
| SYSTEM_INFO system_info; |
| system_info.dwNumberOfProcessors = 0; |
| |
| GetSystemInfo(&system_info); |
| if (system_info.dwNumberOfProcessors == 0){ |
| // GetSystemInfo failed for some reason; return 1 as default |
| return Py_BuildValue("I", 1); |
| } |
| return Py_BuildValue("I", system_info.dwNumberOfProcessors); |
| } |
| |
| /* |
| * Return process name as a Python string. |
| */ |
| static PyObject* |
| get_process_name(PyObject* self, PyObject* args) { |
| long pid; |
| int pid_return; |
| PyObject* name; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| if (pid == 0) { |
| return Py_BuildValue("s", "System Idle Process"); |
| } |
| else if (pid == 4) { |
| return Py_BuildValue("s", "System"); |
| } |
| |
| pid_return = psutil_pid_is_running(pid); |
| if (pid_return == 0) { |
| return NoSuchProcess(); |
| } |
| if (pid_return == -1) { |
| return NULL; |
| } |
| |
| name = psutil_get_name(pid); |
| if (name == NULL) { |
| return NULL; // exception set in psutil_get_name() |
| } |
| return name; |
| } |
| |
| |
| /* |
| * Return process parent pid as a Python integer. |
| */ |
| static PyObject* |
| get_process_ppid(PyObject* self, PyObject* args) { |
| long pid; |
| int pid_return; |
| PyObject* ppid; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if ((pid == 0) || (pid == 4)) { |
| return Py_BuildValue("l", 0); |
| } |
| |
| pid_return = psutil_pid_is_running(pid); |
| if (pid_return == 0) { |
| return NoSuchProcess(); |
| } |
| if (pid_return == -1) { |
| return NULL; |
| } |
| |
| ppid = psutil_get_ppid(pid); |
| if (ppid == NULL) { |
| return NULL; // exception set in psutil_get_ppid() |
| } |
| return ppid; |
| } |
| |
| /* |
| * Return process cmdline as a Python list of cmdline arguments. |
| */ |
| static PyObject* |
| get_process_cmdline(PyObject* self, PyObject* args) { |
| long pid; |
| int pid_return; |
| PyObject* arglist; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if ((pid == 0) || (pid == 4)) { |
| return Py_BuildValue("[]"); |
| } |
| |
| pid_return = psutil_pid_is_running(pid); |
| if (pid_return == 0) { |
| return NoSuchProcess(); |
| } |
| if (pid_return == -1) { |
| return NULL; |
| } |
| |
| // XXX the assumptio below probably needs to go away |
| |
| // May fail any of several ReadProcessMemory calls etc. and not indicate |
| // a real problem so we ignore any errors and just live without commandline |
| arglist = psutil_get_arg_list(pid); |
| if ( NULL == arglist ) { |
| // carry on anyway, clear any exceptions too |
| PyErr_Clear(); |
| return Py_BuildValue("[]"); |
| } |
| |
| return arglist; |
| } |
| |
| |
| /* |
| * Return process executable path. |
| */ |
| static PyObject* |
| get_process_exe(PyObject* self, PyObject* args) { |
| long pid; |
| HANDLE hProcess; |
| wchar_t exe[MAX_PATH]; |
| DWORD nSize = MAX_PATH; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); |
| if (NULL == hProcess) { |
| return NULL; |
| } |
| |
| if (GetProcessImageFileName(hProcess, &exe, nSize) == 0) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| CloseHandle(hProcess); |
| return Py_BuildValue("s", exe); |
| } |
| |
| |
| /* |
| * Return process memory information as a Python tuple. |
| */ |
| static PyObject* |
| get_process_memory_info(PyObject* self, PyObject* args) |
| { |
| HANDLE hProcess; |
| DWORD pid; |
| #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 |
| PROCESS_MEMORY_COUNTERS_EX cnt; |
| #else |
| PROCESS_MEMORY_COUNTERS cnt; |
| #endif |
| SIZE_T private = 0; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| hProcess = psutil_handle_from_pid(pid); |
| if (NULL == hProcess) { |
| return NULL; |
| } |
| |
| if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| #if (_WIN32_WINNT >= 0x0501) |
| private = cnt.PrivateUsage; |
| #endif |
| |
| CloseHandle(hProcess); |
| |
| // py 2.4 |
| #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION <= 4) |
| return Py_BuildValue("(kIIIIIIIII)", |
| cnt.PageFaultCount, |
| (unsigned int)cnt.PeakWorkingSetSize, |
| (unsigned int)cnt.WorkingSetSize, |
| (unsigned int)cnt.QuotaPeakPagedPoolUsage, |
| (unsigned int)cnt.QuotaPagedPoolUsage, |
| (unsigned int)cnt.QuotaPeakNonPagedPoolUsage, |
| (unsigned int)cnt.QuotaNonPagedPoolUsage, |
| (unsigned int)cnt.PagefileUsage, |
| (unsigned int)cnt.PeakPagefileUsage, |
| (unsigned int)private); |
| #else |
| // py >= 2.5 |
| return Py_BuildValue("(knnnnnnnnn)", |
| cnt.PageFaultCount, |
| cnt.PeakWorkingSetSize, |
| cnt.WorkingSetSize, |
| cnt.QuotaPeakPagedPoolUsage, |
| cnt.QuotaPagedPoolUsage, |
| cnt.QuotaPeakNonPagedPoolUsage, |
| cnt.QuotaNonPagedPoolUsage, |
| cnt.PagefileUsage, |
| cnt.PeakPagefileUsage, |
| private); |
| #endif |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject* |
| get_process_memory_info_2(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| ULONG m0; |
| SIZE_T m1, m2, m3, m4, m5, m6, m7, m8, m9; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| m0 = process->PageFaultCount; |
| m1 = process->PeakWorkingSetSize; |
| m2 = process->WorkingSetSize; |
| m3 = process->QuotaPeakPagedPoolUsage; |
| m4 = process->QuotaPagedPoolUsage; |
| m5 = process->QuotaPeakNonPagedPoolUsage; |
| m6 = process->QuotaNonPagedPoolUsage; |
| m7 = process->PagefileUsage; |
| m8 = process->PeakPagefileUsage; |
| #if (_WIN32_WINNT >= 0x0501) |
| m9 = process->PrivatePageCount; // private me |
| #else |
| m9 = 0; |
| #endif |
| free(buffer); |
| |
| // py 2.4 |
| #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION <= 4) |
| return Py_BuildValue("(kIIIIIIIII)", |
| (unsigned int)m0, (unsigned int)m1, (unsigned int)m2, (unsigned int)m3, |
| (unsigned int)m4, (unsigned int)m5, (unsigned int)m6, (unsigned int)m7, |
| (unsigned int)m8, (unsigned int)m9); |
| #else |
| return Py_BuildValue("(knnnnnnnnn)", |
| m0, m1, m2, m3, m4, m5, m6, m7, m8, m9); |
| #endif |
| } |
| |
| |
| /* |
| * Return a Python integer indicating the total amount of physical memory |
| * in bytes. |
| */ |
| static PyObject* |
| get_virtual_mem(PyObject* self, PyObject* args) |
| { |
| MEMORYSTATUSEX memInfo; |
| memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
| |
| if (! GlobalMemoryStatusEx(&memInfo) ) { |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| return Py_BuildValue("(LLLLLL)", |
| memInfo.ullTotalPhys, // total |
| memInfo.ullAvailPhys, // avail |
| memInfo.ullTotalPageFile, // total page file |
| memInfo.ullAvailPageFile, // avail page file |
| memInfo.ullTotalVirtual, // total virtual |
| memInfo.ullAvailVirtual // avail virtual |
| ); |
| } |
| |
| |
| #define LO_T ((float)1e-7) |
| #define HI_T (LO_T*4294967296.0) |
| |
| |
| /* |
| * Return a Python list of tuples representing user, kernel and idle |
| * CPU times for every CPU on the system. |
| */ |
| static PyObject* |
| get_system_cpu_times(PyObject* self, PyObject* args) |
| { |
| float idle, kernel, user; |
| typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG); |
| NTQSI_PROC NtQuerySystemInformation; |
| HINSTANCE hNtDll; |
| SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; |
| SYSTEM_INFO si; |
| UINT i; |
| PyObject *arg = NULL; |
| PyObject *retlist = PyList_New(0); |
| |
| if (retlist == NULL) |
| return NULL; |
| |
| // dynamic linking is mandatory to use NtQuerySystemInformation |
| hNtDll = LoadLibrary(TEXT("ntdll.dll")); |
| if (hNtDll != NULL) { |
| // gets NtQuerySystemInformation address |
| NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( |
| hNtDll, "NtQuerySystemInformation"); |
| |
| if (NtQuerySystemInformation != NULL) |
| { |
| // 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)); |
| if (sppi != NULL) |
| { |
| // gets cpu time informations |
| if (0 == NtQuerySystemInformation( |
| SystemProcessorPerformanceInformation, |
| sppi, |
| si.dwNumberOfProcessors * sizeof |
| (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), |
| NULL) |
| ) |
| { |
| // computes system global times summing each processor value |
| idle = user = kernel = 0; |
| for (i=0; i<si.dwNumberOfProcessors; i++) { |
| arg = NULL; |
| 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)); |
| // kernel time includes idle time on windows |
| // we return only busy kernel time subtracting |
| // idle time from kernel time |
| arg = Py_BuildValue("(ddd)", user, |
| kernel - idle, |
| idle); |
| if (!arg) |
| goto error; |
| if (PyList_Append(retlist, arg)) |
| goto error; |
| Py_DECREF(arg); |
| } |
| free(sppi); |
| FreeLibrary(hNtDll); |
| return retlist; |
| |
| } // END NtQuerySystemInformation |
| } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION |
| } // END GetProcAddress |
| } // END LoadLibrary |
| goto error; |
| |
| error: |
| Py_XDECREF(arg); |
| Py_DECREF(retlist); |
| if (sppi) { |
| free(sppi); |
| } |
| if (hNtDll) { |
| FreeLibrary(hNtDll); |
| } |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| |
| |
| /* |
| * Return process current working directory as a Python string. |
| */ |
| |
| static PyObject* |
| get_process_cwd(PyObject* self, PyObject* args) |
| { |
| long pid; |
| HANDLE processHandle = NULL; |
| PVOID pebAddress; |
| PVOID rtlUserProcParamsAddress; |
| UNICODE_STRING currentDirectory; |
| WCHAR *currentDirectoryContent = NULL; |
| PyObject *returnPyObj = NULL; |
| PyObject *cwd_from_wchar = NULL; |
| PyObject *cwd = NULL; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| processHandle = psutil_handle_from_pid(pid); |
| if (processHandle == NULL) { |
| return NULL; |
| } |
| |
| pebAddress = psutil_get_peb_address(processHandle); |
| |
| // get the address of ProcessParameters |
| #ifdef _WIN64 |
| if (!ReadProcessMemory(processHandle, (PCHAR)pebAddress + 32, |
| &rtlUserProcParamsAddress, sizeof(PVOID), NULL)) |
| #else |
| if (!ReadProcessMemory(processHandle, (PCHAR)pebAddress + 0x10, |
| &rtlUserProcParamsAddress, sizeof(PVOID), NULL)) |
| #endif |
| { |
| CloseHandle(processHandle); |
| |
| if (GetLastError() == ERROR_PARTIAL_COPY) { |
| // this occurs quite often with system processes |
| return AccessDenied(); |
| } |
| else { |
| return PyErr_SetFromWindowsErr(0); |
| } |
| } |
| |
| // Read the currentDirectory UNICODE_STRING structure. |
| // 0x24 refers to "CurrentDirectoryPath" of RTL_USER_PROCESS_PARAMETERS |
| // structure, see: |
| // http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/ |
| #ifdef _WIN64 |
| if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 56, |
| ¤tDirectory, sizeof(currentDirectory), NULL)) |
| #else |
| if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 0x24, |
| ¤tDirectory, sizeof(currentDirectory), NULL)) |
| #endif |
| { |
| CloseHandle(processHandle); |
| if (GetLastError() == ERROR_PARTIAL_COPY) { |
| // this occurs quite often with system processes |
| return AccessDenied(); |
| } |
| else { |
| return PyErr_SetFromWindowsErr(0); |
| } |
| } |
| |
| // allocate memory to hold cwd |
| currentDirectoryContent = (WCHAR *)malloc(currentDirectory.Length+1); |
| if (currentDirectoryContent == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| |
| // read cwd |
| if (!ReadProcessMemory(processHandle, currentDirectory.Buffer, |
| currentDirectoryContent, currentDirectory.Length, NULL)) |
| { |
| if (GetLastError() == ERROR_PARTIAL_COPY) { |
| // this occurs quite often with system processes |
| AccessDenied(); |
| } |
| else { |
| PyErr_SetFromWindowsErr(0); |
| } |
| goto error; |
| } |
| |
| // null-terminate the string to prevent wcslen from returning |
| // incorrect length the length specifier is in characters, but |
| // currentDirectory.Length is in bytes |
| currentDirectoryContent[(currentDirectory.Length/sizeof(WCHAR))] = '\0'; |
| |
| // convert wchar array to a Python unicode string, and then to UTF8 |
| cwd_from_wchar = PyUnicode_FromWideChar(currentDirectoryContent, |
| wcslen(currentDirectoryContent)); |
| if (cwd_from_wchar == NULL) |
| goto error; |
| |
| #if PY_MAJOR_VERSION >= 3 |
| cwd = PyUnicode_FromObject(cwd_from_wchar); |
| #else |
| cwd = PyUnicode_AsUTF8String(cwd_from_wchar); |
| #endif |
| if (cwd == NULL) |
| goto error; |
| |
| // decrement the reference count on our temp unicode str to avoid |
| // mem leak |
| returnPyObj = Py_BuildValue("N", cwd); |
| if (!returnPyObj) |
| goto error; |
| |
| Py_DECREF(cwd_from_wchar); |
| |
| CloseHandle(processHandle); |
| free(currentDirectoryContent); |
| return returnPyObj; |
| |
| error: |
| Py_XDECREF(cwd_from_wchar); |
| Py_XDECREF(cwd); |
| Py_XDECREF(returnPyObj); |
| if (currentDirectoryContent != NULL) |
| free(currentDirectoryContent); |
| if (processHandle != NULL) |
| CloseHandle(processHandle); |
| return NULL; |
| } |
| |
| |
| /* |
| * Resume or suspends a process |
| */ |
| int |
| suspend_resume_process(DWORD pid, int suspend) |
| { |
| // a huge thanks to http://www.codeproject.com/KB/threads/pausep.aspx |
| HANDLE hThreadSnap = NULL; |
| THREADENTRY32 te32 = {0}; |
| |
| if (pid == 0) { |
| AccessDenied(); |
| return FALSE; |
| } |
| |
| hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
| if (hThreadSnap == INVALID_HANDLE_VALUE) { |
| PyErr_SetFromWindowsErr(0); |
| return FALSE; |
| } |
| |
| // Fill in the size of the structure before using it |
| te32.dwSize = sizeof(THREADENTRY32); |
| |
| if (! Thread32First(hThreadSnap, &te32)) { |
| PyErr_SetFromWindowsErr(0); |
| CloseHandle(hThreadSnap); |
| return FALSE; |
| } |
| |
| // Walk the thread snapshot to find all threads of the process. |
| // If the thread belongs to the process, add its information |
| // to the display list. |
| do |
| { |
| if (te32.th32OwnerProcessID == pid) |
| { |
| HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, |
| te32.th32ThreadID); |
| if (hThread == NULL) { |
| PyErr_SetFromWindowsErr(0); |
| CloseHandle(hThread); |
| CloseHandle(hThreadSnap); |
| return FALSE; |
| } |
| if (suspend == 1) |
| { |
| if (SuspendThread(hThread) == (DWORD)-1) { |
| PyErr_SetFromWindowsErr(0); |
| CloseHandle(hThread); |
| CloseHandle(hThreadSnap); |
| return FALSE; |
| } |
| } |
| else |
| { |
| if (ResumeThread(hThread) == (DWORD)-1) { |
| PyErr_SetFromWindowsErr(0); |
| CloseHandle(hThread); |
| CloseHandle(hThreadSnap); |
| return FALSE; |
| } |
| } |
| CloseHandle(hThread); |
| } |
| } while (Thread32Next(hThreadSnap, &te32)); |
| |
| CloseHandle(hThreadSnap); |
| return TRUE; |
| } |
| |
| |
| static PyObject* |
| suspend_process(PyObject* self, PyObject* args) |
| { |
| long pid; |
| int suspend = 1; |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| if (! suspend_resume_process(pid, suspend)) { |
| return NULL; |
| } |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| |
| static PyObject* |
| resume_process(PyObject* self, PyObject* args) |
| { |
| long pid; |
| int suspend = 0; |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| if (! suspend_resume_process(pid, suspend)) { |
| return NULL; |
| } |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| |
| static PyObject* |
| get_process_num_threads(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| int num; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| num = (int)process->NumberOfThreads; |
| free(buffer); |
| return Py_BuildValue("i", num); |
| } |
| |
| |
| static PyObject* |
| get_process_threads(PyObject* self, PyObject* args) |
| { |
| HANDLE hThread; |
| THREADENTRY32 te32 = {0}; |
| long pid; |
| int pid_return; |
| int rc; |
| FILETIME ftDummy, ftKernel, ftUser; |
| PyObject* retList = PyList_New(0); |
| PyObject* pyTuple = NULL; |
| HANDLE hThreadSnap = NULL; |
| |
| if (retList == NULL) { |
| return NULL; |
| } |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| goto error; |
| } |
| if (pid == 0) { |
| // raise AD instead of returning 0 as procexp is able to |
| // retrieve useful information somehow |
| AccessDenied(); |
| goto error; |
| } |
| |
| pid_return = psutil_pid_is_running(pid); |
| if (pid_return == 0) { |
| NoSuchProcess(); |
| goto error; |
| } |
| if (pid_return == -1) { |
| goto error; |
| } |
| |
| hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
| if (hThreadSnap == INVALID_HANDLE_VALUE) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| // Fill in the size of the structure before using it |
| te32.dwSize = sizeof(THREADENTRY32); |
| |
| if (! Thread32First(hThreadSnap, &te32)) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| // Walk the thread snapshot to find all threads of the process. |
| // If the thread belongs to the process, increase the counter. |
| do |
| { |
| if (te32.th32OwnerProcessID == pid) |
| { |
| pyTuple = NULL; |
| hThread = NULL; |
| hThread = OpenThread(THREAD_QUERY_INFORMATION, |
| FALSE, te32.th32ThreadID); |
| if (hThread == NULL) { |
| // thread has disappeared on us |
| continue; |
| } |
| |
| rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser); |
| if (rc == 0) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| /* |
| user and kernel times are represented as a FILETIME structure |
| wich contains a 64-bit value representing the number of |
| 100-nanosecond intervals since January 1, 1601 (UTC). |
| http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx |
| |
| To convert it into a float representing the seconds that the |
| process has executed in user/kernel mode I borrowed the code |
| below from Python's Modules/posixmodule.c |
| */ |
| pyTuple = Py_BuildValue("kdd", |
| te32.th32ThreadID, |
| (double)(ftUser.dwHighDateTime*429.4967296 + \ |
| ftUser.dwLowDateTime*1e-7), |
| (double)(ftKernel.dwHighDateTime*429.4967296 + \ |
| ftKernel.dwLowDateTime*1e-7)); |
| if (!pyTuple) |
| goto error; |
| if (PyList_Append(retList, pyTuple)) |
| goto error; |
| Py_DECREF(pyTuple); |
| |
| CloseHandle(hThread); |
| } |
| } while (Thread32Next(hThreadSnap, &te32)); |
| |
| CloseHandle(hThreadSnap); |
| return retList; |
| |
| error: |
| Py_XDECREF(pyTuple); |
| Py_DECREF(retList); |
| if (hThread != NULL) |
| CloseHandle(hThread); |
| if (hThreadSnap != NULL) { |
| CloseHandle(hThreadSnap); |
| } |
| return NULL; |
| } |
| |
| |
| |
| static PyObject* |
| get_process_open_files(PyObject* self, PyObject* args) |
| { |
| long pid; |
| HANDLE processHandle; |
| DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| PyObject* filesList; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| processHandle = psutil_handle_from_pid_waccess(pid, access); |
| if (processHandle == NULL) { |
| return NULL; |
| } |
| |
| filesList = psutil_get_open_files(pid, processHandle); |
| CloseHandle(processHandle); |
| if (filesList == NULL) { |
| return PyErr_SetFromWindowsErr(0); |
| } |
| return filesList; |
| } |
| |
| |
| /* |
| Accept a filename's drive in native format like "\Device\HarddiskVolume1\" |
| and return the corresponding drive letter (e.g. "C:\\"). |
| If no match is found return an empty string. |
| */ |
| static PyObject* |
| win32_QueryDosDevice(PyObject* self, PyObject* args) |
| { |
| LPCTSTR lpDevicePath; |
| TCHAR d = TEXT('A'); |
| TCHAR szBuff[5]; |
| |
| if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) { |
| return NULL; |
| } |
| |
| while(d <= TEXT('Z')) |
| { |
| TCHAR szDeviceName[3] = {d,TEXT(':'),TEXT('\0')}; |
| TCHAR szTarget[512] = {0}; |
| if (QueryDosDevice(szDeviceName, szTarget, 511) != 0){ |
| //_tprintf (TEXT("%c:\\ => %s\n"), d, szTarget); |
| if(_tcscmp(lpDevicePath, szTarget) == 0) { |
| _stprintf(szBuff, TEXT("%c:"), d); |
| return Py_BuildValue("s", szBuff); |
| } |
| } |
| d++; |
| } |
| return Py_BuildValue("s", ""); |
| } |
| |
| /* |
| * Return process username as a "DOMAIN//USERNAME" string. |
| */ |
| static PyObject* |
| get_process_username(PyObject* self, PyObject* args) |
| { |
| long pid; |
| HANDLE processHandle; |
| HANDLE tokenHandle; |
| PTOKEN_USER user; |
| ULONG bufferSize; |
| PTSTR name; |
| ULONG nameSize; |
| PTSTR domainName; |
| ULONG domainNameSize; |
| SID_NAME_USE nameUse; |
| PTSTR fullName; |
| PyObject* returnObject; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| processHandle = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); |
| if (processHandle == NULL) { |
| return NULL; |
| } |
| |
| if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) { |
| CloseHandle(processHandle); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| CloseHandle(processHandle); |
| |
| /* Get the user SID. */ |
| |
| bufferSize = 0x100; |
| user = malloc(bufferSize); |
| if (user == NULL) { |
| return PyErr_NoMemory(); |
| } |
| |
| if (!GetTokenInformation(tokenHandle, |
| TokenUser, |
| user, |
| bufferSize, |
| &bufferSize)) |
| { |
| free(user); |
| user = malloc(bufferSize); |
| if (user == NULL) { |
| CloseHandle(tokenHandle); |
| return PyErr_NoMemory(); |
| } |
| if (!GetTokenInformation(tokenHandle, |
| TokenUser, |
| user, |
| bufferSize, |
| &bufferSize)) |
| { |
| free(user); |
| CloseHandle(tokenHandle); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| } |
| |
| CloseHandle(tokenHandle); |
| |
| /* Resolve the SID to a name. */ |
| |
| nameSize = 0x100; |
| domainNameSize = 0x100; |
| |
| name = malloc(nameSize * sizeof(TCHAR)); |
| if (name == NULL) |
| return PyErr_NoMemory(); |
| domainName = malloc(domainNameSize * sizeof(TCHAR)); |
| if (domainName == NULL) |
| return PyErr_NoMemory(); |
| |
| if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName, |
| &domainNameSize, &nameUse)) |
| { |
| free(name); |
| free(domainName); |
| name = malloc(nameSize * sizeof(TCHAR)); |
| if (name == NULL) |
| return PyErr_NoMemory(); |
| domainName = malloc(domainNameSize * sizeof(TCHAR)); |
| if (domainName == NULL) |
| return PyErr_NoMemory(); |
| if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName, |
| &domainNameSize, &nameUse)) |
| { |
| free(name); |
| free(domainName); |
| free(user); |
| |
| return PyErr_SetFromWindowsErr(0); |
| } |
| } |
| |
| nameSize = _tcslen(name); |
| domainNameSize = _tcslen(domainName); |
| |
| /* Build the full username string. */ |
| fullName = malloc((domainNameSize + 1 + nameSize + 1) * sizeof(TCHAR)); |
| if (fullName == NULL) { |
| free(name); |
| free(domainName); |
| free(user); |
| return PyErr_NoMemory(); |
| } |
| memcpy(fullName, domainName, domainNameSize); |
| fullName[domainNameSize] = '\\'; |
| memcpy(&fullName[domainNameSize + 1], name, nameSize); |
| fullName[domainNameSize + 1 + nameSize] = '\0'; |
| |
| returnObject = Py_BuildValue("s", fullName); |
| |
| free(fullName); |
| free(name); |
| free(domainName); |
| free(user); |
| |
| return returnObject; |
| } |
| |
| #define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) |
| |
| #ifndef AF_INET6 |
| #define AF_INET6 23 |
| #endif |
| |
| static char *state_to_string(ULONG state) |
| { |
| switch (state) |
| { |
| case MIB_TCP_STATE_CLOSED: |
| return "CLOSE"; |
| case MIB_TCP_STATE_LISTEN: |
| return "LISTEN"; |
| case MIB_TCP_STATE_SYN_SENT: |
| return "SYN_SENT"; |
| case MIB_TCP_STATE_SYN_RCVD: |
| return "SYN_RECV"; |
| case MIB_TCP_STATE_ESTAB: |
| return "ESTABLISHED"; |
| case MIB_TCP_STATE_FIN_WAIT1: |
| return "FIN_WAIT1"; |
| case MIB_TCP_STATE_FIN_WAIT2: |
| return "FIN_WAIT2"; |
| case MIB_TCP_STATE_CLOSE_WAIT: |
| return "CLOSE_WAIT"; |
| case MIB_TCP_STATE_CLOSING: |
| return "CLOSING"; |
| case MIB_TCP_STATE_LAST_ACK: |
| return "LAST_ACK"; |
| case MIB_TCP_STATE_TIME_WAIT: |
| return "TIME_WAIT"; |
| case MIB_TCP_STATE_DELETE_TCB: |
| return "DELETE_TCB"; |
| default: |
| return ""; |
| } |
| } |
| |
| /* mingw support */ |
| #ifndef _IPRTRMIB_H |
| typedef struct _MIB_TCP6ROW_OWNER_PID |
| { |
| UCHAR ucLocalAddr[16]; |
| DWORD dwLocalScopeId; |
| DWORD dwLocalPort; |
| UCHAR ucRemoteAddr[16]; |
| DWORD dwRemoteScopeId; |
| DWORD dwRemotePort; |
| DWORD dwState; |
| DWORD dwOwningPid; |
| } MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; |
| |
| typedef struct _MIB_TCP6TABLE_OWNER_PID |
| { |
| DWORD dwNumEntries; |
| MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; |
| } MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; |
| #endif |
| |
| #ifndef __IPHLPAPI_H__ |
| typedef struct in6_addr { |
| union { |
| UCHAR Byte[16]; |
| USHORT Word[8]; |
| } u; |
| } IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; |
| |
| |
| typedef enum _UDP_TABLE_CLASS { |
| UDP_TABLE_BASIC, |
| UDP_TABLE_OWNER_PID, |
| UDP_TABLE_OWNER_MODULE |
| } UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; |
| |
| |
| typedef struct _MIB_UDPROW_OWNER_PID { |
| DWORD dwLocalAddr; |
| DWORD dwLocalPort; |
| DWORD dwOwningPid; |
| } MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; |
| |
| typedef struct _MIB_UDPTABLE_OWNER_PID |
| { |
| DWORD dwNumEntries; |
| MIB_UDPROW_OWNER_PID table[ANY_SIZE]; |
| } MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; |
| #endif |
| /* end of mingw support */ |
| |
| typedef struct _MIB_UDP6ROW_OWNER_PID { |
| UCHAR ucLocalAddr[16]; |
| DWORD dwLocalScopeId; |
| DWORD dwLocalPort; |
| DWORD dwOwningPid; |
| } MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; |
| |
| typedef struct _MIB_UDP6TABLE_OWNER_PID |
| { |
| DWORD dwNumEntries; |
| MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; |
| } MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; |
| |
| |
| #define ConnDecrefPyObjs() Py_DECREF(_AF_INET); \ |
| Py_DECREF(_AF_INET6);\ |
| Py_DECREF(_SOCK_STREAM);\ |
| Py_DECREF(_SOCK_DGRAM); |
| |
| /* |
| * Return a list of network connections opened by a process |
| */ |
| static PyObject* |
| get_process_connections(PyObject* self, PyObject* args) |
| { |
| static long null_address[4] = { 0, 0, 0, 0 }; |
| |
| unsigned long pid; |
| PyObject* connectionsList; |
| PyObject* connectionTuple = NULL; |
| PyObject *af_filter = NULL; |
| PyObject *type_filter = NULL; |
| |
| PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); |
| PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); |
| PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); |
| PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); |
| |
| typedef PSTR (NTAPI *_RtlIpv4AddressToStringA)(struct in_addr *, |
| PSTR /* __out_ecount(16) */); |
| _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; |
| typedef PSTR (NTAPI *_RtlIpv6AddressToStringA)(struct in6_addr *, |
| PSTR /* __out_ecount(65) */); |
| _RtlIpv6AddressToStringA rtlIpv6AddressToStringA; |
| typedef DWORD (WINAPI *_GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, |
| TCP_TABLE_CLASS, ULONG); |
| _GetExtendedTcpTable getExtendedTcpTable; |
| typedef DWORD (WINAPI *_GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG, |
| UDP_TABLE_CLASS, ULONG); |
| _GetExtendedUdpTable getExtendedUdpTable; |
| PVOID table = NULL; |
| DWORD tableSize; |
| PMIB_TCPTABLE_OWNER_PID tcp4Table; |
| PMIB_UDPTABLE_OWNER_PID udp4Table; |
| PMIB_TCP6TABLE_OWNER_PID tcp6Table; |
| PMIB_UDP6TABLE_OWNER_PID udp6Table; |
| ULONG i; |
| CHAR addressBufferLocal[65]; |
| PyObject* addressTupleLocal = NULL; |
| CHAR addressBufferRemote[65]; |
| PyObject* addressTupleRemote = NULL; |
| |
| if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { |
| ConnDecrefPyObjs(); |
| return NULL; |
| } |
| |
| if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { |
| ConnDecrefPyObjs(); |
| PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); |
| return NULL; |
| } |
| |
| if (psutil_pid_is_running(pid) == 0) { |
| ConnDecrefPyObjs(); |
| return NoSuchProcess(); |
| } |
| |
| /* Import some functions. */ |
| { |
| HMODULE ntdll; |
| HMODULE iphlpapi; |
| |
| ntdll = LoadLibrary(TEXT("ntdll.dll")); |
| rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress(ntdll, |
| "RtlIpv4AddressToStringA"); |
| rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress(ntdll, |
| "RtlIpv6AddressToStringA"); |
| /* TODO: Check these two function pointers */ |
| |
| iphlpapi = LoadLibrary(TEXT("iphlpapi.dll")); |
| getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi, |
| "GetExtendedTcpTable"); |
| getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi, |
| "GetExtendedUdpTable"); |
| FreeLibrary(ntdll); |
| FreeLibrary(iphlpapi); |
| } |
| |
| if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) { |
| PyErr_SetString(PyExc_NotImplementedError, |
| "feature not supported on this Windows version"); |
| ConnDecrefPyObjs(); |
| return NULL; |
| } |
| |
| connectionsList = PyList_New(0); |
| if (connectionsList == NULL) { |
| ConnDecrefPyObjs(); |
| return NULL; |
| } |
| |
| /* TCP IPv4 */ |
| |
| if ((PySequence_Contains(af_filter, _AF_INET) == 1) && |
| (PySequence_Contains(type_filter, _SOCK_STREAM) == 1)) |
| { |
| table = NULL; |
| connectionTuple = NULL; |
| addressTupleLocal = NULL; |
| addressTupleRemote = NULL; |
| tableSize = 0; |
| getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, |
| TCP_TABLE_OWNER_PID_ALL, 0); |
| |
| table = malloc(tableSize); |
| if (table == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET, |
| TCP_TABLE_OWNER_PID_ALL, 0) == 0) |
| { |
| tcp4Table = table; |
| |
| for (i = 0; i < tcp4Table->dwNumEntries; i++) |
| { |
| if (tcp4Table->table[i].dwOwningPid != pid) { |
| continue; |
| } |
| |
| if (tcp4Table->table[i].dwLocalAddr != 0 || |
| tcp4Table->table[i].dwLocalPort != 0) |
| { |
| struct in_addr addr; |
| |
| addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; |
| rtlIpv4AddressToStringA(&addr, addressBufferLocal); |
| addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, |
| BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); |
| } |
| else |
| { |
| addressTupleLocal = PyTuple_New(0); |
| } |
| |
| if (addressTupleLocal == NULL) |
| goto error; |
| |
| // On Windows <= XP, remote addr is filled even if socket |
| // is in LISTEN mode in which case we just ignore it. |
| if ((tcp4Table->table[i].dwRemoteAddr != 0 || |
| tcp4Table->table[i].dwRemotePort != 0) && |
| (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) |
| { |
| struct in_addr addr; |
| |
| addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; |
| rtlIpv4AddressToStringA(&addr, addressBufferRemote); |
| addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote, |
| BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); |
| } |
| else |
| { |
| addressTupleRemote = PyTuple_New(0); |
| } |
| |
| if (addressTupleRemote == NULL) |
| goto error; |
| |
| connectionTuple = Py_BuildValue("(iiiNNs)", |
| -1, |
| AF_INET, |
| SOCK_STREAM, |
| addressTupleLocal, |
| addressTupleRemote, |
| state_to_string(tcp4Table->table[i].dwState) |
| ); |
| if (!connectionTuple) |
| goto error; |
| if (PyList_Append(connectionsList, connectionTuple)) |
| goto error; |
| Py_DECREF(connectionTuple); |
| } |
| } |
| |
| free(table); |
| } |
| |
| /* TCP IPv6 */ |
| |
| if ((PySequence_Contains(af_filter, _AF_INET6) == 1) && |
| (PySequence_Contains(type_filter, _SOCK_STREAM) == 1)) |
| { |
| table = NULL; |
| connectionTuple = NULL; |
| addressTupleLocal = NULL; |
| addressTupleRemote = NULL; |
| tableSize = 0; |
| getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, |
| TCP_TABLE_OWNER_PID_ALL, 0); |
| |
| table = malloc(tableSize); |
| if (table == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, |
| TCP_TABLE_OWNER_PID_ALL, 0) == 0) |
| { |
| tcp6Table = table; |
| |
| for (i = 0; i < tcp6Table->dwNumEntries; i++) |
| { |
| if (tcp6Table->table[i].dwOwningPid != pid) { |
| continue; |
| } |
| |
| if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || |
| tcp6Table->table[i].dwLocalPort != 0) |
| { |
| struct in6_addr addr; |
| |
| memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); |
| rtlIpv6AddressToStringA(&addr, addressBufferLocal); |
| addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, |
| BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); |
| } |
| else |
| { |
| addressTupleLocal = PyTuple_New(0); |
| } |
| |
| if (addressTupleLocal == NULL) |
| goto error; |
| |
| // On Windows <= XP, remote addr is filled even if socket |
| // is in LISTEN mode in which case we just ignore it. |
| if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) != 0 || |
| tcp6Table->table[i].dwRemotePort != 0) && |
| (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) |
| { |
| struct in6_addr addr; |
| |
| memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); |
| rtlIpv6AddressToStringA(&addr, addressBufferRemote); |
| addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote, |
| BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); |
| } |
| else |
| { |
| addressTupleRemote = PyTuple_New(0); |
| } |
| |
| if (addressTupleRemote == NULL) |
| goto error; |
| |
| connectionTuple = Py_BuildValue("(iiiNNs)", |
| -1, |
| AF_INET6, |
| SOCK_STREAM, |
| addressTupleLocal, |
| addressTupleRemote, |
| state_to_string(tcp6Table->table[i].dwState) |
| ); |
| if (!connectionTuple) |
| goto error; |
| if (PyList_Append(connectionsList, connectionTuple)) |
| goto error; |
| Py_DECREF(connectionTuple); |
| } |
| } |
| |
| free(table); |
| } |
| |
| /* UDP IPv4 */ |
| |
| if ((PySequence_Contains(af_filter, _AF_INET) == 1) && |
| (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1)) |
| { |
| table = NULL; |
| connectionTuple = NULL; |
| addressTupleLocal = NULL; |
| addressTupleRemote = NULL; |
| tableSize = 0; |
| getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, |
| UDP_TABLE_OWNER_PID, 0); |
| |
| table = malloc(tableSize); |
| if (table == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET, |
| UDP_TABLE_OWNER_PID, 0) == 0) |
| { |
| udp4Table = table; |
| |
| for (i = 0; i < udp4Table->dwNumEntries; i++) |
| { |
| if (udp4Table->table[i].dwOwningPid != pid) { |
| continue; |
| } |
| |
| if (udp4Table->table[i].dwLocalAddr != 0 || |
| udp4Table->table[i].dwLocalPort != 0) |
| { |
| struct in_addr addr; |
| |
| addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; |
| rtlIpv4AddressToStringA(&addr, addressBufferLocal); |
| addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, |
| BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); |
| } |
| else |
| { |
| addressTupleLocal = PyTuple_New(0); |
| } |
| |
| if (addressTupleLocal == NULL) |
| goto error; |
| |
| connectionTuple = Py_BuildValue("(iiiNNs)", |
| -1, |
| AF_INET, |
| SOCK_DGRAM, |
| addressTupleLocal, |
| PyTuple_New(0), |
| "" |
| ); |
| if (!connectionTuple) |
| goto error; |
| if (PyList_Append(connectionsList, connectionTuple)) |
| goto error; |
| Py_DECREF(connectionTuple); |
| } |
| } |
| |
| free(table); |
| } |
| |
| /* UDP IPv6 */ |
| |
| if ((PySequence_Contains(af_filter, _AF_INET6) == 1) && |
| (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1)) |
| { |
| table = NULL; |
| connectionTuple = NULL; |
| addressTupleLocal = NULL; |
| addressTupleRemote = NULL; |
| tableSize = 0; |
| getExtendedUdpTable(NULL, &tableSize, FALSE, |
| AF_INET6, UDP_TABLE_OWNER_PID, 0); |
| |
| table = malloc(tableSize); |
| if (table == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, |
| UDP_TABLE_OWNER_PID, 0) == 0) |
| { |
| udp6Table = table; |
| |
| for (i = 0; i < udp6Table->dwNumEntries; i++) |
| { |
| if (udp6Table->table[i].dwOwningPid != pid) { |
| continue; |
| } |
| |
| if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || |
| udp6Table->table[i].dwLocalPort != 0) |
| { |
| struct in6_addr addr; |
| |
| memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); |
| rtlIpv6AddressToStringA(&addr, addressBufferLocal); |
| addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, |
| BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); |
| } |
| else |
| { |
| addressTupleLocal = PyTuple_New(0); |
| } |
| |
| if (addressTupleLocal == NULL) |
| goto error; |
| |
| connectionTuple = Py_BuildValue("(iiiNNs)", |
| -1, |
| AF_INET6, |
| SOCK_DGRAM, |
| addressTupleLocal, |
| PyTuple_New(0), |
| "" |
| ); |
| if (!connectionTuple) |
| goto error; |
| if (PyList_Append(connectionsList, connectionTuple)) |
| goto error; |
| Py_DECREF(connectionTuple); |
| } |
| } |
| |
| free(table); |
| } |
| |
| ConnDecrefPyObjs(); |
| return connectionsList; |
| |
| error: |
| ConnDecrefPyObjs(); |
| Py_XDECREF(connectionTuple); |
| Py_XDECREF(addressTupleLocal); |
| Py_XDECREF(addressTupleRemote); |
| Py_DECREF(connectionsList); |
| if (table != NULL) |
| free(table); |
| return NULL; |
| } |
| |
| |
| /* |
| * Get process priority as a Python integer. |
| */ |
| static PyObject* |
| get_process_priority(PyObject* self, PyObject* args) |
| { |
| long pid; |
| DWORD priority; |
| HANDLE hProcess; |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| |
| hProcess = psutil_handle_from_pid(pid); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| priority = GetPriorityClass(hProcess); |
| CloseHandle(hProcess); |
| if (priority == 0) { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| return Py_BuildValue("i", priority); |
| } |
| |
| |
| /* |
| * Set process priority. |
| */ |
| static PyObject* |
| set_process_priority(PyObject* self, PyObject* args) |
| { |
| long pid; |
| int priority; |
| int retval; |
| HANDLE hProcess; |
| DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; |
| if (! PyArg_ParseTuple(args, "li", &pid, &priority)) { |
| return NULL; |
| } |
| |
| hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| retval = SetPriorityClass(hProcess, priority); |
| CloseHandle(hProcess); |
| if (retval == 0) { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| |
| #if (_WIN32_WINNT >= 0x0600) // Windows Vista |
| /* |
| * Get process IO priority as a Python integer. |
| */ |
| static PyObject* |
| get_process_io_priority(PyObject* self, PyObject* args) |
| { |
| long pid; |
| HANDLE hProcess; |
| PULONG IoPriority; |
| |
| _NtQueryInformationProcess NtQueryInformationProcess = |
| (_NtQueryInformationProcess)GetProcAddress( |
| GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid(pid); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| NtQueryInformationProcess( |
| hProcess, |
| ProcessIoPriority, |
| &IoPriority, |
| sizeof(ULONG), |
| NULL |
| ); |
| CloseHandle(hProcess); |
| return Py_BuildValue("i", IoPriority); |
| } |
| |
| |
| /* |
| * Set process IO priority. |
| */ |
| static PyObject* |
| set_process_io_priority(PyObject* self, PyObject* args) |
| { |
| long pid; |
| int prio; |
| HANDLE hProcess; |
| |
| _NtSetInformationProcess NtSetInformationProcess = |
| (_NtSetInformationProcess)GetProcAddress( |
| GetModuleHandleA("ntdll.dll"), "NtSetInformationProcess"); |
| |
| if (NtSetInformationProcess == NULL) { |
| PyErr_SetString(PyExc_RuntimeError, |
| "couldn't get NtSetInformationProcess"); |
| return NULL; |
| } |
| |
| if (! PyArg_ParseTuple(args, "li", &pid, &prio)) { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_ALL_ACCESS); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| NtSetInformationProcess( |
| hProcess, |
| ProcessIoPriority, |
| (PVOID)&prio, |
| sizeof((PVOID)prio) |
| ); |
| |
| CloseHandle(hProcess); |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| #endif |
| |
| |
| /* |
| * Return a Python tuple referencing process I/O counters. |
| */ |
| static PyObject* |
| get_process_io_counters(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| HANDLE hProcess; |
| IO_COUNTERS IoCounters; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid(pid); |
| if (NULL == hProcess) { |
| return NULL; |
| } |
| if (! GetProcessIoCounters(hProcess, &IoCounters)) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| CloseHandle(hProcess); |
| return Py_BuildValue("(KKKK)", IoCounters.ReadOperationCount, |
| IoCounters.WriteOperationCount, |
| IoCounters.ReadTransferCount, |
| IoCounters.WriteTransferCount); |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject* |
| get_process_io_counters_2(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| LONGLONG rcount, wcount, rbytes, wbytes; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| rcount = process->ReadOperationCount.QuadPart; |
| wcount = process->WriteOperationCount.QuadPart; |
| rbytes = process->ReadTransferCount.QuadPart; |
| wbytes = process->WriteTransferCount.QuadPart; |
| free(buffer); |
| return Py_BuildValue("KKKK", rcount, wcount, rbytes, wbytes); |
| } |
| |
| |
| /* |
| * Return process CPU affinity as a bitmask |
| */ |
| static PyObject* |
| get_process_cpu_affinity(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| HANDLE hProcess; |
| PDWORD_PTR proc_mask; |
| PDWORD_PTR system_mask; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid(pid); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| CloseHandle(hProcess); |
| #ifdef _WIN64 |
| return Py_BuildValue("K", (unsigned long long)proc_mask); |
| #else |
| return Py_BuildValue("k", (unsigned long)proc_mask); |
| #endif |
| } |
| |
| |
| /* |
| * Set process CPU affinity |
| */ |
| static PyObject* |
| set_process_cpu_affinity(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| HANDLE hProcess; |
| DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; |
| DWORD_PTR mask; |
| |
| #ifdef _WIN64 |
| if (! PyArg_ParseTuple(args, "lK", &pid, &mask)) |
| #else |
| if (! PyArg_ParseTuple(args, "lk", &pid, &mask)) |
| #endif |
| { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); |
| if (hProcess == NULL) { |
| return NULL; |
| } |
| |
| if (SetProcessAffinityMask(hProcess, mask) == 0) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| CloseHandle(hProcess); |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| |
| /* |
| * Return True if one of the process threads is in a waiting or |
| * suspended status. |
| */ |
| static PyObject* |
| is_process_suspended(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| ULONG i; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| for (i = 0; i < process->NumberOfThreads; i++) { |
| if (process->Threads[i].ThreadState != Waiting || |
| process->Threads[i].WaitReason != Suspended) |
| { |
| free(buffer); |
| Py_RETURN_FALSE; |
| } |
| } |
| free(buffer); |
| Py_RETURN_TRUE; |
| } |
| |
| |
| /* |
| * Return path's disk total and free as a Python tuple. |
| */ |
| static PyObject* |
| get_disk_usage(PyObject* self, PyObject* args) |
| { |
| BOOL retval; |
| ULARGE_INTEGER _, total, free; |
| LPCTSTR path; |
| |
| if (! PyArg_ParseTuple(args, "s", &path)) { |
| return NULL; |
| } |
| |
| Py_BEGIN_ALLOW_THREADS |
| retval = GetDiskFreeSpaceEx(path, &_, &total, &free); |
| Py_END_ALLOW_THREADS |
| if (retval == 0) { |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); |
| } |
| |
| |
| /* |
| * Return a Python list of named tuples with overall network I/O information |
| */ |
| static PyObject* |
| get_network_io_counters(PyObject* self, PyObject* args) |
| { |
| int attempts = 0; |
| int outBufLen = 15000; |
| DWORD dwRetVal = 0; |
| MIB_IFROW *pIfRow = NULL; |
| ULONG flags = 0; |
| ULONG family = AF_UNSPEC; |
| PIP_ADAPTER_ADDRESSES pAddresses = NULL; |
| PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; |
| |
| PyObject* py_retdict = PyDict_New(); |
| PyObject* py_nic_info = NULL; |
| PyObject* py_pre_nic_name = NULL; |
| PyObject* py_nic_name = NULL; |
| |
| if (py_retdict == NULL) { |
| return NULL; |
| } |
| do { |
| pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); |
| if (pAddresses == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, |
| &outBufLen); |
| if (dwRetVal == ERROR_BUFFER_OVERFLOW) { |
| free(pAddresses); |
| pAddresses = NULL; |
| } |
| else { |
| break; |
| } |
| |
| attempts++; |
| } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); |
| |
| if (dwRetVal != NO_ERROR) { |
| PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); |
| goto error; |
| } |
| |
| pCurrAddresses = pAddresses; |
| while (pCurrAddresses) { |
| py_pre_nic_name = NULL; |
| py_nic_name = NULL; |
| py_nic_info = NULL; |
| pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); |
| |
| if (pIfRow == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| |
| pIfRow->dwIndex = pCurrAddresses->IfIndex; |
| dwRetVal = GetIfEntry(pIfRow); |
| if (dwRetVal != NO_ERROR) { |
| PyErr_SetString(PyExc_RuntimeError, "GetIfEntry() failed."); |
| goto error; |
| } |
| |
| py_nic_info = Py_BuildValue("(IIIIIIII)", |
| pIfRow->dwOutOctets, |
| pIfRow->dwInOctets, |
| pIfRow->dwOutUcastPkts, |
| pIfRow->dwInUcastPkts, |
| pIfRow->dwInErrors, |
| pIfRow->dwOutErrors, |
| pIfRow->dwInDiscards, |
| pIfRow->dwOutDiscards); |
| if (!py_nic_info) |
| goto error; |
| |
| py_pre_nic_name = PyUnicode_FromWideChar( |
| pCurrAddresses->FriendlyName, |
| wcslen(pCurrAddresses->FriendlyName)); |
| if (py_pre_nic_name == NULL) |
| goto error; |
| py_nic_name = PyUnicode_FromObject(py_pre_nic_name); |
| if (py_nic_name == NULL) |
| goto error; |
| if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) |
| goto error; |
| Py_XDECREF(py_pre_nic_name); |
| Py_XDECREF(py_nic_name); |
| Py_XDECREF(py_nic_info); |
| |
| free(pIfRow); |
| pCurrAddresses = pCurrAddresses->Next; |
| } |
| |
| free(pAddresses); |
| return py_retdict; |
| |
| error: |
| Py_XDECREF(py_pre_nic_name); |
| Py_XDECREF(py_nic_name); |
| Py_XDECREF(py_nic_info); |
| Py_DECREF(py_retdict); |
| if (pAddresses != NULL) |
| free(pAddresses); |
| if (pIfRow != NULL) |
| free(pIfRow); |
| return NULL; |
| } |
| |
| // fix for mingw32, see |
| // https://code.google.com/p/psutil/issues/detail?id=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; |
| |
| /* |
| * Return a Python dict of tuples for disk I/O information |
| */ |
| static PyObject* |
| get_disk_io_counters(PyObject* self, PyObject* args) |
| { |
| DISK_PERFORMANCE_WIN_2008 diskPerformance; |
| DWORD dwSize; |
| HANDLE hDevice = NULL; |
| char szDevice[MAX_PATH]; |
| char szDeviceDisplay[MAX_PATH]; |
| int devNum; |
| PyObject* py_retdict = PyDict_New(); |
| PyObject* py_disk_info = NULL; |
| if (py_retdict == NULL) { |
| return NULL; |
| } |
| |
| // Apparently there's no way to figure out how many times we have |
| // to iterate in order to find valid drives. |
| // Let's assume 32, which is higher than 26, the number of letters |
| // in the alphabet (from A:\ to Z:\). |
| for (devNum=0; devNum <= 32; ++devNum) { |
| py_disk_info = NULL; |
| sprintf(szDevice, "\\\\.\\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)) |
| { |
| sprintf(szDeviceDisplay, "PhysicalDrive%d", devNum); |
| py_disk_info = Py_BuildValue("(IILLLL)", |
| diskPerformance.ReadCount, |
| diskPerformance.WriteCount, |
| diskPerformance.BytesRead, |
| diskPerformance.BytesWritten, |
| (diskPerformance.ReadTime.QuadPart |
| * 10) / 1000, |
| (diskPerformance.WriteTime.QuadPart |
| * 10) / 1000); |
| if (!py_disk_info) |
| goto error; |
| if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_disk_info)) |
| goto error; |
| Py_XDECREF(py_disk_info); |
| } |
| else { |
| // XXX we might get here with ERROR_INSUFFICIENT_BUFFER when |
| // compiling with mingw32; not sure what to do. |
| //return PyErr_SetFromWindowsErr(0); |
| ;; |
| } |
| |
| CloseHandle(hDevice); |
| } |
| |
| return py_retdict; |
| |
| error: |
| Py_XDECREF(py_disk_info); |
| Py_DECREF(py_retdict); |
| if (hDevice != NULL) |
| CloseHandle(hDevice); |
| return NULL; |
| } |
| |
| |
| 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 "?"; |
| } |
| } |
| |
| |
| #define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) |
| |
| /* |
| * Return disk partitions as a list of tuples such as |
| * (drive_letter, drive_letter, type, "") |
| */ |
| static PyObject* |
| get_disk_partitions(PyObject* self, PyObject* args) |
| { |
| DWORD num_bytes; |
| char drive_strings[255]; |
| char* drive_letter = drive_strings; |
| int all; |
| int type; |
| int ret; |
| char opts[20]; |
| LPTSTR fs_type[MAX_PATH + 1] = { 0 }; |
| DWORD pflags = 0; |
| PyObject* py_all; |
| PyObject* py_retlist = PyList_New(0); |
| PyObject* py_tuple = NULL; |
| |
| if (py_retlist == NULL) { |
| return NULL; |
| } |
| |
| // avoid to visualize a message box in case something goes wrong |
| // see http://code.google.com/p/psutil/issues/detail?id=264 |
| SetErrorMode(SEM_FAILCRITICALERRORS); |
| |
| if (! PyArg_ParseTuple(args, "O", &py_all)) { |
| goto error; |
| } |
| all = PyObject_IsTrue(py_all); |
| |
| Py_BEGIN_ALLOW_THREADS |
| num_bytes = GetLogicalDriveStrings(254, drive_letter); |
| Py_END_ALLOW_THREADS |
| |
| if (num_bytes == 0) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| while (*drive_letter != 0) { |
| py_tuple = NULL; |
| opts[0] = 0; |
| fs_type[0] = 0; |
| |
| Py_BEGIN_ALLOW_THREADS |
| type = GetDriveType(drive_letter); |
| Py_END_ALLOW_THREADS |
| |
| // 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(drive_letter, NULL, _ARRAYSIZE(drive_letter), |
| NULL, NULL, &pflags, 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(opts, ""); |
| SetLastError(0); |
| } |
| else { |
| if (pflags & FILE_READ_ONLY_VOLUME) { |
| strcat(opts, "ro"); |
| } |
| else { |
| strcat(opts, "rw"); |
| } |
| if (pflags & FILE_VOLUME_IS_COMPRESSED) { |
| strcat(opts, ",compressed"); |
| } |
| } |
| |
| if (strlen(opts) > 0) { |
| strcat(opts, ","); |
| } |
| strcat(opts, get_drive_type(type)); |
| |
| py_tuple = Py_BuildValue("(ssss)", |
| drive_letter, |
| drive_letter, |
| fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS |
| opts); |
| if (!py_tuple) |
| goto error; |
| if (PyList_Append(py_retlist, py_tuple)) |
| goto error; |
| Py_DECREF(py_tuple); |
| goto next; |
| |
| next: |
| drive_letter = strchr(drive_letter, 0) + 1; |
| } |
| |
| SetErrorMode(0); |
| return py_retlist; |
| |
| error: |
| SetErrorMode(0); |
| Py_XDECREF(py_tuple); |
| Py_DECREF(py_retlist); |
| return NULL; |
| } |
| |
| |
| #ifdef UNICODE |
| #define WTSOpenServer WTSOpenServerW |
| #else |
| #define WTSOpenServer WTSOpenServerA |
| #endif |
| |
| |
| /* |
| * Return a Python dict of tuples for disk I/O information |
| */ |
| static PyObject* |
| get_system_users(PyObject* self, PyObject* args) |
| { |
| HANDLE hServer = NULL; |
| LPTSTR 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; |
| |
| PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; |
| WINSTATION_INFO station_info; |
| HINSTANCE hInstWinSta = NULL; |
| ULONG returnLen; |
| |
| PyObject* py_retlist = PyList_New(0); |
| PyObject* py_tuple = NULL; |
| PyObject* py_address = NULL; |
| if (py_retlist == NULL) { |
| return NULL; |
| } |
| |
| hInstWinSta = LoadLibraryA("winsta.dll"); |
| WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) |
| GetProcAddress(hInstWinSta, "WinStationQueryInformationW"); |
| |
| hServer = WTSOpenServer('\0'); |
| if (hServer == NULL) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| for (i=0; i<count; i++) { |
| py_address = NULL; |
| py_tuple = NULL; |
| sessionId = sessions[i].SessionId; |
| if (buffer_user != NULL) { |
| WTSFreeMemory(buffer_user); |
| } |
| if (buffer_addr != NULL) { |
| WTSFreeMemory(buffer_addr); |
| } |
| |
| buffer_user = NULL; |
| buffer_addr = NULL; |
| |
| // username |
| bytes = 0; |
| if (WTSQuerySessionInformation(hServer, sessionId, WTSUserName, |
| &buffer_user, &bytes) == 0) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| if (bytes == 1) { |
| continue; |
| } |
| |
| // address |
| bytes = 0; |
| if (WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress, |
| &buffer_addr, &bytes) == 0) { |
| PyErr_SetFromWindowsErr(0); |
| goto error; |
| } |
| |
| address = (PWTS_CLIENT_ADDRESS)buffer_addr; |
| if (address->AddressFamily == 0) { // AF_INET |
| sprintf(address_str, "%u.%u.%u.%u", address->Address[0], |
| address->Address[1], |
| address->Address[2], |
| address->Address[3]); |
| py_address = Py_BuildValue("s", address_str); |
| if (!py_address) |
| goto error; |
| } |
| else { |
| py_address = Py_None; |
| } |
| |
| // login time |
| if (!WinStationQueryInformationW(hServer, |
| sessionId, |
| WinStationInformation, |
| &station_info, |
| sizeof(station_info), |
| &returnLen)) |
| { |
| goto error; |
| } |
| |
| unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; |
| unix_time += station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; |
| unix_time /= 10000000; |
| |
| py_tuple = Py_BuildValue("sOd", buffer_user, |
| py_address, |
| (double)unix_time); |
| if (!py_tuple) |
| goto error; |
| if (PyList_Append(py_retlist, py_tuple)) |
| goto error; |
| Py_XDECREF(py_address); |
| Py_XDECREF(py_tuple); |
| } |
| |
| WTSCloseServer(hServer); |
| WTSFreeMemory(sessions); |
| WTSFreeMemory(buffer_user); |
| WTSFreeMemory(buffer_addr); |
| FreeLibrary(hInstWinSta); |
| return py_retlist; |
| |
| error: |
| Py_XDECREF(py_tuple); |
| Py_XDECREF(py_address); |
| Py_DECREF(py_retlist); |
| |
| if (hInstWinSta != NULL) { |
| FreeLibrary(hInstWinSta); |
| } |
| if (hServer != NULL) { |
| WTSCloseServer(hServer); |
| } |
| if (sessions != NULL) { |
| WTSFreeMemory(sessions); |
| } |
| if (buffer_user != NULL) { |
| WTSFreeMemory(buffer_user); |
| } |
| if (buffer_addr != NULL) { |
| WTSFreeMemory(buffer_addr); |
| } |
| return NULL; |
| } |
| |
| |
| /* |
| * Return the number of handles opened by process. |
| */ |
| static PyObject* |
| get_process_num_handles(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| HANDLE hProcess; |
| DWORD handleCount; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| hProcess = psutil_handle_from_pid(pid); |
| if (NULL == hProcess) { |
| return NULL; |
| } |
| if (! GetProcessHandleCount(hProcess, &handleCount)) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| CloseHandle(hProcess); |
| return Py_BuildValue("k", handleCount); |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject* |
| get_process_num_handles_2(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| ULONG count; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| count = process->HandleCount; |
| free(buffer); |
| return Py_BuildValue("k", count); |
| } |
| |
| |
| /* |
| * Return the number of context switches executed by process. |
| */ |
| static PyObject* |
| get_process_num_ctx_switches(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| ULONG i; |
| ULONG total = 0; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| return NULL; |
| } |
| if (! get_process_info(pid, &process, &buffer)) { |
| return NULL; |
| } |
| for (i=0; i < process->NumberOfThreads; i++) { |
| total += process->Threads[i].ContextSwitches; |
| } |
| free(buffer); |
| return Py_BuildValue("ki", total, 0); |
| } |
| |
| |
| static char *get_region_protection_string(ULONG protection) |
| { |
| switch (protection & 0xff) { |
| case PAGE_NOACCESS: |
| return ""; |
| case PAGE_READONLY: |
| return "r"; |
| case PAGE_READWRITE: |
| return "rw"; |
| case PAGE_WRITECOPY: |
| return "wc"; |
| case PAGE_EXECUTE: |
| return "x"; |
| case PAGE_EXECUTE_READ: |
| return "xr"; |
| case PAGE_EXECUTE_READWRITE: |
| return "xrw"; |
| case PAGE_EXECUTE_WRITECOPY: |
| return "xwc"; |
| default: |
| return "?"; |
| } |
| } |
| |
| /* |
| * Return a list of process's memory mappings. |
| */ |
| static PyObject* |
| get_process_memory_maps(PyObject* self, PyObject* args) |
| { |
| DWORD pid; |
| HANDLE hProcess = NULL; |
| MEMORY_BASIC_INFORMATION basicInfo; |
| PVOID baseAddress; |
| PVOID previousAllocationBase; |
| CHAR mappedFileName[MAX_PATH]; |
| SYSTEM_INFO system_info; |
| LPVOID maxAddr; |
| PyObject* py_list = PyList_New(0); |
| PyObject* py_tuple = NULL; |
| |
| if (py_list == NULL) { |
| return NULL; |
| } |
| if (! PyArg_ParseTuple(args, "l", &pid)) { |
| goto error; |
| } |
| hProcess = psutil_handle_from_pid(pid); |
| if (NULL == hProcess) { |
| goto error; |
| } |
| |
| GetSystemInfo(&system_info); |
| maxAddr = system_info.lpMaximumApplicationAddress; |
| baseAddress = NULL; |
| previousAllocationBase = NULL; |
| |
| while (VirtualQueryEx(hProcess, baseAddress, &basicInfo, |
| sizeof(MEMORY_BASIC_INFORMATION))) |
| { |
| py_tuple = NULL; |
| if (baseAddress > maxAddr) { |
| break; |
| } |
| if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName, |
| sizeof(mappedFileName))) |
| { |
| py_tuple = Py_BuildValue("(kssI)", |
| (unsigned long)baseAddress, |
| get_region_protection_string(basicInfo.Protect), |
| mappedFileName, |
| basicInfo.RegionSize |
| ); |
| if (!py_tuple) |
| goto error; |
| if (PyList_Append(py_list, py_tuple)) |
| goto error; |
| Py_DECREF(py_tuple); |
| } |
| previousAllocationBase = basicInfo.AllocationBase; |
| baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; |
| } |
| |
| CloseHandle(hProcess); |
| return py_list; |
| |
| error: |
| Py_XDECREF(py_tuple); |
| Py_DECREF(py_list); |
| if (hProcess != NULL) |
| CloseHandle(hProcess); |
| return NULL; |
| } |
| |
| // ------------------------ Python init --------------------------- |
| |
| static PyMethodDef |
| PsutilMethods[] = |
| { |
| // --- per-process functions |
| |
| {"get_process_name", get_process_name, METH_VARARGS, |
| "Return process name"}, |
| {"get_process_cmdline", get_process_cmdline, METH_VARARGS, |
| "Return process cmdline as a list of cmdline arguments"}, |
| {"get_process_exe", get_process_exe, METH_VARARGS, |
| "Return path of the process executable"}, |
| {"get_process_ppid", get_process_ppid, METH_VARARGS, |
| "Return process ppid as an integer"}, |
| {"kill_process", kill_process, METH_VARARGS, |
| "Kill the process identified by the given PID"}, |
| {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, |
| "Return tuple of user/kern time for the given PID"}, |
| {"get_process_create_time", get_process_create_time, METH_VARARGS, |
| "Return a float indicating the process create time expressed in " |
| "seconds since the epoch"}, |
| {"get_process_memory_info", get_process_memory_info, METH_VARARGS, |
| "Return a tuple of process memory information"}, |
| {"get_process_cwd", get_process_cwd, METH_VARARGS, |
| "Return process current working directory"}, |
| {"suspend_process", suspend_process, METH_VARARGS, |
| "Suspend a process"}, |
| {"resume_process", resume_process, METH_VARARGS, |
| "Resume a process"}, |
| {"get_process_open_files", get_process_open_files, METH_VARARGS, |
| "Return files opened by process"}, |
| {"get_process_username", get_process_username, METH_VARARGS, |
| "Return the username of a process"}, |
| {"get_process_connections", get_process_connections, METH_VARARGS, |
| "Return the network connections of a process"}, |
| {"get_process_num_threads", get_process_num_threads, METH_VARARGS, |
| "Return the network connections of a process"}, |
| {"get_process_threads", get_process_threads, METH_VARARGS, |
| "Return process threads information as a list of tuple"}, |
| {"process_wait", process_wait, METH_VARARGS, |
| "Wait for process to terminate and return its exit code."}, |
| {"get_process_priority", get_process_priority, METH_VARARGS, |
| "Return process priority."}, |
| {"set_process_priority", set_process_priority, METH_VARARGS, |
| "Set process priority."}, |
| #if (_WIN32_WINNT >= 0x0600) // Windows Vista |
| {"get_process_io_priority", get_process_io_priority, METH_VARARGS, |
| "Return process IO priority."}, |
| {"set_process_io_priority", set_process_io_priority, METH_VARARGS, |
| "Set process IO priority."}, |
| #endif |
| {"get_process_cpu_affinity", get_process_cpu_affinity, METH_VARARGS, |
| "Return process CPU affinity as a bitmask."}, |
| {"set_process_cpu_affinity", set_process_cpu_affinity, METH_VARARGS, |
| "Set process CPU affinity."}, |
| {"get_process_io_counters", get_process_io_counters, METH_VARARGS, |
| "Get process I/O counters."}, |
| {"is_process_suspended", is_process_suspended, METH_VARARGS, |
| "Return True if one of the process threads is in a suspended state"}, |
| {"get_process_num_handles", get_process_num_handles, METH_VARARGS, |
| "Return the number of handles opened by process."}, |
| {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS, |
| "Return the number of context switches performed by process."}, |
| {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS, |
| "Return a list of process's memory mappings"}, |
| |
| // --- alternative pinfo interface |
| {"get_process_cpu_times_2", get_process_cpu_times_2, METH_VARARGS, |
| "Alternative implementation"}, |
| {"get_process_create_time_2", get_process_create_time_2, METH_VARARGS, |
| "Alternative implementation"}, |
| {"get_process_num_handles_2", get_process_num_handles_2, METH_VARARGS, |
| "Alternative implementation"}, |
| {"get_process_io_counters_2", get_process_io_counters_2, METH_VARARGS, |
| "Alternative implementation"}, |
| {"get_process_memory_info_2", get_process_memory_info_2, METH_VARARGS, |
| "Alternative implementation"}, |
| |
| // --- system-related functions |
| |
| {"get_pid_list", get_pid_list, METH_VARARGS, |
| "Returns a list of PIDs currently running on the system"}, |
| {"pid_exists", pid_exists, METH_VARARGS, |
| "Determine if the process exists in the current process list."}, |
| {"get_num_cpus", get_num_cpus, METH_VARARGS, |
| "Returns the number of CPUs on the system"}, |
| {"get_system_boot_time", get_system_boot_time, METH_VARARGS, |
| "Return the system boot time expressed in seconds since the epoch."}, |
| {"get_virtual_mem", get_virtual_mem, METH_VARARGS, |
| "Return the total amount of physical memory, in bytes"}, |
| {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, |
| "Return system per-cpu times as a list of tuples"}, |
| {"get_disk_usage", get_disk_usage, METH_VARARGS, |
| "Return path's disk total and free as a Python tuple."}, |
| {"get_network_io_counters", get_network_io_counters, METH_VARARGS, |
| "Return dict of tuples of networks I/O information."}, |
| {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS, |
| "Return dict of tuples of disks I/O information."}, |
| {"get_system_users", get_system_users, METH_VARARGS, |
| "Return a list of currently connected users."}, |
| {"get_disk_partitions", get_disk_partitions, METH_VARARGS, |
| "Return disk partitions."}, |
| |
| |
| // --- windows API bindings |
| {"win32_QueryDosDevice", win32_QueryDosDevice, METH_VARARGS, |
| "QueryDosDevice binding"}, |
| |
| {NULL, NULL, 0, NULL} |
| }; |
| |
| |
| struct module_state { |
| PyObject *error; |
| }; |
| |
| #if PY_MAJOR_VERSION >= 3 |
| #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) |
| #else |
| #define GETSTATE(m) (&_state) |
| static struct module_state _state; |
| #endif |
| |
| #if PY_MAJOR_VERSION >= 3 |
| |
| static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) { |
| Py_VISIT(GETSTATE(m)->error); |
| return 0; |
| } |
| |
| static int psutil_mswindows_clear(PyObject *m) { |
| Py_CLEAR(GETSTATE(m)->error); |
| return 0; |
| } |
| |
| static struct PyModuleDef moduledef = { |
| PyModuleDef_HEAD_INIT, |
| "psutil_mswindows", |
| NULL, |
| sizeof(struct module_state), |
| PsutilMethods, |
| NULL, |
| psutil_mswindows_traverse, |
| psutil_mswindows_clear, |
| NULL |
| }; |
| |
| #define INITERROR return NULL |
| |
| PyObject* PyInit__psutil_mswindows(void) |
| |
| #else |
| #define INITERROR return |
| void init_psutil_mswindows(void) |
| #endif |
| { |
| struct module_state *st = NULL; |
| #if PY_MAJOR_VERSION >= 3 |
| PyObject *module = PyModule_Create(&moduledef); |
| #else |
| PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods); |
| #endif |
| |
| if (module == NULL) { |
| INITERROR; |
| } |
| |
| st = GETSTATE(module); |
| st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL); |
| if (st->error == NULL) { |
| Py_DECREF(module); |
| INITERROR; |
| } |
| |
| // Public constants |
| // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx |
| PyModule_AddIntConstant(module, "ABOVE_NORMAL_PRIORITY_CLASS", |
| ABOVE_NORMAL_PRIORITY_CLASS); |
| PyModule_AddIntConstant(module, "BELOW_NORMAL_PRIORITY_CLASS", |
| BELOW_NORMAL_PRIORITY_CLASS); |
| PyModule_AddIntConstant(module, "HIGH_PRIORITY_CLASS", |
| HIGH_PRIORITY_CLASS); |
| PyModule_AddIntConstant(module, "IDLE_PRIORITY_CLASS", |
| IDLE_PRIORITY_CLASS); |
| PyModule_AddIntConstant(module, "NORMAL_PRIORITY_CLASS", |
| NORMAL_PRIORITY_CLASS); |
| PyModule_AddIntConstant(module, "REALTIME_PRIORITY_CLASS", |
| REALTIME_PRIORITY_CLASS); |
| // private constants |
| PyModule_AddIntConstant(module, "INFINITE", INFINITE); |
| PyModule_AddIntConstant(module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); |
| SetSeDebug(); |
| |
| #if PY_MAJOR_VERSION >= 3 |
| return module; |
| #endif |
| } |