summaryrefslogtreecommitdiff
path: root/psutil/_psutil_windows.c
diff options
context:
space:
mode:
Diffstat (limited to 'psutil/_psutil_windows.c')
-rw-r--r--psutil/_psutil_windows.c1225
1 files changed, 1 insertions, 1224 deletions
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index ef854332..272e39a8 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -14,23 +14,15 @@
* - NtResumeProcess
*/
-// Fixes clash between winsock2.h and windows.h
-#define WIN32_LEAN_AND_MEAN
-
#include <Python.h>
#include <windows.h>
-#include <Psapi.h> // memory_info(), memory_maps()
-#include <signal.h>
-#include <tlhelp32.h> // threads(), PROCESSENTRY32
-
-// Link with Iphlpapi.lib
-#pragma comment(lib, "IPHLPAPI.lib")
#include "_psutil_common.h"
#include "arch/windows/cpu.h"
#include "arch/windows/disk.h"
#include "arch/windows/mem.h"
#include "arch/windows/net.h"
+#include "arch/windows/proc.h"
#include "arch/windows/process_handles.h"
#include "arch/windows/process_info.h"
#include "arch/windows/process_utils.h"
@@ -41,1221 +33,6 @@
#include "arch/windows/sys.h"
#include "arch/windows/wmi.h"
-// Raised by Process.wait().
-static PyObject *TimeoutExpired;
-static PyObject *TimeoutAbandoned;
-
-
-
-/*
- * Return 1 if PID exists in the current process list, else 0.
- */
-static PyObject *
-psutil_pid_exists(PyObject *self, PyObject *args) {
- DWORD pid;
- int status;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &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 = PyLong_FromPid(proclist[i]);
- if (!py_pid)
- goto error;
- if (PyList_Append(py_retlist, py_pid))
- goto error;
- Py_CLEAR(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 pid;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
- return NULL;
- if (pid == 0)
- return AccessDenied("automatically set for PID 0");
-
- hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
- hProcess = psutil_check_phandle(hProcess, pid, 0);
- if (hProcess == NULL) {
- return NULL;
- }
-
- if (! TerminateProcess(hProcess, SIGTERM)) {
- // ERROR_ACCESS_DENIED may happen if the process already died. See:
- // https://github.com/giampaolo/psutil/issues/1099
- // http://bugs.python.org/issue14252
- if (GetLastError() != ERROR_ACCESS_DENIED) {
- PyErr_SetFromOSErrnoWithSyscall("TerminateProcess");
- 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;
- DWORD pid;
- long timeout;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID "l", &pid, &timeout))
- return NULL;
- if (pid == 0)
- return AccessDenied("automatically set for PID 0");
-
- 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_SetFromOSErrnoWithSyscall("OpenProcess");
- return NULL;
- }
- }
-
- // 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_times(PyObject *self, PyObject *args) {
- DWORD pid;
- HANDLE hProcess;
- FILETIME ftCreate, ftExit, ftKernel, ftUser;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &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("GetProcessTimes -> ERROR_ACCESS_DENIED");
- }
- 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(
- "(ddd)",
- (double)(ftUser.dwHighDateTime * HI_T + \
- ftUser.dwLowDateTime * LO_T),
- (double)(ftKernel.dwHighDateTime * HI_T + \
- ftKernel.dwLowDateTime * LO_T),
- psutil_FiletimeToUnixTime(ftCreate)
- );
-}
-
-
-/*
- * Return process executable path. Works for all processes regardless of
- * privilege. NtQuerySystemInformation has some sort of internal cache,
- * since it succeeds even when a process is gone (but not if a PID never
- * existed).
- */
-static PyObject *
-psutil_proc_exe(PyObject *self, PyObject *args) {
- DWORD pid;
- NTSTATUS status;
- PVOID buffer = NULL;
- ULONG bufferSize = 0x104 * 2; // WIN_MAX_PATH * sizeof(wchar_t)
- SYSTEM_PROCESS_ID_INFORMATION processIdInfo;
- PyObject *py_exe;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
- return NULL;
-
- if (pid == 0)
- return AccessDenied("automatically set for PID 0");
-
- buffer = MALLOC_ZERO(bufferSize);
- if (! buffer) {
- PyErr_NoMemory();
- return NULL;
- }
-
- processIdInfo.ProcessId = (HANDLE)(ULONG_PTR)pid;
- processIdInfo.ImageName.Length = 0;
- processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize;
- processIdInfo.ImageName.Buffer = buffer;
-
- status = NtQuerySystemInformation(
- SystemProcessIdInformation,
- &processIdInfo,
- sizeof(SYSTEM_PROCESS_ID_INFORMATION),
- NULL);
-
- if ((status == STATUS_INFO_LENGTH_MISMATCH) &&
- (processIdInfo.ImageName.MaximumLength <= bufferSize))
- {
- // Required length was NOT stored in MaximumLength (WOW64 issue).
- ULONG maxBufferSize = 0x7FFF * 2; // NTFS_MAX_PATH * sizeof(wchar_t)
- do {
- // Iteratively double the size of the buffer up to maxBufferSize
- bufferSize *= 2;
- FREE(buffer);
- buffer = MALLOC_ZERO(bufferSize);
- if (! buffer) {
- PyErr_NoMemory();
- return NULL;
- }
-
- processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize;
- processIdInfo.ImageName.Buffer = buffer;
-
- status = NtQuerySystemInformation(
- SystemProcessIdInformation,
- &processIdInfo,
- sizeof(SYSTEM_PROCESS_ID_INFORMATION),
- NULL);
- } while ((status == STATUS_INFO_LENGTH_MISMATCH) &&
- (bufferSize <= maxBufferSize));
- }
- else if (status == STATUS_INFO_LENGTH_MISMATCH) {
- // Required length is stored in MaximumLength.
- FREE(buffer);
- buffer = MALLOC_ZERO(processIdInfo.ImageName.MaximumLength);
- if (! buffer) {
- PyErr_NoMemory();
- return NULL;
- }
-
- processIdInfo.ImageName.Buffer = buffer;
-
- status = NtQuerySystemInformation(
- SystemProcessIdInformation,
- &processIdInfo,
- sizeof(SYSTEM_PROCESS_ID_INFORMATION),
- NULL);
- }
-
- if (! NT_SUCCESS(status)) {
- FREE(buffer);
- if (psutil_pid_is_running(pid) == 0)
- NoSuchProcess("psutil_pid_is_running -> 0");
- else
- psutil_SetFromNTStatusErr(status, "NtQuerySystemInformation");
- return NULL;
- }
-
- if (processIdInfo.ImageName.Buffer == NULL) {
- // Happens for PID 4.
- py_exe = Py_BuildValue("s", "");
- }
- else {
- py_exe = PyUnicode_FromWideChar(processIdInfo.ImageName.Buffer,
- processIdInfo.ImageName.Length / 2);
- }
- FREE(buffer);
- return py_exe;
-}
-
-
-/*
- * Return process memory information as a Python tuple.
- */
-static PyObject *
-psutil_proc_memory_info(PyObject *self, PyObject *args) {
- HANDLE hProcess;
- DWORD pid;
- PROCESS_MEMORY_COUNTERS_EX cnt;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &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;
- }
- 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)cnt.PrivateUsage);
-#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)cnt.PrivateUsage);
-#endif
-}
-
-
-static int
-psutil_GetProcWsetInformation(
- DWORD pid,
- HANDLE hProcess,
- PMEMORY_WORKING_SET_INFORMATION *wSetInfo)
-{
- NTSTATUS status;
- PVOID buffer;
- SIZE_T bufferSize;
-
- bufferSize = 0x8000;
- buffer = MALLOC_ZERO(bufferSize);
- if (! buffer) {
- PyErr_NoMemory();
- return 1;
- }
-
- while ((status = NtQueryVirtualMemory(
- hProcess,
- NULL,
- MemoryWorkingSetInformation,
- buffer,
- bufferSize,
- NULL)) == STATUS_INFO_LENGTH_MISMATCH)
- {
- FREE(buffer);
- bufferSize *= 2;
- // 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 = MALLOC_ZERO(bufferSize);
- if (! buffer) {
- PyErr_NoMemory();
- return 1;
- }
- }
-
- if (!NT_SUCCESS(status)) {
- if (status == STATUS_ACCESS_DENIED) {
- AccessDenied("NtQueryVirtualMemory -> STATUS_ACCESS_DENIED");
- }
- else if (psutil_pid_is_running(pid) == 0) {
- NoSuchProcess("psutil_pid_is_running -> 0");
- }
- else {
- PyErr_Clear();
- psutil_SetFromNTStatusErr(
- status, "NtQueryVirtualMemory(MemoryWorkingSetInformation)");
- }
- 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, _Py_PARSE_PID, &pid))
- return NULL;
- hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_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);
-}
-
-
-/*
- * Resume or suspends a process
- */
-static PyObject *
-psutil_proc_suspend_or_resume(PyObject *self, PyObject *args) {
- DWORD pid;
- NTSTATUS status;
- HANDLE hProcess;
- PyObject* suspend;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &suspend))
- return NULL;
-
- hProcess = psutil_handle_from_pid(pid, PROCESS_SUSPEND_RESUME);
- if (hProcess == NULL)
- return NULL;
-
- if (PyObject_IsTrue(suspend))
- status = NtSuspendProcess(hProcess);
- else
- status = NtResumeProcess(hProcess);
-
- if (! NT_SUCCESS(status)) {
- CloseHandle(hProcess);
- return psutil_SetFromNTStatusErr(status, "NtSuspend|ResumeProcess");
- }
-
- CloseHandle(hProcess);
- Py_RETURN_NONE;
-}
-
-
-static PyObject *
-psutil_proc_threads(PyObject *self, PyObject *args) {
- HANDLE hThread = NULL;
- THREADENTRY32 te32 = {0};
- DWORD 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, _Py_PARSE_PID, &pid))
- goto error;
- if (pid == 0) {
- // raise AD instead of returning 0 as procexp is able to
- // retrieve useful information somehow
- AccessDenied("forced for PID 0");
- goto error;
- }
-
- pid_return = psutil_pid_is_running(pid);
- if (pid_return == 0) {
- NoSuchProcess("psutil_pid_is_running -> 0");
- 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 * HI_T + \
- ftUser.dwLowDateTime * LO_T),
- (double)(ftKernel.dwHighDateTime * HI_T + \
- ftKernel.dwLowDateTime * LO_T));
- if (!py_tuple)
- goto error;
- if (PyList_Append(py_retlist, py_tuple))
- goto error;
- Py_CLEAR(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) {
- DWORD pid;
- HANDLE processHandle;
- DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
- PyObject *py_retlist;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
- return NULL;
-
- processHandle = psutil_handle_from_pid(pid, access);
- if (processHandle == NULL)
- return NULL;
-
- py_retlist = psutil_get_open_files(pid, processHandle);
- CloseHandle(processHandle);
- return py_retlist;
-}
-
-
-static PTOKEN_USER
-_psutil_user_token_from_pid(DWORD pid) {
- HANDLE hProcess = NULL;
- HANDLE hToken = NULL;
- PTOKEN_USER userToken = NULL;
- ULONG bufferSize = 0x100;
-
- hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION);
- if (hProcess == NULL)
- return NULL;
-
- if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
- PyErr_SetFromOSErrnoWithSyscall("OpenProcessToken");
- goto error;
- }
-
- // Get the user SID.
- while (1) {
- userToken = malloc(bufferSize);
- if (userToken == NULL) {
- PyErr_NoMemory();
- goto error;
- }
- if (!GetTokenInformation(hToken, TokenUser, userToken, bufferSize,
- &bufferSize))
- {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- free(userToken);
- continue;
- }
- else {
- PyErr_SetFromOSErrnoWithSyscall("GetTokenInformation");
- goto error;
- }
- }
- break;
- }
-
- CloseHandle(hProcess);
- CloseHandle(hToken);
- return userToken;
-
-error:
- if (hProcess != NULL)
- CloseHandle(hProcess);
- if (hToken != NULL)
- CloseHandle(hToken);
- return NULL;
-}
-
-
-/*
- * Return process username as a "DOMAIN//USERNAME" string.
- */
-static PyObject *
-psutil_proc_username(PyObject *self, PyObject *args) {
- DWORD pid;
- PTOKEN_USER userToken = NULL;
- WCHAR *userName = NULL;
- WCHAR *domainName = NULL;
- ULONG nameSize = 0x100;
- ULONG domainNameSize = 0x100;
- SID_NAME_USE nameUse;
- PyObject *py_username = NULL;
- PyObject *py_domain = NULL;
- PyObject *py_tuple = NULL;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
- return NULL;
- userToken = _psutil_user_token_from_pid(pid);
- if (userToken == NULL)
- return NULL;
-
- // resolve the SID to a name
- while (1) {
- userName = malloc(nameSize * sizeof(WCHAR));
- if (userName == NULL) {
- PyErr_NoMemory();
- goto error;
- }
- domainName = malloc(domainNameSize * sizeof(WCHAR));
- if (domainName == NULL) {
- PyErr_NoMemory();
- goto error;
- }
- if (!LookupAccountSidW(NULL, userToken->User.Sid, userName, &nameSize,
- domainName, &domainNameSize, &nameUse))
- {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- free(userName);
- free(domainName);
- continue;
- }
- else if (GetLastError() == ERROR_NONE_MAPPED) {
- // From MS doc:
- // https://docs.microsoft.com/en-us/windows/win32/api/winbase/
- // nf-winbase-lookupaccountsida
- // If the function cannot find an account name for the SID,
- // GetLastError returns ERROR_NONE_MAPPED. This can occur if
- // a network time-out prevents the function from finding the
- // name. It also occurs for SIDs that have no corresponding
- // account name, such as a logon SID that identifies a logon
- // session.
- AccessDenied("LookupAccountSidW -> ERROR_NONE_MAPPED");
- goto error;
- }
- else {
- PyErr_SetFromOSErrnoWithSyscall("LookupAccountSidW");
- goto error;
- }
- }
- break;
- }
-
- py_domain = PyUnicode_FromWideChar(domainName, wcslen(domainName));
- if (! py_domain)
- goto error;
- py_username = PyUnicode_FromWideChar(userName, wcslen(userName));
- 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(userName);
- free(domainName);
- free(userToken);
- return py_tuple;
-
-error:
- if (userName != NULL)
- free(userName);
- if (domainName != NULL)
- free(domainName);
- if (userToken != NULL)
- free(userToken);
- Py_XDECREF(py_domain);
- Py_XDECREF(py_username);
- Py_XDECREF(py_tuple);
- return NULL;
-}
-
-
-/*
- * Get process priority as a Python integer.
- */
-static PyObject *
-psutil_proc_priority_get(PyObject *self, PyObject *args) {
- DWORD pid;
- DWORD priority;
- HANDLE hProcess;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &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) {
- DWORD pid;
- int priority;
- int retval;
- HANDLE hProcess;
- DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID "i", &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;
-}
-
-
-/*
- * Get process IO priority as a Python integer.
- */
-static PyObject *
-psutil_proc_io_priority_get(PyObject *self, PyObject *args) {
- DWORD pid;
- HANDLE hProcess;
- DWORD IoPriority;
- NTSTATUS status;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
- return NULL;
-
- hProcess = psutil_handle_from_pid(pid, PROCESS_QUERY_LIMITED_INFORMATION);
- if (hProcess == NULL)
- return NULL;
-
- status = NtQueryInformationProcess(
- hProcess,
- ProcessIoPriority,
- &IoPriority,
- sizeof(DWORD),
- NULL
- );
-
- CloseHandle(hProcess);
- if (! NT_SUCCESS(status))
- return psutil_SetFromNTStatusErr(status, "NtQueryInformationProcess");
- return Py_BuildValue("i", IoPriority);
-}
-
-
-/*
- * Set process IO priority.
- */
-static PyObject *
-psutil_proc_io_priority_set(PyObject *self, PyObject *args) {
- DWORD pid;
- DWORD prio;
- HANDLE hProcess;
- NTSTATUS status;
- DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
-
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID "i", &pid, &prio))
- return NULL;
-
- hProcess = psutil_handle_from_pid(pid, access);
- if (hProcess == NULL)
- return NULL;
-
- status = NtSetInformationProcess(
- hProcess,
- ProcessIoPriority,
- (PVOID)&prio,
- sizeof(DWORD)
- );
-
- CloseHandle(hProcess);
- if (! NT_SUCCESS(status))
- return psutil_SetFromNTStatusErr(status, "NtSetInformationProcess");
- Py_RETURN_NONE;
-}
-
-
-/*
- * 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, _Py_PARSE_PID, &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, _Py_PARSE_PID, &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, _Py_PARSE_PID "K", &pid, &mask))
-#else
- if (! PyArg_ParseTuple(args, _Py_PARSE_PID "k", &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, _Py_PARSE_PID, &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 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, _Py_PARSE_PID, &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);
-}
-
-
-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;
- 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, _Py_PARSE_PID, &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_CLEAR(py_tuple);
- Py_CLEAR(py_str);
- }
- 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 = PyLong_FromPid(pe.th32ProcessID);
- if (py_pid == NULL)
- goto error;
- py_ppid = PyLong_FromPid(pe.th32ParentProcessID);
- if (py_ppid == NULL)
- goto error;
- if (PyDict_SetItem(py_retdict, py_pid, py_ppid))
- goto error;
- Py_CLEAR(py_pid);
- Py_CLEAR(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;
-}
-
// ------------------------ Python init ---------------------------