| /* |
| * 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_windows |
| */ |
| |
| // 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> |
| #include <ws2tcpip.h> |
| |
| // Link with Iphlpapi.lib |
| #pragma comment(lib, "IPHLPAPI.lib") |
| |
| #include "_psutil_windows.h" |
| #include "_psutil_common.h" |
| #include "arch/windows/security.h" |
| #include "arch/windows/process_info.h" |
| #include "arch/windows/process_handles.h" |
| #include "arch/windows/ntextapi.h" |
| #include "arch/windows/inet_ntop.h" |
| |
| #ifdef __MINGW32__ |
| #include "arch/windows/glpi.h" |
| #endif |
| |
| |
| /* |
| * ============================================================================ |
| * Utilities |
| * ============================================================================ |
| */ |
| |
| // a flag for connections without an actual status |
| static int PSUTIL_CONN_NONE = 128; |
| |
| #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) |
| #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) |
| #define LO_T ((float)1e-7) |
| #define HI_T (LO_T*4294967296.0) |
| #define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) |
| #ifndef AF_INET6 |
| #define AF_INET6 23 |
| #endif |
| #define _psutil_conn_decref_objs() \ |
| Py_DECREF(_AF_INET); \ |
| Py_DECREF(_AF_INET6);\ |
| Py_DECREF(_SOCK_STREAM);\ |
| Py_DECREF(_SOCK_DGRAM); |
| |
| 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; |
| |
| // --- network connections mingw32 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 |
| |
| 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; |
| |
| |
| PIP_ADAPTER_ADDRESSES |
| psutil_get_nic_addresses() { |
| // allocate a 15 KB buffer to start with |
| int outBufLen = 15000; |
| DWORD dwRetVal = 0; |
| ULONG attempts = 0; |
| PIP_ADAPTER_ADDRESSES pAddresses = NULL; |
| |
| do { |
| pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); |
| if (pAddresses == NULL) { |
| PyErr_NoMemory(); |
| return NULL; |
| } |
| |
| dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, |
| &outBufLen); |
| if (dwRetVal == ERROR_BUFFER_OVERFLOW) { |
| free(pAddresses); |
| pAddresses = NULL; |
| } |
| else { |
| break; |
| } |
| |
| attempts++; |
| } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); |
| |
| if (dwRetVal != NO_ERROR) { |
| PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); |
| return NULL; |
| } |
| |
| return pAddresses; |
| } |
| |
| |
| /* |
| * ============================================================================ |
| * Public Python API |
| * ============================================================================ |
| */ |
| |
| |
| /* |
| * Return a Python float representing the system uptime expressed in seconds |
| * since the epoch. |
| */ |
| static PyObject * |
| psutil_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 * |
| psutil_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 * |
| psutil_pids(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 (proclist == NULL) |
| 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 * |
| psutil_proc_kill(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 https://github.com/giampaolo/psutil/issues/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_RETURN_NONE; |
| } |
| |
| |
| /* |
| * Wait for process to terminate and return its exit code. |
| */ |
| static PyObject * |
| psutil_proc_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_RETURN_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 * |
| psutil_proc_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) |
| ); |
| } |
| |
| |
| /* |
| * Return a Python float indicating the process create time expressed in |
| * seconds since the epoch. |
| */ |
| static PyObject * |
| psutil_proc_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 system boot time |
| if (0 == pid || 4 == pid) |
| return psutil_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); |
| } |
| |
| |
| |
| /* |
| * Return the number of logical CPUs. |
| */ |
| static PyObject * |
| psutil_cpu_count_logical(PyObject *self, PyObject *args) |
| { |
| SYSTEM_INFO system_info; |
| system_info.dwNumberOfProcessors = 0; |
| |
| GetSystemInfo(&system_info); |
| if (system_info.dwNumberOfProcessors == 0) |
| Py_RETURN_NONE; // mimic os.cpu_count() |
| else |
| return Py_BuildValue("I", system_info.dwNumberOfProcessors); |
| } |
| |
| |
| /* |
| * Return the number of physical CPU cores. |
| */ |
| static PyObject * |
| psutil_cpu_count_phys(PyObject *self, PyObject *args) |
| { |
| LPFN_GLPI glpi; |
| DWORD rc; |
| PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; |
| PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; |
| DWORD length = 0; |
| DWORD offset = 0; |
| int ncpus = 0; |
| |
| glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), |
| "GetLogicalProcessorInformation"); |
| if (glpi == NULL) |
| goto return_none; |
| |
| while (1) { |
| rc = glpi(buffer, &length); |
| if (rc == FALSE) { |
| if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { |
| if (buffer) |
| free(buffer); |
| buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( |
| length); |
| if (NULL == buffer) { |
| PyErr_NoMemory(); |
| return NULL; |
| } |
| } |
| else { |
| goto return_none; |
| } |
| } |
| 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 return_none; |
| else |
| return Py_BuildValue("i", ncpus); |
| |
| return_none: |
| // mimic os.cpu_count() |
| if (buffer != NULL) |
| free(buffer); |
| Py_RETURN_NONE; |
| } |
| |
| |
| /* |
| * Return process cmdline as a Python list of cmdline arguments. |
| */ |
| static PyObject * |
| psutil_proc_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 * |
| psutil_proc_exe(PyObject *self, PyObject *args) { |
| long pid; |
| HANDLE hProcess; |
| wchar_t exe[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 (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { |
| CloseHandle(hProcess); |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| CloseHandle(hProcess); |
| return Py_BuildValue("u", exe); |
| } |
| |
| |
| /* |
| * Return process base name. |
| * Note: psutil_proc_exe() is attempted first because it's faster |
| * but it raise AccessDenied for processes owned by other users |
| * in which case we fall back on using this. |
| */ |
| static PyObject * |
| psutil_proc_name(PyObject *self, PyObject *args) { |
| long pid; |
| int ok; |
| PROCESSENTRY32 pentry; |
| HANDLE hSnapShot; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); |
| if (hSnapShot == INVALID_HANDLE_VALUE) { |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| pentry.dwSize = sizeof(PROCESSENTRY32); |
| ok = Process32First(hSnapShot, &pentry); |
| if (! ok) { |
| CloseHandle(hSnapShot); |
| PyErr_SetFromWindowsErr(0); |
| return NULL; |
| } |
| while (ok) { |
| if (pentry.th32ProcessID == pid) { |
| CloseHandle(hSnapShot); |
| return Py_BuildValue("s", pentry.szExeFile); |
| } |
| ok = Process32Next(hSnapShot, &pentry); |
| } |
| |
| CloseHandle(hSnapShot); |
| NoSuchProcess(); |
| return NULL; |
| } |
| |
| |
| /* |
| * Return process memory information as a Python tuple. |
| */ |
| static PyObject * |
| psutil_proc_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, (PPROCESS_MEMORY_COUNTERS)&cnt, |
| sizeof(cnt))) { |
| CloseHandle(hProcess); |
| return PyErr_SetFromWindowsErr(0); |
| } |
| |
| #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 |
| private = cnt.PrivateUsage; |
| #endif |
| |
| CloseHandle(hProcess); |
| |
| // PROCESS_MEMORY_COUNTERS values are defined as SIZE_T which on 64bits |
| // is an (unsigned long long) and on 32bits is an (unsigned int). |
| // "_WIN64" is defined if we're running a 64bit Python interpreter not |
| // exclusively if the *system* is 64bit. |
| #if defined(_WIN64) |
| return Py_BuildValue( |
| "(kKKKKKKKKK)", |
| cnt.PageFaultCount, // unsigned long |
| (unsigned long long)cnt.PeakWorkingSetSize, |
| (unsigned long long)cnt.WorkingSetSize, |
| (unsigned long long)cnt.QuotaPeakPagedPoolUsage, |
| (unsigned long long)cnt.QuotaPagedPoolUsage, |
| (unsigned long long)cnt.QuotaPeakNonPagedPoolUsage, |
| (unsigned long long)cnt.QuotaNonPagedPoolUsage, |
| (unsigned long long)cnt.PagefileUsage, |
| (unsigned long long)cnt.PeakPagefileUsage, |
| (unsigned long long)private); |
| #else |
| return Py_BuildValue( |
| "(kIIIIIIIII)", |
| cnt.PageFaultCount, // unsigned long |
| (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); |
| #endif |
| } |
| |
| |
| /* |
| * Alternative implementation of the one above but bypasses ACCESS DENIED. |
| */ |
| static PyObject * |
| psutil_proc_memory_info_2(PyObject *self, PyObject *args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| SIZE_T private; |
| unsigned long pfault_count; |
| |
| #if defined(_WIN64) |
| unsigned long long m1, m2, m3, m4, m5, m6, m7, m8; |
| #else |
| unsigned int m1, m2, m3, m4, m5, m6, m7, m8; |
| #endif |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| if (! psutil_get_proc_info(pid, &process, &buffer)) |
| return NULL; |
| |
| #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 |
| private = process->PrivatePageCount; |
| #else |
| private = 0; |
| #endif |
| pfault_count = 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; |
| |
| free(buffer); |
| |
| // SYSTEM_PROCESS_INFORMATION values are defined as SIZE_T which on 64 |
| // bits is an (unsigned long long) and on 32bits is an (unsigned int). |
| // "_WIN64" is defined if we're running a 64bit Python interpreter not |
| // exclusively if the *system* is 64bit. |
| #if defined(_WIN64) |
| return Py_BuildValue("(kKKKKKKKKK)", |
| #else |
| return Py_BuildValue("(kIIIIIIIII)", |
| #endif |
| pfault_count, m1, m2, m3, m4, m5, m6, m7, m8, private); |
| } |
| |
| |
| /* |
| * Return a Python integer indicating the total amount of physical memory |
| * in bytes. |
| */ |
| static PyObject * |
| psutil_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 |
| } |
| |
| |
| /* |
| * Retrieves system CPU timing information as a (user, system, idle) |
| * tuple. On a multiprocessor system, the values returned are the |
| * sum of the designated times across all processors. |
| */ |
| static PyObject * |
| psutil_cpu_times(PyObject *self, PyObject *args) |
| { |
| float idle, kernel, user, system; |
| FILETIME idle_time, kernel_time, user_time; |
| |
| if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) |
| return PyErr_SetFromWindowsErr(0); |
| |
| 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); |
| return Py_BuildValue("(fff)", user, system, idle); |
| } |
| |
| |
| /* |
| * Same as above but for all system CPUs. |
| */ |
| static PyObject * |
| psutil_per_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 * |
| psutil_proc_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 |
| psutil_proc_suspend_or_resume(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 * |
| psutil_proc_suspend(PyObject *self, PyObject *args) |
| { |
| long pid; |
| int suspend = 1; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| if (! psutil_proc_suspend_or_resume(pid, suspend)) |
| return NULL; |
| Py_RETURN_NONE; |
| } |
| |
| |
| static PyObject * |
| psutil_proc_resume(PyObject *self, PyObject *args) |
| { |
| long pid; |
| int suspend = 0; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| if (! psutil_proc_suspend_or_resume(pid, suspend)) |
| return NULL; |
| Py_RETURN_NONE; |
| } |
| |
| |
| static PyObject * |
| psutil_proc_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 * |
| psutil_proc_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 * |
| psutil_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) { |
| if (_tcscmp(lpDevicePath, szTarget) == 0) { |
| _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d); |
| return Py_BuildValue("s", szBuff); |
| } |
| } |
| d++; |
| } |
| return Py_BuildValue("s", ""); |
| } |
| |
| |
| /* |
| * Return process username as a "DOMAIN//USERNAME" string. |
| */ |
| static PyObject * |
| psutil_proc_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 = PyUnicode_Decode( |
| fullName, _tcslen(fullName), Py_FileSystemDefaultEncoding, "replace"); |
| |
| free(fullName); |
| free(name); |
| free(domainName); |
| free(user); |
| |
| return returnObject; |
| } |
| |
| |
| /* |
| * Return a list of network connections opened by a process |
| */ |
| static PyObject * |
| psutil_net_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); |
| _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; |
| typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR); |
| _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)) { |
| _psutil_conn_decref_objs(); |
| return NULL; |
| } |
| |
| if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { |
| _psutil_conn_decref_objs(); |
| PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); |
| return NULL; |
| } |
| |
| if (pid != -1) { |
| if (psutil_pid_is_running(pid) == 0) { |
| _psutil_conn_decref_objs(); |
| 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"); |
| _psutil_conn_decref_objs(); |
| return NULL; |
| } |
| |
| connectionsList = PyList_New(0); |
| if (connectionsList == NULL) { |
| _psutil_conn_decref_objs(); |
| 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 (pid != -1) { |
| 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( |
| "(iiiNNiI)", |
| -1, |
| AF_INET, |
| SOCK_STREAM, |
| addressTupleLocal, |
| addressTupleRemote, |
| tcp4Table->table[i].dwState, |
| tcp4Table->table[i].dwOwningPid); |
| 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 (pid != -1) { |
| 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( |
| "(iiiNNiI)", |
| -1, |
| AF_INET6, |
| SOCK_STREAM, |
| addressTupleLocal, |
| addressTupleRemote, |
| tcp6Table->table[i].dwState, |
| tcp6Table->table[i].dwOwningPid); |
| 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 (pid != -1) { |
| 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( |
| "(iiiNNiI)", |
| -1, |
| AF_INET, |
| SOCK_DGRAM, |
| addressTupleLocal, |
| PyTuple_New(0), |
| PSUTIL_CONN_NONE, |
| udp4Table->table[i].dwOwningPid); |
| 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 (pid != -1) { |
| 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( |
| "(iiiNNiI)", |
| -1, |
| AF_INET6, |
| SOCK_DGRAM, |
| addressTupleLocal, |
| PyTuple_New(0), |
| PSUTIL_CONN_NONE, |
| udp6Table->table[i].dwOwningPid); |
| if (!connectionTuple) |
| goto error; |
| if (PyList_Append(connectionsList, connectionTuple)) |
| goto error; |
| Py_DECREF(connectionTuple); |
| } |
| } |
| |
| free(table); |
| } |
| |
| _psutil_conn_decref_objs(); |
| return connectionsList; |
| |
| error: |
| _psutil_conn_decref_objs(); |
| 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 * |
| psutil_proc_priority_get(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 * |
| psutil_proc_priority_set(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_RETURN_NONE; |
| } |
| |
| |
| #if (_WIN32_WINNT >= 0x0600) // Windows Vista |
| /* |
| * Get process IO priority as a Python integer. |
| */ |
| static PyObject * |
| psutil_proc_io_priority_get(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 * |
| psutil_proc_io_priority_set(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_RETURN_NONE; |
| } |
| #endif |
| |
| |
| /* |
| * Return a Python tuple referencing process I/O counters. |
| */ |
| static PyObject * |
| psutil_proc_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); |
| } |
| |
| |
| /* |
| * Return process CPU affinity as a bitmask |
| */ |
| static PyObject * |
| psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) |
| { |
| DWORD pid; |
| HANDLE hProcess; |
| DWORD_PTR proc_mask; |
| DWORD_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 * |
| psutil_proc_cpu_affinity_set(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_RETURN_NONE; |
| } |
| |
| |
| /* |
| * Return True if one of the process threads is in a waiting or |
| * suspended status. |
| */ |
| static PyObject * |
| psutil_proc_is_suspended(PyObject *self, PyObject *args) |
| { |
| DWORD pid; |
| ULONG i; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| if (! psutil_get_proc_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 * |
| psutil_disk_usage(PyObject *self, PyObject *args) |
| { |
| BOOL retval; |
| ULARGE_INTEGER _, total, free; |
| char *path; |
| |
| if (PyArg_ParseTuple(args, "u", &path)) { |
| Py_BEGIN_ALLOW_THREADS |
| retval = GetDiskFreeSpaceExW((LPCWSTR)path, &_, &total, &free); |
| Py_END_ALLOW_THREADS |
| goto return_; |
| } |
| |
| // on Python 2 we also want to accept plain strings other |
| // than Unicode |
| #if PY_MAJOR_VERSION <= 2 |
| PyErr_Clear(); // drop the argument parsing error |
| if (PyArg_ParseTuple(args, "s", &path)) { |
| Py_BEGIN_ALLOW_THREADS |
| retval = GetDiskFreeSpaceEx(path, &_, &total, &free); |
| Py_END_ALLOW_THREADS |
| goto return_; |
| } |
| #endif |
| |
| return NULL; |
| |
| return_: |
| if (retval == 0) |
| return PyErr_SetFromWindowsErr(0); |
| else |
| return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); |
| } |
| |
| |
| /* |
| * Return a Python list of named tuples with overall network I/O information |
| */ |
| static PyObject * |
| psutil_net_io_counters(PyObject *self, PyObject *args) |
| { |
| char ifname[MAX_PATH]; |
| DWORD dwRetVal = 0; |
| MIB_IFROW *pIfRow = NULL; |
| PIP_ADAPTER_ADDRESSES pAddresses = NULL; |
| PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; |
| |
| PyObject *py_retdict = PyDict_New(); |
| PyObject *py_nic_info = NULL; |
| PyObject *py_nic_name = NULL; |
| |
| if (py_retdict == NULL) |
| return NULL; |
| pAddresses = psutil_get_nic_addresses(); |
| if (pAddresses == NULL) |
| goto error; |
| pCurrAddresses = pAddresses; |
| |
| while (pCurrAddresses) { |
| 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("(kkkkkkkk)", |
| pIfRow->dwOutOctets, |
| pIfRow->dwInOctets, |
| pIfRow->dwOutUcastPkts, |
| pIfRow->dwInUcastPkts, |
| pIfRow->dwInErrors, |
| pIfRow->dwOutErrors, |
| pIfRow->dwInDiscards, |
| pIfRow->dwOutDiscards); |
| if (!py_nic_info) |
| goto error; |
| |
| sprintf_s(ifname, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); |
| py_nic_name = PyUnicode_Decode( |
| ifname, _tcslen(ifname), Py_FileSystemDefaultEncoding, "replace"); |
| |
| if (py_nic_name == NULL) |
| goto error; |
| if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) |
| goto error; |
| Py_XDECREF(py_nic_name); |
| Py_XDECREF(py_nic_info); |
| |
| free(pIfRow); |
| pCurrAddresses = pCurrAddresses->Next; |
| } |
| |
| free(pAddresses); |
| return py_retdict; |
| |
| error: |
| 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; |
| } |
| |
| |
| /* |
| * Return a Python dict of tuples for disk I/O information |
| */ |
| static PyObject * |
| psutil_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_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)) |
| { |
| sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); |
| py_disk_info = Py_BuildValue( |
| "(IILLKK)", |
| diskPerformance.ReadCount, |
| diskPerformance.WriteCount, |
| diskPerformance.BytesRead, |
| diskPerformance.BytesWritten, |
| (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000, |
| (unsigned long long)(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 *psutil_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 "?"; |
| } |
| } |
| |
| |
| #ifndef _ARRAYSIZE |
| #define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) |
| #endif |
| |
| /* |
| * Return disk partitions as a list of tuples such as |
| * (drive_letter, drive_letter, type, "") |
| */ |
| static PyObject * |
| psutil_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 https://github.com/giampaolo/psutil/issues/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( |
| (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), psutil_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; |
| } |
| |
| /* |
| * Return a Python dict of tuples for disk I/O information |
| */ |
| static PyObject * |
| psutil_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; |
| PyObject *py_buffer_user_encoded = 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_s(address_str, |
| _countof(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_buffer_user_encoded = PyUnicode_Decode( |
| buffer_user, _tcslen(buffer_user), Py_FileSystemDefaultEncoding, |
| "replace"); |
| py_tuple = Py_BuildValue("OOd", py_buffer_user_encoded, py_address, |
| (double)unix_time); |
| if (!py_tuple) |
| goto error; |
| if (PyList_Append(py_retlist, py_tuple)) |
| goto error; |
| Py_XDECREF(py_buffer_user_encoded); |
| 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_buffer_user_encoded); |
| 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 * |
| psutil_proc_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); |
| } |
| |
| |
| /* |
| * Get various process information by using NtQuerySystemInformation. |
| * We use this as a fallback when faster functions fail with access |
| * denied. This is slower because it iterates over all processes. |
| * Returned tuple includes the following process info: |
| * |
| * - num_threads |
| * - ctx_switches |
| * - num_handles (fallback) |
| * - user/kernel times (fallback) |
| * - create time (fallback) |
| * - io counters (fallback) |
| */ |
| static PyObject * |
| psutil_proc_info(PyObject *self, PyObject *args) |
| { |
| DWORD pid; |
| PSYSTEM_PROCESS_INFORMATION process; |
| PVOID buffer; |
| ULONG num_handles; |
| ULONG i; |
| ULONG ctx_switches = 0; |
| double user_time; |
| double kernel_time; |
| long long create_time; |
| int num_threads; |
| LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes; |
| |
| |
| if (! PyArg_ParseTuple(args, "l", &pid)) |
| return NULL; |
| if (! psutil_get_proc_info(pid, &process, &buffer)) |
| return NULL; |
| |
| num_handles = process->HandleCount; |
| for (i = 0; i < process->NumberOfThreads; i++) |
| ctx_switches += process->Threads[i].ContextSwitches; |
| user_time = (double)process->UserTime.HighPart * 429.4967296 + \ |
| (double)process->UserTime.LowPart * 1e-7; |
| kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \ |
| (double)process->KernelTime.LowPart * 1e-7; |
| // 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) { |
| // the python module will translate this into BOOT_TIME later |
| create_time = 0; |
| } |
| else { |
| create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; |
| create_time += process->CreateTime.LowPart - 116444736000000000LL; |
| create_time /= 10000000; |
| } |
| num_threads = (int)process->NumberOfThreads; |
| io_rcount = process->ReadOperationCount.QuadPart; |
| io_wcount = process->WriteOperationCount.QuadPart; |
| io_rbytes = process->ReadTransferCount.QuadPart; |
| io_wbytes = process->WriteTransferCount.QuadPart; |
| free(buffer); |
| |
| return Py_BuildValue( |
| "kkdddiKKKK", |
| num_handles, |
| ctx_switches, |
| user_time, |
| kernel_time, |
| (double)create_time, |
| num_threads, |
| io_rcount, |
| io_wcount, |
| io_rbytes, |
| io_wbytes |
| ); |
| } |
| |
| |
| 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 * |
| psutil_proc_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; |
| } |
| |
| |
| /* |
| * Return a {pid:ppid, ...} dict for all running processes. |
| */ |
| static PyObject * |
| psutil_ppid_map(PyObject *self, PyObject *args) |
| { |
| PyObject *pid = NULL; |
| PyObject *ppid = NULL; |
| PyObject *py_retdict = PyDict_New(); |
| HANDLE handle = NULL; |
| PROCESSENTRY32 pe = {0}; |
| pe.dwSize = sizeof(PROCESSENTRY32); |
| |
| if (py_retdict == NULL) |
| return NULL; |
| handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
| if (handle == INVALID_HANDLE_VALUE) { |
| PyErr_SetFromWindowsErr(0); |
| Py_DECREF(py_retdict); |
| return NULL; |
| } |
| |
| if (Process32First(handle, &pe)) { |
| do { |
| pid = Py_BuildValue("I", pe.th32ProcessID); |
| if (pid == NULL) |
| goto error; |
| ppid = Py_BuildValue("I", pe.th32ParentProcessID); |
| if (ppid == NULL) |
| goto error; |
| if (PyDict_SetItem(py_retdict, pid, ppid)) |
| goto error; |
| Py_DECREF(pid); |
| Py_DECREF(ppid); |
| } while (Process32Next(handle, &pe)); |
| } |
| |
| CloseHandle(handle); |
| return py_retdict; |
| |
| error: |
| Py_XDECREF(pid); |
| Py_XDECREF(ppid); |
| Py_DECREF(py_retdict); |
| CloseHandle(handle); |
| return NULL; |
| } |
| |
| |
| /* |
| * Return NICs addresses. |
| */ |
| |
| static PyObject * |
| psutil_net_if_addrs(PyObject *self, PyObject *args) |
| { |
| unsigned int i = 0; |
| ULONG family; |
| PCTSTR intRet; |
| char *ptr; |
| char buff[100]; |
| char ifname[MAX_PATH]; |
| DWORD bufflen = 100; |
| PIP_ADAPTER_ADDRESSES pAddresses = NULL; |
| PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; |
| PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; |
| |
| PyObject *py_retlist = PyList_New(0); |
| PyObject *py_tuple = NULL; |
| PyObject *py_address = NULL; |
| PyObject *py_mac_address = NULL; |
| |
| if (py_retlist == NULL) |
| return NULL; |
| |
| pAddresses = psutil_get_nic_addresses(); |
| if (pAddresses == NULL) |
| goto error; |
| pCurrAddresses = pAddresses; |
| |
| while (pCurrAddresses) { |
| pUnicast = pCurrAddresses->FirstUnicastAddress; |
| sprintf_s(ifname, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); |
| |
| // MAC address |
| if (pCurrAddresses->PhysicalAddressLength != 0) { |
| ptr = buff; |
| *ptr = '\0'; |
| for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) { |
| if (i == (pCurrAddresses->PhysicalAddressLength - 1)) { |
| sprintf_s(ptr, _countof(buff), "%.2X\n", |
| (int)pCurrAddresses->PhysicalAddress[i]); |
| } |
| else { |
| sprintf_s(ptr, _countof(buff), "%.2X-", |
| (int)pCurrAddresses->PhysicalAddress[i]); |
| } |
| ptr += 3; |
| } |
| *--ptr = '\0'; |
| |
| #if PY_MAJOR_VERSION >= 3 |
| py_mac_address = PyUnicode_FromString(buff); |
| #else |
| py_mac_address = PyString_FromString(buff); |
| #endif |
| if (py_mac_address == NULL) |
| goto error; |
| |
| Py_INCREF(Py_None); |
| Py_INCREF(Py_None); |
| py_tuple = Py_BuildValue( |
| "(siOOO)", |
| ifname, |
| -1, // this will be converted later to AF_LINK |
| py_mac_address, |
| Py_None, |
| Py_None |
| ); |
| if (! py_tuple) |
| goto error; |
| if (PyList_Append(py_retlist, py_tuple)) |
| goto error; |
| Py_DECREF(py_tuple); |
| Py_DECREF(py_mac_address); |
| } |
| |
| // find out the IP address associated with the NIC |
| if (pUnicast != NULL) { |
| for (i = 0; pUnicast != NULL; i++) { |
| family = pUnicast->Address.lpSockaddr->sa_family; |
| if (family == AF_INET) { |
| struct sockaddr_in *sa_in = (struct sockaddr_in *) |
| pUnicast->Address.lpSockaddr; |
| intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, |
| bufflen); |
| } |
| else if (family == AF_INET6) { |
| struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) |
| pUnicast->Address.lpSockaddr; |
| intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr), |
| buff, bufflen); |
| } |
| else { |
| // we should never get here |
| pUnicast = pUnicast->Next; |
| continue; |
| } |
| |
| if (intRet == NULL) { |
| PyErr_SetFromWindowsErr(GetLastError()); |
| goto error; |
| } |
| #if PY_MAJOR_VERSION >= 3 |
| py_address = PyUnicode_FromString(buff); |
| #else |
| py_address = PyString_FromString(buff); |
| #endif |
| if (py_address == NULL) |
| goto error; |
| |
| Py_INCREF(Py_None); |
| Py_INCREF(Py_None); |
| py_tuple = Py_BuildValue( |
| "(siOOO)", |
| ifname, |
| family, |
| py_address, |
| Py_None, |
| Py_None |
| ); |
| |
| if (! py_tuple) |
| goto error; |
| if (PyList_Append(py_retlist, py_tuple)) |
| goto error; |
| Py_DECREF(py_tuple); |
| Py_DECREF(py_address); |
| |
| pUnicast = pUnicast->Next; |
| } |
| } |
| |
| pCurrAddresses = pCurrAddresses->Next; |
| } |
| |
| free(pAddresses); |
| return py_retlist; |
| |
| error: |
| if (pAddresses) |
| free(pAddresses); |
| Py_DECREF(py_retlist); |
| Py_XDECREF(py_tuple); |
| Py_XDECREF(py_address); |
| return NULL; |
| } |
| |
| |
| /* |
| * Provides stats about NIC interfaces installed on the system. |
| * TODO: get 'duplex' (currently it's hard coded to '2', aka |
| 'full duplex') |
| */ |
| static PyObject * |
| psutil_net_if_stats(PyObject *self, PyObject *args) |
| { |
| int i; |
| DWORD dwSize = 0; |
| DWORD dwRetVal = 0; |
| MIB_IFTABLE *pIfTable; |
| MIB_IFROW *pIfRow; |
| PIP_ADAPTER_ADDRESSES pAddresses = NULL; |
| PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; |
| char friendly_name[MAX_PATH]; |
| char descr[MAX_PATH]; |
| int ifname_found; |
| |
| PyObject *py_retdict = PyDict_New(); |
| PyObject *py_ifc_info = NULL; |
| PyObject *py_is_up = NULL; |
| |
| if (py_retdict == NULL) |
| return NULL; |
| |
| pAddresses = psutil_get_nic_addresses(); |
| if (pAddresses == NULL) |
| goto error; |
| |
| pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); |
| if (pIfTable == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| dwSize = sizeof(MIB_IFTABLE); |
| if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { |
| free(pIfTable); |
| pIfTable = (MIB_IFTABLE *) malloc(dwSize); |
| if (pIfTable == NULL) { |
| PyErr_NoMemory(); |
| goto error; |
| } |
| } |
| // Make a second call to GetIfTable to get the actual |
| // data we want. |
| if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) { |
| PyErr_SetString(PyExc_RuntimeError, "GetIfTable() failed"); |
| goto error; |
| } |
| |
| for (i = 0; i < (int) pIfTable->dwNumEntries; i++) { |
| pIfRow = (MIB_IFROW *) & pIfTable->table[i]; |
| |
| // GetIfTable is not able to give us NIC with "friendly names" |
| // so we determine them via GetAdapterAddresses() which |
| // provides friendly names *and* descriptions and find the |
| // ones that match. |
| ifname_found = 0; |
| pCurrAddresses = pAddresses; |
| while (pCurrAddresses) { |
| sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description); |
| if (lstrcmp(descr, pIfRow->bDescr) == 0) { |
| sprintf_s(friendly_name, MAX_PATH, "%wS", pCurrAddresses->FriendlyName); |
| ifname_found = 1; |
| break; |
| } |
| pCurrAddresses = pCurrAddresses->Next; |
| } |
| if (ifname_found == 0) { |
| // Name not found means GetAdapterAddresses() doesn't list |
| // this NIC, only GetIfTable, meaning it's not really a NIC |
| // interface so we skip it. |
| continue; |
| } |
| |
| // is up? |
| if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || |
| pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) && |
| pIfRow->dwAdminStatus == 1 ) { |
| py_is_up = Py_True; |
| } |
| else { |
| py_is_up = Py_False; |
| } |
| Py_INCREF(py_is_up); |
| |
| py_ifc_info = Py_BuildValue( |
| "(Oikk)", |
| py_is_up, |
| 2, // there's no way to know duplex so let's assume 'full' |
| pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb |
| pIfRow->dwMtu |
| ); |
| if (!py_ifc_info) |
| goto error; |
| if (PyDict_SetItemString(py_retdict, friendly_name, py_ifc_info)) |
| goto error; |
| Py_DECREF(py_ifc_info); |
| } |
| |
| free(pIfTable); |
| free(pAddresses); |
| return py_retdict; |
| |
| error: |
| Py_XDECREF(py_is_up); |
| Py_XDECREF(py_ifc_info); |
| Py_DECREF(py_retdict); |
| if (pIfTable != NULL) |
| free(pIfTable); |
| if (pAddresses != NULL) |
| free(pAddresses); |
| return NULL; |
| } |
| |
| |
| // ------------------------ Python init --------------------------- |
| |
| static PyMethodDef |
| PsutilMethods[] = |
| { |
| // --- per-process functions |
| |
| {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, |
| "Return process cmdline as a list of cmdline arguments"}, |
| {"proc_exe", psutil_proc_exe, METH_VARARGS, |
| "Return path of the process executable"}, |
| {"proc_name", psutil_proc_name, METH_VARARGS, |
| "Return process name"}, |
| {"proc_kill", psutil_proc_kill, METH_VARARGS, |
| "Kill the process identified by the given PID"}, |
| {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, |
| "Return tuple of user/kern time for the given PID"}, |
| {"proc_create_time", psutil_proc_create_time, METH_VARARGS, |
| "Return a float indicating the process create time expressed in " |
| "seconds since the epoch"}, |
| {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, |
| "Return a tuple of process memory information"}, |
| {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS, |
| "Alternate implementation"}, |
| {"proc_cwd", psutil_proc_cwd, METH_VARARGS, |
| "Return process current working directory"}, |
| {"proc_suspend", psutil_proc_suspend, METH_VARARGS, |
| "Suspend a process"}, |
| {"proc_resume", psutil_proc_resume, METH_VARARGS, |
| "Resume a process"}, |
| {"proc_open_files", psutil_proc_open_files, METH_VARARGS, |
| "Return files opened by process"}, |
| {"proc_username", psutil_proc_username, METH_VARARGS, |
| "Return the username of a process"}, |
| {"proc_threads", psutil_proc_threads, METH_VARARGS, |
| "Return process threads information as a list of tuple"}, |
| {"proc_wait", psutil_proc_wait, METH_VARARGS, |
| "Wait for process to terminate and return its exit code."}, |
| {"proc_priority_get", psutil_proc_priority_get, METH_VARARGS, |
| "Return process priority."}, |
| {"proc_priority_set", psutil_proc_priority_set, METH_VARARGS, |
| "Set process priority."}, |
| #if (_WIN32_WINNT >= 0x0600) // Windows Vista |
| {"proc_io_priority_get", psutil_proc_io_priority_get, METH_VARARGS, |
| "Return process IO priority."}, |
| {"proc_io_priority_set", psutil_proc_io_priority_set, METH_VARARGS, |
| "Set process IO priority."}, |
| #endif |
| {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, |
| "Return process CPU affinity as a bitmask."}, |
| {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, |
| "Set process CPU affinity."}, |
| {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, |
| "Get process I/O counters."}, |
| {"proc_is_suspended", psutil_proc_is_suspended, METH_VARARGS, |
| "Return True if one of the process threads is in a suspended state"}, |
| {"proc_num_handles", psutil_proc_num_handles, METH_VARARGS, |
| "Return the number of handles opened by process."}, |
| {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, |
| "Return a list of process's memory mappings"}, |
| |
| // --- alternative pinfo interface |
| {"proc_info", psutil_proc_info, METH_VARARGS, |
| "Various process information"}, |
| |
| // --- system-related functions |
| {"pids", psutil_pids, METH_VARARGS, |
| "Returns a list of PIDs currently running on the system"}, |
| {"ppid_map", psutil_ppid_map, METH_VARARGS, |
| "Return a {pid:ppid, ...} dict for all running processes"}, |
| {"pid_exists", psutil_pid_exists, METH_VARARGS, |
| "Determine if the process exists in the current process list."}, |
| {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, |
| "Returns the number of logical CPUs on the system"}, |
| {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, |
| "Returns the number of physical CPUs on the system"}, |
| {"boot_time", psutil_boot_time, METH_VARARGS, |
| "Return the system boot time expressed in seconds since the epoch."}, |
| {"virtual_mem", psutil_virtual_mem, METH_VARARGS, |
| "Return the total amount of physical memory, in bytes"}, |
| {"cpu_times", psutil_cpu_times, METH_VARARGS, |
| "Return system cpu times as a list"}, |
| {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, |
| "Return system per-cpu times as a list of tuples"}, |
| {"disk_usage", psutil_disk_usage, METH_VARARGS, |
| "Return path's disk total and free as a Python tuple."}, |
| {"net_io_counters", psutil_net_io_counters, METH_VARARGS, |
| "Return dict of tuples of networks I/O information."}, |
| {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, |
| "Return dict of tuples of disks I/O information."}, |
| {"users", psutil_users, METH_VARARGS, |
| "Return a list of currently connected users."}, |
| {"disk_partitions", psutil_disk_partitions, METH_VARARGS, |
| "Return disk partitions."}, |
| {"net_connections", psutil_net_connections, METH_VARARGS, |
| "Return system-wide connections"}, |
| {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, |
| "Return NICs addresses."}, |
| {"net_if_stats", psutil_net_if_stats, METH_VARARGS, |
| "Return NICs stats."}, |
| |
| // --- windows API bindings |
| {"win32_QueryDosDevice", psutil_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_windows_traverse(PyObject *m, visitproc visit, void *arg) { |
| Py_VISIT(GETSTATE(m)->error); |
| return 0; |
| } |
| |
| static int psutil_windows_clear(PyObject *m) { |
| Py_CLEAR(GETSTATE(m)->error); |
| return 0; |
| } |
| |
| static struct PyModuleDef moduledef = { |
| PyModuleDef_HEAD_INIT, |
| "psutil_windows", |
| NULL, |
| sizeof(struct module_state), |
| PsutilMethods, |
| NULL, |
| psutil_windows_traverse, |
| psutil_windows_clear, |
| NULL |
| }; |
| |
| #define INITERROR return NULL |
| |
| PyMODINIT_FUNC PyInit__psutil_windows(void) |
| |
| #else |
| #define INITERROR return |
| void init_psutil_windows(void) |
| #endif |
| { |
| struct module_state *st = NULL; |
| #if PY_MAJOR_VERSION >= 3 |
| PyObject *module = PyModule_Create(&moduledef); |
| #else |
| PyObject *module = Py_InitModule("_psutil_windows", PsutilMethods); |
| #endif |
| |
| if (module == NULL) { |
| INITERROR; |
| } |
| |
| st = GETSTATE(module); |
| st->error = PyErr_NewException("_psutil_windows.Error", NULL, NULL); |
| if (st->error == NULL) { |
| Py_DECREF(module); |
| INITERROR; |
| } |
| |
| PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); |
| |
| // process status 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); |
| // connection status constants |
| // http://msdn.microsoft.com/en-us/library/cc669305.aspx |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_CLOSED", MIB_TCP_STATE_CLOSED); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_CLOSING", MIB_TCP_STATE_CLOSING); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_CLOSE_WAIT", MIB_TCP_STATE_CLOSE_WAIT); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_LISTEN", MIB_TCP_STATE_LISTEN); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_ESTAB", MIB_TCP_STATE_ESTAB); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_SYN_SENT", MIB_TCP_STATE_SYN_SENT); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_SYN_RCVD", MIB_TCP_STATE_SYN_RCVD); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_FIN_WAIT1", MIB_TCP_STATE_FIN_WAIT1); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_FIN_WAIT2", MIB_TCP_STATE_FIN_WAIT2); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_LAST_ACK", MIB_TCP_STATE_LAST_ACK); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); |
| PyModule_AddIntConstant( |
| module, "MIB_TCP_STATE_DELETE_TCB", MIB_TCP_STATE_DELETE_TCB); |
| PyModule_AddIntConstant( |
| module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); |
| // ...for internal use in _psutil_windows.py |
| PyModule_AddIntConstant( |
| module, "INFINITE", INFINITE); |
| PyModule_AddIntConstant( |
| module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); |
| |
| // set SeDebug for the current process |
| psutil_set_se_debug(); |
| |
| #if PY_MAJOR_VERSION >= 3 |
| return module; |
| #endif |
| } |