/* * 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 #include #include #include #include // disk_io_counters() #include #include #include // users() #include // cpu_freq() #if (_WIN32_WINNT >= 0x0600) // Windows >= Vista #include // net_connections() #endif // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") #include "arch/windows/ntextapi.h" #include "arch/windows/global.h" #include "arch/windows/security.h" #include "arch/windows/process_info.h" #include "arch/windows/process_handles.h" #include "arch/windows/inet_ntop.h" #include "arch/windows/services.h" #include "_psutil_common.h" /* * ============================================================================ * Utilities * ============================================================================ */ #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define LO_T 1e-7 #define HI_T 429.4967296 #define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) #ifndef AF_INET6 #define AF_INET6 23 #endif 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() syscall failed."); return NULL; } return pAddresses; } /* * Return the number of logical, active CPUs. Return 0 if undetermined. * See discussion at: https://bugs.python.org/issue33166#msg314631 */ unsigned int psutil_get_num_cpus(int fail_on_err) { unsigned int ncpus = 0; // Minimum requirement: Windows 7 if (psutil_GetActiveProcessorCount != NULL) { ncpus = psutil_GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); if ((ncpus == 0) && (fail_on_err == 1)) { PyErr_SetFromWindowsErr(0); } } else { psutil_debug("GetActiveProcessorCount() not available; " "using GetSystemInfo()"); ncpus = (unsigned int)PSUTIL_SYSTEM_INFO.dwNumberOfProcessors; if ((ncpus <= 0) && (fail_on_err == 1)) { PyErr_SetString( PyExc_RuntimeError, "GetSystemInfo() failed to retrieve CPU count"); } } return ncpus; } /* * ============================================================================ * Public Python API * ============================================================================ */ // Raised by Process.wait(). static PyObject *TimeoutExpired; static PyObject *TimeoutAbandoned; /* * Return a Python float representing the system uptime expressed in seconds * since the epoch. */ static PyObject * psutil_boot_time(PyObject *self, PyObject *args) { ULONGLONG uptime; time_t pt; FILETIME fileTime; ULONGLONG 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 between 01-01-1970 and 01-01-1601, from time_t the divide by 1e+7 to get to the same base granularity. */ ll = (((ULONGLONG) (fileTime.dwHighDateTime)) << 32) + fileTime.dwLowDateTime; pt = (time_t)((ll - 116444736000000000ull) / 10000000ull); if (psutil_GetTickCount64 != NULL) { // Windows >= Vista uptime = psutil_GetTickCount64() / 1000ull; } else { // Windows XP. // GetTickCount() time will wrap around to zero if the // system is run continuously for 49.7 days. uptime = (ULONGLONG)GetTickCount() / 1000ull; } return Py_BuildValue("K", 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 *py_pid = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; proclist = psutil_get_pids(&numberOfReturnedPIDs); if (proclist == NULL) goto error; for (i = 0; i < numberOfReturnedPIDs; i++) { py_pid = Py_BuildValue("I", proclist[i]); if (!py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) goto error; Py_DECREF(py_pid); } // free C array allocated for PIDs free(proclist); return py_retlist; error: Py_XDECREF(py_pid); Py_DECREF(py_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; DWORD err; 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 psutil_debug("OpenProcess -> ERROR_INVALID_PARAMETER turned " "into NoSuchProcess"); NoSuchProcess(""); } else { PyErr_SetFromWindowsErr(0); } return NULL; } // kill the process if (! TerminateProcess(hProcess, SIGTERM)) { err = GetLastError(); // See: https://github.com/giampaolo/psutil/issues/1099 if (err != ERROR_ACCESS_DENIED) { PyErr_SetFromOSErrnoWithSyscall("TerminateProcess"); 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 return PyErr_SetFromWindowsErr(0); } // wait until the process has terminated Py_BEGIN_ALLOW_THREADS retVal = WaitForSingleObject(hProcess, timeout); Py_END_ALLOW_THREADS // handle return code if (retVal == WAIT_FAILED) { PyErr_SetFromOSErrnoWithSyscall("WaitForSingleObject"); CloseHandle(hProcess); return NULL; } if (retVal == WAIT_TIMEOUT) { PyErr_SetString(TimeoutExpired, "WaitForSingleObject() returned WAIT_TIMEOUT"); CloseHandle(hProcess); return NULL; } if (retVal == WAIT_ABANDONED) { psutil_debug("WaitForSingleObject() -> WAIT_ABANDONED"); PyErr_SetString(TimeoutAbandoned, "WaitForSingleObject() returned WAIT_ABANDONED"); CloseHandle(hProcess); return NULL; } // WaitForSingleObject() returned WAIT_OBJECT_0. It means the // process is gone so we can get its process exit code. The PID // may still stick around though but we'll handle that from Python. if (GetExitCodeProcess(hProcess, &ExitCode) == 0) { PyErr_SetFromOSErrnoWithSyscall("GetExitCodeProcess"); CloseHandle(hProcess); return NULL; } 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, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) return NULL; if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { if (GetLastError() == ERROR_ACCESS_DENIED) { // usually means the process has died so we throw a NoSuchProcess // here NoSuchProcess(""); } else { PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); /* * User and kernel times are represented as a FILETIME structure * which 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; HANDLE hProcess; 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, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) return NULL; if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { if (GetLastError() == ERROR_ACCESS_DENIED) { // usually means the process has died so we throw a // NoSuchProcess here NoSuchProcess(""); } else { PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); /* // 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) return PyErr_SetFromWindowsErr(0); } */ // 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 active, logical CPUs. */ static PyObject * psutil_cpu_count_logical(PyObject *self, PyObject *args) { unsigned int ncpus; ncpus = psutil_get_num_cpus(0); if (ncpus != 0) return Py_BuildValue("I", ncpus); else Py_RETURN_NONE; // mimick os.cpu_count() } /* * Return the number of physical CPU cores (hyper-thread CPUs count * is excluded). */ static PyObject * psutil_cpu_count_phys(PyObject *self, PyObject *args) { DWORD rc; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer = NULL; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX ptr = NULL; DWORD length = 0; DWORD offset = 0; DWORD ncpus = 0; // GetLogicalProcessorInformationEx() is available from Windows 7 // onward. Differently from GetLogicalProcessorInformation() // it supports process groups, meaning this is able to report more // than 64 CPUs. See: // https://bugs.python.org/issue33166 if (psutil_GetLogicalProcessorInformationEx == NULL) { psutil_debug("Win < 7; cpu_count_phys() forced to None"); Py_RETURN_NONE; } while (1) { rc = psutil_GetLogicalProcessorInformationEx( RelationAll, buffer, &length); if (rc == FALSE) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if (buffer) { free(buffer); } buffer = \ (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)malloc(length); if (NULL == buffer) { PyErr_NoMemory(); return NULL; } } else { psutil_debug("GetLogicalProcessorInformationEx() returned ", GetLastError()); goto return_none; } } else { break; } } ptr = buffer; while (ptr->Size > 0 && offset + ptr->Size <= length) { if (ptr->Relationship == RelationProcessorCore) { ncpus += 1; } offset += ptr->Size; ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)\ (((char*)ptr) + ptr->Size); } free(buffer); if (ncpus != 0) { return Py_BuildValue("I", ncpus); } else { psutil_debug("GetLogicalProcessorInformationEx() count was 0"); Py_RETURN_NONE; // mimick os.cpu_count() } return_none: 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, PyObject *kwdict) { long pid; int pid_return; int use_peb; PyObject *py_usepeb = Py_True; static char *keywords[] = {"pid", "use_peb", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "i|O", keywords, &pid, &py_usepeb)) { 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; use_peb = (py_usepeb == Py_True) ? 1 : 0; return psutil_get_cmdline(pid, use_peb); } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject * psutil_proc_environ(PyObject *self, PyObject *args) { long pid; int pid_return; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if ((pid == 0) || (pid == 4)) return Py_BuildValue("s", ""); pid_return = psutil_pid_is_running(pid); if (pid_return == 0) return NoSuchProcess(""); if (pid_return == -1) return NULL; return psutil_get_environ(pid); } /* * Return process executable path. */ static PyObject * psutil_proc_exe(PyObject *self, PyObject *args) { long pid; HANDLE hProcess; wchar_t exe[MAX_PATH]; #if (_WIN32_WINNT >= 0x0600) // >= Vista unsigned int size = sizeof(exe); #endif if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION); if (NULL == hProcess) return NULL; // Here we differentiate between XP and Vista+ because // QueryFullProcessImageNameW is better than GetProcessImageFileNameW // (avoid using QueryDosDevice on the returned path), see: // https://github.com/giampaolo/psutil/issues/1394 #if (_WIN32_WINNT >= 0x0600) // Windows >= Vista memset(exe, 0, MAX_PATH); if (QueryFullProcessImageNameW(hProcess, 0, exe, &size) == 0) { PyErr_SetFromOSErrnoWithSyscall("QueryFullProcessImageNameW"); CloseHandle(hProcess); return NULL; } #else // Windows XP if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { // see: https://github.com/giampaolo/psutil/issues/1394 if (GetLastError() == 0) PyErr_SetFromWindowsErr(ERROR_ACCESS_DENIED); else PyErr_SetFromOSErrnoWithSyscall("GetProcessImageFileNameW"); CloseHandle(hProcess); return NULL; } #endif CloseHandle(hProcess); return PyUnicode_FromWideChar(exe, wcslen(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; PROCESSENTRY32W pentry; HANDLE hSnapShot; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); if (hSnapShot == INVALID_HANDLE_VALUE) return PyErr_SetFromOSErrnoWithSyscall("CreateToolhelp32Snapshot"); pentry.dwSize = sizeof(PROCESSENTRY32W); ok = Process32FirstW(hSnapShot, &pentry); if (! ok) { PyErr_SetFromOSErrnoWithSyscall("Process32FirstW"); CloseHandle(hSnapShot); return NULL; } while (ok) { if (pentry.th32ProcessID == pid) { CloseHandle(hSnapShot); return PyUnicode_FromWideChar( pentry.szExeFile, wcslen(pentry.szExeFile)); } ok = Process32NextW(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, PROCESS_QUERY_LIMITED_INFORMATION); if (NULL == hProcess) return NULL; if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, sizeof(cnt))) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } #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 } static int psutil_GetProcWsetInformation( DWORD pid, HANDLE hProcess, PMEMORY_WORKING_SET_INFORMATION *wSetInfo) { NTSTATUS status; PVOID buffer; SIZE_T bufferSize; bufferSize = 0x8000; buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufferSize); while ((status = psutil_NtQueryVirtualMemory( hProcess, NULL, MemoryWorkingSetInformation, buffer, bufferSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) { HeapFree(GetProcessHeap(), 0, buffer); bufferSize *= 2; psutil_debug("NtQueryVirtualMemory increase bufsize %zd", bufferSize); // Fail if we're resizing the buffer to something very large. if (bufferSize > 256 * 1024 * 1024) { PyErr_SetString(PyExc_RuntimeError, "NtQueryVirtualMemory bufsize is too large"); return 1; } buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bufferSize); } if (!NT_SUCCESS(status)) { if (status == STATUS_ACCESS_DENIED) { AccessDenied(""); } else if (psutil_pid_is_running(pid) == 0) { NoSuchProcess(""); } else { PyErr_Clear(); psutil_debug("NtQueryVirtualMemory failed with %i", status); PyErr_SetString(PyExc_RuntimeError, "NtQueryVirtualMemory failed"); } HeapFree(GetProcessHeap(), 0, buffer); return 1; } *wSetInfo = (PMEMORY_WORKING_SET_INFORMATION)buffer; return 0; } /* * Returns the USS of the process. * Reference: * https://dxr.mozilla.org/mozilla-central/source/xpcom/base/ * nsMemoryReporterManager.cpp */ static PyObject * psutil_proc_memory_uss(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; PSUTIL_PROCESS_WS_COUNTERS wsCounters; PMEMORY_WORKING_SET_INFORMATION wsInfo; ULONG_PTR i; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) return NULL; if (psutil_GetProcWsetInformation(pid, hProcess, &wsInfo) != 0) { CloseHandle(hProcess); return NULL; } memset(&wsCounters, 0, sizeof(PSUTIL_PROCESS_WS_COUNTERS)); for (i = 0; i < wsInfo->NumberOfEntries; i++) { // This is what ProcessHacker does. /* wsCounters.NumberOfPages++; if (wsInfo->WorkingSetInfo[i].ShareCount > 1) wsCounters.NumberOfSharedPages++; if (wsInfo->WorkingSetInfo[i].ShareCount == 0) wsCounters.NumberOfPrivatePages++; if (wsInfo->WorkingSetInfo[i].Shared) wsCounters.NumberOfShareablePages++; */ // This is what we do: count shared pages that only one process // is using as private (USS). if (!wsInfo->WorkingSetInfo[i].Shared || wsInfo->WorkingSetInfo[i].ShareCount <= 1) { wsCounters.NumberOfPrivatePages++; } } HeapFree(GetProcessHeap(), 0, wsInfo); CloseHandle(hProcess); return Py_BuildValue("I", wsCounters.NumberOfPrivatePages); } /* * 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) { double idle, kernel, user, system; FILETIME idle_time, kernel_time, user_time; if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) return PyErr_SetFromWindowsErr(0); idle = (double)((HI_T * idle_time.dwHighDateTime) + \ (LO_T * idle_time.dwLowDateTime)); user = (double)((HI_T * user_time.dwHighDateTime) + \ (LO_T * user_time.dwLowDateTime)); kernel = (double)((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("(ddd)", user, system, idle); } /* * Same as above but for all system CPUs. */ static PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { double idle, kernel, systemt, user, interrupt, dpc; NTSTATUS status; _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; UINT i; unsigned int ncpus; PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; // retrieves number of processors ncpus = psutil_get_num_cpus(1); if (ncpus == 0) goto error; // allocates an array of _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION // structures, one per processor sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ malloc(ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); if (sppi == NULL) { PyErr_NoMemory(); goto error; } // gets cpu time informations status = psutil_NtQuerySystemInformation( SystemProcessorPerformanceInformation, sppi, ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), NULL); if (status != 0) { PyErr_SetFromWindowsErr(0); goto error; } // computes system global times summing each // processor value idle = user = kernel = interrupt = dpc = 0; for (i = 0; i < ncpus; i++) { py_tuple = NULL; user = (double)((HI_T * sppi[i].UserTime.HighPart) + (LO_T * sppi[i].UserTime.LowPart)); idle = (double)((HI_T * sppi[i].IdleTime.HighPart) + (LO_T * sppi[i].IdleTime.LowPart)); kernel = (double)((HI_T * sppi[i].KernelTime.HighPart) + (LO_T * sppi[i].KernelTime.LowPart)); interrupt = (double)((HI_T * sppi[i].InterruptTime.HighPart) + (LO_T * sppi[i].InterruptTime.LowPart)); dpc = (double)((HI_T * sppi[i].DpcTime.HighPart) + (LO_T * sppi[i].DpcTime.LowPart)); // kernel time includes idle time on windows // we return only busy kernel time subtracting // idle time from kernel time systemt = kernel - idle; py_tuple = Py_BuildValue( "(ddddd)", user, systemt, idle, interrupt, dpc ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(sppi); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (sppi) free(sppi); return NULL; } /* * Return process current working directory as a Python string. */ static PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { long pid; int pid_return; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; pid_return = psutil_pid_is_running(pid); if (pid_return == 0) return NoSuchProcess(""); if (pid_return == -1) return NULL; return psutil_get_cwd(pid); } /* * Resume or suspends a process */ static PyObject * psutil_proc_suspend_or_resume(PyObject *self, PyObject *args) { long pid; int ret; HANDLE hProcess; PyObject* suspend; if (! PyArg_ParseTuple(args, "lO", &pid, &suspend)) return NULL; hProcess = psutil_handle_from_pid(pid, PROCESS_SUSPEND_RESUME); if (hProcess == NULL) return NULL; if (PyObject_IsTrue(suspend)) ret = psutil_NtSuspendProcess(hProcess); else ret = psutil_NtResumeProcess(hProcess); if (ret != 0) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); 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; HANDLE hThreadSnap = NULL; PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_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_SetFromOSErrnoWithSyscall("CreateToolhelp32Snapshot"); goto error; } // Fill in the size of the structure before using it te32.dwSize = sizeof(THREADENTRY32); if (! Thread32First(hThreadSnap, &te32)) { PyErr_SetFromOSErrnoWithSyscall("Thread32First"); 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) { py_tuple = 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_SetFromOSErrnoWithSyscall("GetThreadTimes"); goto error; } /* * User and kernel times are represented as a FILETIME structure * which 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 */ py_tuple = Py_BuildValue( "kdd", te32.th32ThreadID, (double)(ftUser.dwHighDateTime * 429.4967296 + \ ftUser.dwLowDateTime * 1e-7), (double)(ftKernel.dwHighDateTime * 429.4967296 + \ ftKernel.dwLowDateTime * 1e-7)); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); CloseHandle(hThread); } } while (Thread32Next(hThreadSnap, &te32)); CloseHandle(hThreadSnap); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_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 *py_retlist; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; processHandle = psutil_handle_from_pid(pid, access); if (processHandle == NULL) return NULL; py_retlist = psutil_get_open_files(pid, processHandle); if (py_retlist == NULL) { PyErr_SetFromWindowsErr(0); CloseHandle(processHandle); return NULL; } CloseHandle(processHandle); return py_retlist; } /* 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 = NULL; HANDLE tokenHandle = NULL; PTOKEN_USER user = NULL; ULONG bufferSize; WCHAR *name = NULL; WCHAR *domainName = NULL; ULONG nameSize; ULONG domainNameSize; SID_NAME_USE nameUse; PyObject *py_username = NULL; PyObject *py_domain = NULL; PyObject *py_tuple = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; processHandle = psutil_handle_from_pid( pid, PROCESS_QUERY_LIMITED_INFORMATION); if (processHandle == NULL) return NULL; if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) { PyErr_SetFromOSErrnoWithSyscall("OpenProcessToken"); goto error; } CloseHandle(processHandle); processHandle = NULL; // Get the user SID. bufferSize = 0x100; while (1) { user = malloc(bufferSize); if (user == NULL) { PyErr_NoMemory(); goto error; } if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, &bufferSize)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { free(user); continue; } else { PyErr_SetFromOSErrnoWithSyscall("GetTokenInformation"); goto error; } } break; } CloseHandle(tokenHandle); tokenHandle = NULL; // resolve the SID to a name nameSize = 0x100; domainNameSize = 0x100; while (1) { name = malloc(nameSize * sizeof(WCHAR)); if (name == NULL) { PyErr_NoMemory(); goto error; } domainName = malloc(domainNameSize * sizeof(WCHAR)); if (domainName == NULL) { PyErr_NoMemory(); goto error; } if (!LookupAccountSidW(NULL, user->User.Sid, name, &nameSize, domainName, &domainNameSize, &nameUse)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { free(name); free(domainName); continue; } else { PyErr_SetFromOSErrnoWithSyscall("LookupAccountSidW"); goto error; } } break; } py_domain = PyUnicode_FromWideChar(domainName, wcslen(domainName)); if (! py_domain) goto error; py_username = PyUnicode_FromWideChar(name, wcslen(name)); if (! py_username) goto error; py_tuple = Py_BuildValue("OO", py_domain, py_username); if (! py_tuple) goto error; Py_DECREF(py_domain); Py_DECREF(py_username); free(name); free(domainName); free(user); return py_tuple; error: if (processHandle != NULL) CloseHandle(processHandle); if (tokenHandle != NULL) CloseHandle(tokenHandle); if (name != NULL) free(name); if (domainName != NULL) free(domainName); if (user != NULL) free(user); Py_XDECREF(py_domain); Py_XDECREF(py_username); Py_XDECREF(py_tuple); return NULL; } // https://msdn.microsoft.com/library/aa365928.aspx static DWORD __GetExtendedTcpTable(_GetExtendedTcpTable call, ULONG address_family, PVOID * data, DWORD * size) { // Due to other processes being active on the machine, it's possible // that the size of the table increases between the moment where we // query the size and the moment where we query the data. Therefore, it's // important to call this in a loop to retry if that happens. // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error // and https://github.com/giampaolo/psutil/issues/1294 DWORD error = ERROR_INSUFFICIENT_BUFFER; *size = 0; *data = NULL; error = call(NULL, size, FALSE, address_family, TCP_TABLE_OWNER_PID_ALL, 0); while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) { *data = malloc(*size); if (*data == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; continue; } error = call(*data, size, FALSE, address_family, TCP_TABLE_OWNER_PID_ALL, 0); if (error != NO_ERROR) { free(*data); *data = NULL; } } return error; } // https://msdn.microsoft.com/library/aa365930.aspx static DWORD __GetExtendedUdpTable(_GetExtendedUdpTable call, ULONG address_family, PVOID * data, DWORD * size) { // Due to other processes being active on the machine, it's possible // that the size of the table increases between the moment where we // query the size and the moment where we query the data. Therefore, it's // important to call this in a loop to retry if that happens. // See https://github.com/giampaolo/psutil/pull/1335 concerning 0xC0000001 error // and https://github.com/giampaolo/psutil/issues/1294 DWORD error = ERROR_INSUFFICIENT_BUFFER; *size = 0; *data = NULL; error = call(NULL, size, FALSE, address_family, UDP_TABLE_OWNER_PID, 0); while (error == ERROR_INSUFFICIENT_BUFFER || error == 0xC0000001) { *data = malloc(*size); if (*data == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; continue; } error = call(*data, size, FALSE, address_family, UDP_TABLE_OWNER_PID, 0); if (error != NO_ERROR) { free(*data); *data = NULL; } } if (error == ERROR_NOT_ENOUGH_MEMORY) { PyErr_NoMemory(); return 1; } if (error != NO_ERROR) { PyErr_SetFromWindowsErr(error); return 1; } return 0; } #define psutil_conn_decref_objs() \ 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 * psutil_net_connections(PyObject *self, PyObject *args) { static long null_address[4] = { 0, 0, 0, 0 }; unsigned long pid; int pid_return; PVOID table = NULL; DWORD tableSize; DWORD error; 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]; CHAR addressBufferRemote[65]; PyObject *py_retlist; PyObject *py_conn_tuple = NULL; PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; PyObject *py_addr_tuple_local = NULL; PyObject *py_addr_tuple_remote = 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); // Import some functions. if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) goto error; if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { psutil_conn_decref_objs(); PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); return NULL; } if (pid != -1) { pid_return = psutil_pid_is_running(pid); if (pid_return == 0) { psutil_conn_decref_objs(); return NoSuchProcess(""); } else if (pid_return == -1) { psutil_conn_decref_objs(); return NULL; } } py_retlist = PyList_New(0); if (py_retlist == NULL) { psutil_conn_decref_objs(); return NULL; } // TCP IPv4 if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, AF_INET, &table, &tableSize); if (error != 0) goto error; 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; psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == 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; psutil_rtlIpv4AddressToStringA(&addr, addressBufferRemote); py_addr_tuple_remote = Py_BuildValue( "(si)", addressBufferRemote, BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); } else { py_addr_tuple_remote = PyTuple_New(0); } if (py_addr_tuple_remote == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET, SOCK_STREAM, py_addr_tuple_local, py_addr_tuple_remote, tcp4Table->table[i].dwState, tcp4Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } free(table); table = NULL; tableSize = 0; } // TCP IPv6 if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1) && (psutil_rtlIpv6AddressToStringA != NULL)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; error = __GetExtendedTcpTable(psutil_GetExtendedTcpTable, AF_INET6, &table, &tableSize); if (error != 0) goto error; 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); psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == 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); psutil_rtlIpv6AddressToStringA(&addr, addressBufferRemote); py_addr_tuple_remote = Py_BuildValue( "(si)", addressBufferRemote, BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); } else { py_addr_tuple_remote = PyTuple_New(0); } if (py_addr_tuple_remote == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET6, SOCK_STREAM, py_addr_tuple_local, py_addr_tuple_remote, tcp6Table->table[i].dwState, tcp6Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } free(table); table = NULL; tableSize = 0; } // UDP IPv4 if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, AF_INET, &table, &tableSize); if (error != 0) goto error; 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; psutil_rtlIpv4AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET, SOCK_DGRAM, py_addr_tuple_local, PyTuple_New(0), PSUTIL_CONN_NONE, udp4Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } free(table); table = NULL; tableSize = 0; } // UDP IPv6 if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1) && (psutil_rtlIpv6AddressToStringA != NULL)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; error = __GetExtendedUdpTable(psutil_GetExtendedUdpTable, AF_INET6, &table, &tableSize); if (error != 0) goto error; 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); psutil_rtlIpv6AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM, py_addr_tuple_local, PyTuple_New(0), PSUTIL_CONN_NONE, udp6Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } free(table); table = NULL; tableSize = 0; } psutil_conn_decref_objs(); return py_retlist; error: psutil_conn_decref_objs(); Py_XDECREF(py_conn_tuple); Py_XDECREF(py_addr_tuple_local); Py_XDECREF(py_addr_tuple_remote); Py_DECREF(py_retlist); 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, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) return NULL; priority = GetPriorityClass(hProcess); if (priority == 0) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); 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 access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; if (! PyArg_ParseTuple(args, "li", &pid, &priority)) return NULL; hProcess = psutil_handle_from_pid(pid, access); if (hProcess == NULL) return NULL; retval = SetPriorityClass(hProcess, priority); if (retval == 0) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); 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; DWORD IoPriority; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) return NULL; psutil_NtQueryInformationProcess( hProcess, ProcessIoPriority, &IoPriority, sizeof(DWORD), 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; DWORD prio; HANDLE hProcess; DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; if (! PyArg_ParseTuple(args, "li", &pid, &prio)) return NULL; hProcess = psutil_handle_from_pid(pid, access); if (hProcess == NULL) return NULL; psutil_NtSetInformationProcess( hProcess, ProcessIoPriority, (PVOID)&prio, sizeof(DWORD) ); 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, PROCESS_QUERY_LIMITED_INFORMATION); if (NULL == hProcess) return NULL; if (! GetProcessIoCounters(hProcess, &IoCounters)) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); return Py_BuildValue("(KKKKKK)", IoCounters.ReadOperationCount, IoCounters.WriteOperationCount, IoCounters.ReadTransferCount, IoCounters.WriteTransferCount, IoCounters.OtherOperationCount, IoCounters.OtherTransferCount); } /* * 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, PROCESS_QUERY_LIMITED_INFORMATION); if (hProcess == NULL) { return NULL; } if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } 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 access = 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(pid, access); if (hProcess == NULL) return NULL; if (SetProcessAffinityMask(hProcess, mask) == 0) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); Py_RETURN_NONE; } /* * Return True if all process threads are in waiting/suspended state. */ 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_SetFromWindowsErrWithFilename(0, path); 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) { DWORD dwRetVal = 0; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above MIB_IF_ROW2 *pIfRow = NULL; #else // Windows XP MIB_IFROW *pIfRow = NULL; #endif PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PyObject *py_retdict = PyDict_New(); PyObject *py_nic_info = NULL; PyObject *py_nic_name = NULL; if (py_retdict == NULL) return NULL; pAddresses = psutil_get_nic_addresses(); if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; while (pCurrAddresses) { py_nic_name = NULL; py_nic_info = NULL; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2)); #else // Windows XP pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); #endif if (pIfRow == NULL) { PyErr_NoMemory(); goto error; } #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2)); pIfRow->InterfaceIndex = pCurrAddresses->IfIndex; dwRetVal = GetIfEntry2(pIfRow); #else // Windows XP pIfRow->dwIndex = pCurrAddresses->IfIndex; dwRetVal = GetIfEntry(pIfRow); #endif if (dwRetVal != NO_ERROR) { PyErr_SetString(PyExc_RuntimeError, "GetIfEntry() or GetIfEntry2() syscalls failed."); goto error; } #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above py_nic_info = Py_BuildValue("(KKKKKKKK)", pIfRow->OutOctets, pIfRow->InOctets, (pIfRow->OutUcastPkts + pIfRow->OutNUcastPkts), (pIfRow->InUcastPkts + pIfRow->InNUcastPkts), pIfRow->InErrors, pIfRow->OutErrors, pIfRow->InDiscards, pIfRow->OutDiscards); #else // Windows XP py_nic_info = Py_BuildValue("(kkkkkkkk)", pIfRow->dwOutOctets, pIfRow->dwInOctets, (pIfRow->dwOutUcastPkts + pIfRow->dwOutNUcastPkts), (pIfRow->dwInUcastPkts + pIfRow->dwInNUcastPkts), pIfRow->dwInErrors, pIfRow->dwOutErrors, pIfRow->dwInDiscards, pIfRow->dwOutDiscards); #endif if (!py_nic_info) goto error; py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); 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. This may * require running "diskperf -y" command first. */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { DISK_PERFORMANCE diskPerformance; DWORD dwSize; HANDLE hDevice = NULL; char szDevice[MAX_PATH]; char szDeviceDisplay[MAX_PATH]; int devNum; int i; DWORD ioctrlSize; BOOL ret; PyObject *py_retdict = PyDict_New(); PyObject *py_tuple = 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_tuple = 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; // DeviceIoControl() sucks! i = 0; ioctrlSize = sizeof(diskPerformance); while (1) { i += 1; ret = DeviceIoControl( hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance, ioctrlSize, &dwSize, NULL); if (ret != 0) break; // OK! if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Retry with a bigger buffer (+ limit for retries). if (i <= 1024) { ioctrlSize *= 2; continue; } } else if (GetLastError() == ERROR_INVALID_FUNCTION) { // This happens on AppVeyor: // https://ci.appveyor.com/project/giampaolo/psutil/build/ // 1364/job/ascpdi271b06jle3 // Assume it means we're dealing with some exotic disk // and go on. psutil_debug("DeviceIoControl -> ERROR_INVALID_FUNCTION; " "ignore PhysicalDrive%i", devNum); goto next; } else if (GetLastError() == ERROR_NOT_SUPPORTED) { // Again, let's assume we're dealing with some exotic disk. psutil_debug("DeviceIoControl -> ERROR_NOT_SUPPORTED; " "ignore PhysicalDrive%i", devNum); goto next; } // XXX: it seems we should also catch ERROR_INVALID_PARAMETER: // https://sites.ualberta.ca/dept/aict/uts/software/openbsd/ // ports/4.1/i386/openafs/w-openafs-1.4.14-transarc/ // openafs-1.4.14/src/usd/usd_nt.c // XXX: we can also bump into ERROR_MORE_DATA in which case // (quoting doc) we're supposed to retry with a bigger buffer // and specify a new "starting point", whatever it means. PyErr_SetFromWindowsErr(0); goto error; } sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%i", devNum); py_tuple = Py_BuildValue( "(IILLKK)", diskPerformance.ReadCount, diskPerformance.WriteCount, diskPerformance.BytesRead, diskPerformance.BytesWritten, // convert to ms: // https://github.com/giampaolo/psutil/issues/1012 (unsigned long long) (diskPerformance.ReadTime.QuadPart) / 10000000, (unsigned long long) (diskPerformance.WriteTime.QuadPart) / 10000000); if (!py_tuple) goto error; if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_tuple)) goto error; Py_XDECREF(py_tuple); next: CloseHandle(hDevice); } return py_retdict; error: Py_XDECREF(py_tuple); 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; char mp_buf[MAX_PATH]; char mp_path[MAX_PATH]; int all; int type; int ret; unsigned int old_mode = 0; char opts[20]; HANDLE mp_h; BOOL mp_flag= TRUE; 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 old_mode = 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"); // Check for mount points on this volume and add/get info // (checks first to know if we can even have mount points) if (pflags & FILE_SUPPORTS_REPARSE_POINTS) { mp_h = FindFirstVolumeMountPoint(drive_letter, mp_buf, MAX_PATH); if (mp_h != INVALID_HANDLE_VALUE) { while (mp_flag) { // Append full mount path with drive letter strcpy_s(mp_path, _countof(mp_path), drive_letter); strcat_s(mp_path, _countof(mp_path), mp_buf); py_tuple = Py_BuildValue( "(ssss)", drive_letter, mp_path, fs_type, // Typically NTFS opts); if (!py_tuple || PyList_Append(py_retlist, py_tuple) == -1) { FindVolumeMountPointClose(mp_h); goto error; } Py_DECREF(py_tuple); // Continue looking for more mount points mp_flag = FindNextVolumeMountPoint(mp_h, mp_buf, MAX_PATH); } FindVolumeMountPointClose(mp_h); } } } 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(old_mode); return py_retlist; error: SetErrorMode(old_mode); 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 = WTS_CURRENT_SERVER_HANDLE; WCHAR *buffer_user = NULL; LPTSTR buffer_addr = NULL; PWTS_SESSION_INFO sessions = NULL; DWORD count; DWORD i; DWORD sessionId; DWORD bytes; PWTS_CLIENT_ADDRESS address; char address_str[50]; long long unix_time; WINSTATION_INFO station_info; ULONG returnLen; PyObject *py_tuple = NULL; PyObject *py_address = NULL; PyObject *py_username = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) { PyErr_SetFromOSErrnoWithSyscall("WTSEnumerateSessions"); 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 (WTSQuerySessionInformationW(hServer, sessionId, WTSUserName, &buffer_user, &bytes) == 0) { PyErr_SetFromOSErrnoWithSyscall("WTSQuerySessionInformationW"); goto error; } if (bytes <= 2) continue; // address bytes = 0; if (WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress, &buffer_addr, &bytes) == 0) { PyErr_SetFromOSErrnoWithSyscall("WTSQuerySessionInformation"); 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 (! psutil_WinStationQueryInformationW( hServer, sessionId, WinStationInformation, &station_info, sizeof(station_info), &returnLen)) { PyErr_SetFromOSErrnoWithSyscall("WinStationQueryInformationW"); goto error; } unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; unix_time += \ station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; unix_time /= 10000000; py_username = PyUnicode_FromWideChar(buffer_user, wcslen(buffer_user)); if (py_username == NULL) goto error; py_tuple = Py_BuildValue("OOd", py_username, py_address, (double)unix_time); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_XDECREF(py_username); Py_XDECREF(py_address); Py_XDECREF(py_tuple); } WTSFreeMemory(sessions); WTSFreeMemory(buffer_user); WTSFreeMemory(buffer_addr); return py_retlist; error: Py_XDECREF(py_username); Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_DECREF(py_retlist); 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, PROCESS_QUERY_LIMITED_INFORMATION); if (NULL == hProcess) return NULL; if (! GetProcessHandleCount(hProcess, &handleCount)) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } 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) * - cpu_times() (fallback) * - create_time() (fallback) * - io_counters() (fallback) * - memory_info() (fallback) */ static PyObject * psutil_proc_info(PyObject *self, PyObject *args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; ULONG i; ULONG ctx_switches = 0; double user_time; double kernel_time; long long create_time; SIZE_T mem_private; PyObject *py_retlist; 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++) ctx_switches += process->Threads[i].ContextSwitches; user_time = (double)process->UserTime.HighPart * HI_T + \ (double)process->UserTime.LowPart * LO_T; kernel_time = (double)process->KernelTime.HighPart * HI_T + \ (double)process->KernelTime.LowPart * LO_T; // 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; } #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 mem_private = process->PrivatePageCount; #else mem_private = 0; #endif py_retlist = Py_BuildValue( #if defined(_WIN64) "kkdddiKKKKKK" "kKKKKKKKKK", #else "kkdddiKKKKKK" "kIIIIIIIII", #endif process->HandleCount, // num handles ctx_switches, // num ctx switches user_time, // cpu user time kernel_time, // cpu kernel time (double)create_time, // create time (int)process->NumberOfThreads, // num threads // IO counters process->ReadOperationCount.QuadPart, // io rcount process->WriteOperationCount.QuadPart, // io wcount process->ReadTransferCount.QuadPart, // io rbytes process->WriteTransferCount.QuadPart, // io wbytes process->OtherOperationCount.QuadPart, // io others count process->OtherTransferCount.QuadPart, // io others bytes // memory process->PageFaultCount, // num page faults process->PeakWorkingSetSize, // peak wset process->WorkingSetSize, // wset process->QuotaPeakPagedPoolUsage, // peak paged pool process->QuotaPagedPoolUsage, // paged pool process->QuotaPeakNonPagedPoolUsage, // peak non paged pool process->QuotaNonPagedPoolUsage, // non paged pool process->PagefileUsage, // pagefile process->PeakPagefileUsage, // peak pagefile mem_private // private ); free(buffer); return py_retlist; } 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) { MEMORY_BASIC_INFORMATION basicInfo; DWORD pid; HANDLE hProcess = NULL; PVOID baseAddress; ULONGLONG previousAllocationBase; WCHAR mappedFileName[MAX_PATH]; LPVOID maxAddr; // required by GetMappedFileNameW DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_str = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; hProcess = psutil_handle_from_pid(pid, access); if (NULL == hProcess) goto error; maxAddr = PSUTIL_SYSTEM_INFO.lpMaximumApplicationAddress; baseAddress = NULL; while (VirtualQueryEx(hProcess, baseAddress, &basicInfo, sizeof(MEMORY_BASIC_INFORMATION))) { py_tuple = NULL; if (baseAddress > maxAddr) break; if (GetMappedFileNameW(hProcess, baseAddress, mappedFileName, sizeof(mappedFileName))) { py_str = PyUnicode_FromWideChar(mappedFileName, wcslen(mappedFileName)); if (py_str == NULL) goto error; #ifdef _WIN64 py_tuple = Py_BuildValue( "(KsOI)", (unsigned long long)baseAddress, #else py_tuple = Py_BuildValue( "(ksOI)", (unsigned long)baseAddress, #endif get_region_protection_string(basicInfo.Protect), py_str, basicInfo.RegionSize); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_DECREF(py_str); } previousAllocationBase = (ULONGLONG)basicInfo.AllocationBase; baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; } CloseHandle(hProcess); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_str); Py_DECREF(py_retlist); 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 *py_pid = NULL; PyObject *py_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 { py_pid = Py_BuildValue("I", pe.th32ProcessID); if (py_pid == NULL) goto error; py_ppid = Py_BuildValue("I", pe.th32ParentProcessID); if (py_ppid == NULL) goto error; if (PyDict_SetItem(py_retdict, py_pid, py_ppid)) goto error; Py_DECREF(py_pid); Py_DECREF(py_ppid); } while (Process32Next(handle, &pe)); } CloseHandle(handle); return py_retdict; error: Py_XDECREF(py_pid); Py_XDECREF(py_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; PCTSTR netmaskIntRet; char *ptr; char buff_addr[1024]; char buff_macaddr[1024]; char buff_netmask[1024]; DWORD dwRetVal = 0; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above ULONG converted_netmask; UINT netmask_bits; struct in_addr in_netmask; #endif 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; PyObject *py_nic_name = NULL; PyObject *py_netmask = NULL; if (py_retlist == NULL) return NULL; pAddresses = psutil_get_nic_addresses(); if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; while (pCurrAddresses) { pUnicast = pCurrAddresses->FirstUnicastAddress; netmaskIntRet = NULL; py_nic_name = NULL; py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); if (py_nic_name == NULL) goto error; // MAC address if (pCurrAddresses->PhysicalAddressLength != 0) { ptr = buff_macaddr; *ptr = '\0'; for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) { if (i == (pCurrAddresses->PhysicalAddressLength - 1)) { sprintf_s(ptr, _countof(buff_macaddr), "%.2X\n", (int)pCurrAddresses->PhysicalAddress[i]); } else { sprintf_s(ptr, _countof(buff_macaddr), "%.2X-", (int)pCurrAddresses->PhysicalAddress[i]); } ptr += 3; } *--ptr = '\0'; py_mac_address = Py_BuildValue("s", buff_macaddr); if (py_mac_address == NULL) goto error; Py_INCREF(Py_None); Py_INCREF(Py_None); Py_INCREF(Py_None); py_tuple = Py_BuildValue( "(OiOOOO)", py_nic_name, -1, // this will be converted later to AF_LINK py_mac_address, Py_None, // netmask (not supported) Py_None, // broadcast (not supported) Py_None // ptp (not supported on Windows) ); 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_addr, sizeof(buff_addr)); if (!intRet) goto error; #if (_WIN32_WINNT >= 0x0600) // Windows Vista and above netmask_bits = pUnicast->OnLinkPrefixLength; dwRetVal = ConvertLengthToIpv4Mask(netmask_bits, &converted_netmask); if (dwRetVal == NO_ERROR) { in_netmask.s_addr = converted_netmask; netmaskIntRet = inet_ntop( AF_INET, &in_netmask, buff_netmask, sizeof(buff_netmask)); if (!netmaskIntRet) goto error; } #endif } 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_addr, sizeof(buff_addr)); if (!intRet) goto error; } else { // we should never get here pUnicast = pUnicast->Next; continue; } #if PY_MAJOR_VERSION >= 3 py_address = PyUnicode_FromString(buff_addr); #else py_address = PyString_FromString(buff_addr); #endif if (py_address == NULL) goto error; if (netmaskIntRet != NULL) { #if PY_MAJOR_VERSION >= 3 py_netmask = PyUnicode_FromString(buff_netmask); #else py_netmask = PyString_FromString(buff_netmask); #endif } else { Py_INCREF(Py_None); py_netmask = Py_None; } Py_INCREF(Py_None); Py_INCREF(Py_None); py_tuple = Py_BuildValue( "(OiOOOO)", py_nic_name, family, py_address, py_netmask, Py_None, // broadcast (not supported) Py_None // ptp (not supported on Windows) ); if (! py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_DECREF(py_address); Py_DECREF(py_netmask); pUnicast = pUnicast->Next; } } Py_DECREF(py_nic_name); 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); Py_XDECREF(py_nic_name); Py_XDECREF(py_netmask); 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 descr[MAX_PATH]; int ifname_found; PyObject *py_nic_name = NULL; 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() syscall 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) { py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); if (py_nic_name == NULL) goto error; 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_SetItem(py_retdict, py_nic_name, py_ifc_info)) goto error; Py_DECREF(py_nic_name); Py_DECREF(py_ifc_info); } free(pIfTable); free(pAddresses); return py_retdict; error: Py_XDECREF(py_is_up); Py_XDECREF(py_ifc_info); Py_XDECREF(py_nic_name); Py_DECREF(py_retdict); if (pIfTable != NULL) free(pIfTable); if (pAddresses != NULL) free(pAddresses); return NULL; } /* * Return CPU statistics. */ static PyObject * psutil_cpu_stats(PyObject *self, PyObject *args) { NTSTATUS status; _SYSTEM_PERFORMANCE_INFORMATION *spi = NULL; _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; _SYSTEM_INTERRUPT_INFORMATION *InterruptInformation = NULL; unsigned int ncpus; UINT i; ULONG64 dpcs = 0; ULONG interrupts = 0; // retrieves number of processors ncpus = psutil_get_num_cpus(1); if (ncpus == 0) goto error; // get syscalls / ctx switches spi = (_SYSTEM_PERFORMANCE_INFORMATION *) \ malloc(ncpus * sizeof(_SYSTEM_PERFORMANCE_INFORMATION)); if (spi == NULL) { PyErr_NoMemory(); goto error; } status = psutil_NtQuerySystemInformation( SystemPerformanceInformation, spi, ncpus * sizeof(_SYSTEM_PERFORMANCE_INFORMATION), NULL); if (status != 0) { PyErr_SetFromOSErrnoWithSyscall( "NtQuerySystemInformation(SYSTEM_PERFORMANCE_INFORMATION)"); goto error; } // get DPCs InterruptInformation = \ malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) * ncpus); if (InterruptInformation == NULL) { PyErr_NoMemory(); goto error; } status = psutil_NtQuerySystemInformation( SystemInterruptInformation, InterruptInformation, ncpus * sizeof(SYSTEM_INTERRUPT_INFORMATION), NULL); if (status != 0) { PyErr_SetFromOSErrnoWithSyscall( "NtQuerySystemInformation(SYSTEM_INTERRUPT_INFORMATION)"); goto error; } for (i = 0; i < ncpus; i++) { dpcs += InterruptInformation[i].DpcCount; } // get interrupts sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \ malloc(ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); if (sppi == NULL) { PyErr_NoMemory(); goto error; } status = psutil_NtQuerySystemInformation( SystemProcessorPerformanceInformation, sppi, ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), NULL); if (status != 0) { PyErr_SetFromOSErrnoWithSyscall( "NtQuerySystemInformation(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)"); goto error; } for (i = 0; i < ncpus; i++) { interrupts += sppi[i].InterruptCount; } // done free(spi); free(InterruptInformation); free(sppi); return Py_BuildValue( "kkkk", spi->ContextSwitches, interrupts, (unsigned long)dpcs, spi->SystemCalls ); error: if (spi) free(spi); if (InterruptInformation) free(InterruptInformation); if (sppi) free(sppi); return NULL; } /* * Return CPU frequency. */ static PyObject * psutil_cpu_freq(PyObject *self, PyObject *args) { PROCESSOR_POWER_INFORMATION *ppi; NTSTATUS ret; ULONG size; LPBYTE pBuffer = NULL; ULONG current; ULONG max; unsigned int ncpus; // Get the number of CPUs. ncpus = psutil_get_num_cpus(1); if (ncpus == 0) return NULL; // Allocate size. size = ncpus * sizeof(PROCESSOR_POWER_INFORMATION); pBuffer = (BYTE*)LocalAlloc(LPTR, size); if (! pBuffer) return PyErr_SetFromWindowsErr(0); // Syscall. ret = CallNtPowerInformation( ProcessorInformation, NULL, 0, pBuffer, size); if (ret != 0) { PyErr_SetString(PyExc_RuntimeError, "CallNtPowerInformation syscall failed"); goto error; } // Results. ppi = (PROCESSOR_POWER_INFORMATION *)pBuffer; max = ppi->MaxMhz; current = ppi->CurrentMhz; LocalFree(pBuffer); return Py_BuildValue("kk", current, max); error: if (pBuffer != NULL) LocalFree(pBuffer); return NULL; } /* * Return battery usage stats. */ static PyObject * psutil_sensors_battery(PyObject *self, PyObject *args) { SYSTEM_POWER_STATUS sps; if (GetSystemPowerStatus(&sps) == 0) return PyErr_SetFromWindowsErr(0); return Py_BuildValue( "iiiI", sps.ACLineStatus, // whether AC is connected: 0=no, 1=yes, 255=unknown // status flag: // 1, 2, 4 = high, low, critical // 8 = charging // 128 = no battery sps.BatteryFlag, sps.BatteryLifePercent, // percent sps.BatteryLifeTime // remaining secs ); } /* * System memory page size as an int. */ static PyObject * psutil_getpagesize(PyObject *self, PyObject *args) { // XXX: we may want to use GetNativeSystemInfo to differentiate // page size for WoW64 processes (but am not sure). return Py_BuildValue("I", PSUTIL_SYSTEM_INFO.dwPageSize); } // ------------------------ Python init --------------------------- static PyMethodDef PsutilMethods[] = { // --- per-process functions {"proc_cmdline", (PyCFunction)(void(*)(void))psutil_proc_cmdline, METH_VARARGS | METH_KEYWORDS, "Return process cmdline as a list of cmdline arguments"}, {"proc_environ", psutil_proc_environ, METH_VARARGS, "Return process environment data"}, {"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_uss", psutil_proc_memory_uss, METH_VARARGS, "Return the USS of the process"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory"}, {"proc_suspend_or_resume", psutil_proc_suspend_or_resume, METH_VARARGS, "Suspend or 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."}, {"cpu_stats", psutil_cpu_stats, METH_VARARGS, "Return NICs stats."}, {"cpu_freq", psutil_cpu_freq, METH_VARARGS, "Return CPU frequency."}, {"sensors_battery", psutil_sensors_battery, METH_VARARGS, "Return battery metrics usage."}, {"getpagesize", psutil_getpagesize, METH_VARARGS, "Return system memory page size."}, // --- windows services {"winservice_enumerate", psutil_winservice_enumerate, METH_VARARGS, "List all services"}, {"winservice_query_config", psutil_winservice_query_config, METH_VARARGS, "Return service config"}, {"winservice_query_status", psutil_winservice_query_status, METH_VARARGS, "Return service config"}, {"winservice_query_descr", psutil_winservice_query_descr, METH_VARARGS, "Return the description of a service"}, {"winservice_start", psutil_winservice_start, METH_VARARGS, "Start a service"}, {"winservice_stop", psutil_winservice_stop, METH_VARARGS, "Stop a service"}, // --- windows API bindings {"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS, "QueryDosDevice binding"}, // --- others {"set_testing", psutil_set_testing, METH_NOARGS, "Set psutil in testing mode"}, {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; if (psutil_setup() != 0) INITERROR; if (psutil_load_globals() != 0) INITERROR; if (psutil_set_se_debug() != 0) INITERROR; st = GETSTATE(module); st->error = PyErr_NewException("_psutil_windows.Error", NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } // Exceptions. TimeoutExpired = PyErr_NewException( "_psutil_windows.TimeoutExpired", NULL, NULL); Py_INCREF(TimeoutExpired); PyModule_AddObject(module, "TimeoutExpired", TimeoutExpired); TimeoutAbandoned = PyErr_NewException( "_psutil_windows.TimeoutAbandoned", NULL, NULL); Py_INCREF(TimeoutAbandoned); PyModule_AddObject(module, "TimeoutAbandoned", TimeoutAbandoned); // version constant 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); // service status constants /* PyModule_AddIntConstant( module, "SERVICE_CONTINUE_PENDING", SERVICE_CONTINUE_PENDING); PyModule_AddIntConstant( module, "SERVICE_PAUSE_PENDING", SERVICE_PAUSE_PENDING); PyModule_AddIntConstant( module, "SERVICE_PAUSED", SERVICE_PAUSED); PyModule_AddIntConstant( module, "SERVICE_RUNNING", SERVICE_RUNNING); PyModule_AddIntConstant( module, "SERVICE_START_PENDING", SERVICE_START_PENDING); PyModule_AddIntConstant( module, "SERVICE_STOP_PENDING", SERVICE_STOP_PENDING); PyModule_AddIntConstant( module, "SERVICE_STOPPED", SERVICE_STOPPED); */ // ...for internal use in _psutil_windows.py PyModule_AddIntConstant( module, "INFINITE", INFINITE); PyModule_AddIntConstant( module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); PyModule_AddIntConstant( module, "ERROR_INVALID_NAME", ERROR_INVALID_NAME); PyModule_AddIntConstant( module, "ERROR_SERVICE_DOES_NOT_EXIST", ERROR_SERVICE_DOES_NOT_EXIST); PyModule_AddIntConstant( module, "WINVER", PSUTIL_WINVER); PyModule_AddIntConstant( module, "WINDOWS_XP", PSUTIL_WINDOWS_XP); PyModule_AddIntConstant( module, "WINDOWS_SERVER_2003", PSUTIL_WINDOWS_SERVER_2003); PyModule_AddIntConstant( module, "WINDOWS_VISTA", PSUTIL_WINDOWS_VISTA); PyModule_AddIntConstant( module, "WINDOWS_7", PSUTIL_WINDOWS_7); PyModule_AddIntConstant( module, "WINDOWS_8", PSUTIL_WINDOWS_8); PyModule_AddIntConstant( module, "WINDOWS_8_1", PSUTIL_WINDOWS_8_1); PyModule_AddIntConstant( module, "WINDOWS_10", PSUTIL_WINDOWS_10); #if PY_MAJOR_VERSION >= 3 return module; #endif }