1 /*
2 * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 *
6 * Routines common to all platforms.
7 */
8
9 #include <Python.h>
10 #include "_psutil_common.h"
11
12 // ====================================================================
13 // --- Global vars
14 // ====================================================================
15
16 int PSUTIL_DEBUG = 0;
17 int PSUTIL_TESTING = 0;
18 // PSUTIL_CONN_NONE
19
20
21 // ====================================================================
22 // --- Backward compatibility with missing Python.h APIs
23 // ====================================================================
24
25 // PyPy on Windows
26 #if defined(PSUTIL_WINDOWS) && defined(PYPY_VERSION)
27 #if !defined(PyErr_SetFromWindowsErrWithFilename)
28 PyObject *
PyErr_SetFromWindowsErrWithFilename(int winerr,const char * filename)29 PyErr_SetFromWindowsErrWithFilename(int winerr, const char *filename) {
30 PyObject *py_exc = NULL;
31 PyObject *py_winerr = NULL;
32
33 if (winerr == 0)
34 winerr = GetLastError();
35 if (filename == NULL) {
36 py_exc = PyObject_CallFunction(PyExc_OSError, "(is)", winerr,
37 strerror(winerr));
38 }
39 else {
40 py_exc = PyObject_CallFunction(PyExc_OSError, "(iss)", winerr,
41 strerror(winerr), filename);
42 }
43 if (py_exc == NULL)
44 return NULL;
45
46 py_winerr = Py_BuildValue("i", winerr);
47 if (py_winerr == NULL)
48 goto error;
49 if (PyObject_SetAttrString(py_exc, "winerror", py_winerr) != 0)
50 goto error;
51 PyErr_SetObject(PyExc_OSError, py_exc);
52 Py_XDECREF(py_exc);
53 return NULL;
54
55 error:
56 Py_XDECREF(py_exc);
57 Py_XDECREF(py_winerr);
58 return NULL;
59 }
60 #endif // !defined(PyErr_SetFromWindowsErrWithFilename)
61
62
63 // PyPy 2.7
64 #if !defined(PyErr_SetFromWindowsErr)
65 PyObject *
PyErr_SetFromWindowsErr(int winerr)66 PyErr_SetFromWindowsErr(int winerr) {
67 return PyErr_SetFromWindowsErrWithFilename(winerr, "");
68 }
69 #endif // !defined(PyErr_SetFromWindowsErr)
70 #endif // defined(PSUTIL_WINDOWS) && defined(PYPY_VERSION)
71
72
73 // ====================================================================
74 // --- Custom exceptions
75 // ====================================================================
76
77 /*
78 * Same as PyErr_SetFromErrno(0) but adds the syscall to the exception
79 * message.
80 */
81 PyObject *
PyErr_SetFromOSErrnoWithSyscall(const char * syscall)82 PyErr_SetFromOSErrnoWithSyscall(const char *syscall) {
83 char fullmsg[1024];
84
85 #ifdef PSUTIL_WINDOWS
86 sprintf(fullmsg, "(originated from %s)", syscall);
87 PyErr_SetFromWindowsErrWithFilename(GetLastError(), fullmsg);
88 #else
89 PyObject *exc;
90 sprintf(fullmsg, "%s (originated from %s)", strerror(errno), syscall);
91 exc = PyObject_CallFunction(PyExc_OSError, "(is)", errno, fullmsg);
92 PyErr_SetObject(PyExc_OSError, exc);
93 Py_XDECREF(exc);
94 #endif
95 return NULL;
96 }
97
98
99 /*
100 * Set OSError(errno=ESRCH, strerror="No such process (originated from")
101 * Python exception.
102 */
103 PyObject *
NoSuchProcess(const char * syscall)104 NoSuchProcess(const char *syscall) {
105 PyObject *exc;
106 char msg[1024];
107
108 sprintf(msg, "assume no such process (originated from %s)", syscall);
109 exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
110 PyErr_SetObject(PyExc_OSError, exc);
111 Py_XDECREF(exc);
112 return NULL;
113 }
114
115
116 /*
117 * Set OSError(errno=EACCES, strerror="Permission denied" (originated from ...)
118 * Python exception.
119 */
120 PyObject *
AccessDenied(const char * syscall)121 AccessDenied(const char *syscall) {
122 PyObject *exc;
123 char msg[1024];
124
125 sprintf(msg, "assume access denied (originated from %s)", syscall);
126 exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
127 PyErr_SetObject(PyExc_OSError, exc);
128 Py_XDECREF(exc);
129 return NULL;
130 }
131
132
133 // ====================================================================
134 // --- Global utils
135 // ====================================================================
136
137 /*
138 * Enable testing mode. This has the same effect as setting PSUTIL_TESTING
139 * env var. This dual method exists because updating os.environ on
140 * Windows has no effect. Called on unit tests setup.
141 */
142 PyObject *
psutil_set_testing(PyObject * self,PyObject * args)143 psutil_set_testing(PyObject *self, PyObject *args) {
144 PSUTIL_TESTING = 1;
145 PSUTIL_DEBUG = 1;
146 Py_INCREF(Py_None);
147 return Py_None;
148 }
149
150
151 /*
152 * Print a debug message on stderr. No-op if PSUTIL_DEBUG env var is not set.
153 */
154 void
psutil_debug(const char * format,...)155 psutil_debug(const char* format, ...) {
156 va_list argptr;
157 if (PSUTIL_DEBUG) {
158 va_start(argptr, format);
159 fprintf(stderr, "psutil-debug> ");
160 vfprintf(stderr, format, argptr);
161 fprintf(stderr, "\n");
162 va_end(argptr);
163 }
164 }
165
166
167 /*
168 * Called on module import on all platforms.
169 */
170 int
psutil_setup(void)171 psutil_setup(void) {
172 if (getenv("PSUTIL_DEBUG") != NULL)
173 PSUTIL_DEBUG = 1;
174 if (getenv("PSUTIL_TESTING") != NULL)
175 PSUTIL_TESTING = 1;
176 return 0;
177 }
178
179
180 // ============================================================================
181 // Utility functions (BSD)
182 // ============================================================================
183
184 #if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD) || defined(PSUTIL_DRAGONFLY)
185 void
convert_kvm_err(const char * syscall,char * errbuf)186 convert_kvm_err(const char *syscall, char *errbuf) {
187 char fullmsg[8192];
188
189 sprintf(fullmsg, "(originated from %s: %s)", syscall, errbuf);
190 if (strstr(errbuf, "Permission denied") != NULL)
191 AccessDenied(fullmsg);
192 else if (strstr(errbuf, "Operation not permitted") != NULL)
193 AccessDenied(fullmsg);
194 else
195 PyErr_Format(PyExc_RuntimeError, fullmsg);
196 }
197 #endif
198
199
200 // ====================================================================
201 // --- Windows
202 // ====================================================================
203
204 #ifdef PSUTIL_WINDOWS
205 #include <windows.h>
206
207 // Needed to make these globally visible.
208 int PSUTIL_WINVER;
209 SYSTEM_INFO PSUTIL_SYSTEM_INFO;
210 CRITICAL_SECTION PSUTIL_CRITICAL_SECTION;
211
212
213 // A wrapper around GetModuleHandle and GetProcAddress.
214 PVOID
psutil_GetProcAddress(LPCSTR libname,LPCSTR procname)215 psutil_GetProcAddress(LPCSTR libname, LPCSTR procname) {
216 HMODULE mod;
217 FARPROC addr;
218
219 if ((mod = GetModuleHandleA(libname)) == NULL) {
220 PyErr_SetFromWindowsErrWithFilename(0, libname);
221 return NULL;
222 }
223 if ((addr = GetProcAddress(mod, procname)) == NULL) {
224 PyErr_SetFromWindowsErrWithFilename(0, procname);
225 return NULL;
226 }
227 return addr;
228 }
229
230
231 // A wrapper around LoadLibrary and GetProcAddress.
232 PVOID
psutil_GetProcAddressFromLib(LPCSTR libname,LPCSTR procname)233 psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname) {
234 HMODULE mod;
235 FARPROC addr;
236
237 Py_BEGIN_ALLOW_THREADS
238 mod = LoadLibraryA(libname);
239 Py_END_ALLOW_THREADS
240 if (mod == NULL) {
241 PyErr_SetFromWindowsErrWithFilename(0, libname);
242 return NULL;
243 }
244 if ((addr = GetProcAddress(mod, procname)) == NULL) {
245 PyErr_SetFromWindowsErrWithFilename(0, procname);
246 FreeLibrary(mod);
247 return NULL;
248 }
249 // Causes crash.
250 // FreeLibrary(mod);
251 return addr;
252 }
253
254
255 /*
256 * Convert a NTSTATUS value to a Win32 error code and set the proper
257 * Python exception.
258 */
259 PVOID
psutil_SetFromNTStatusErr(NTSTATUS Status,const char * syscall)260 psutil_SetFromNTStatusErr(NTSTATUS Status, const char *syscall) {
261 ULONG err;
262 char fullmsg[1024];
263
264 if (NT_NTWIN32(Status))
265 err = WIN32_FROM_NTSTATUS(Status);
266 else
267 err = RtlNtStatusToDosErrorNoTeb(Status);
268 // if (GetLastError() != 0)
269 // err = GetLastError();
270 sprintf(fullmsg, "(originated from %s)", syscall);
271 return PyErr_SetFromWindowsErrWithFilename(err, fullmsg);
272 }
273
274
275 static int
psutil_loadlibs()276 psutil_loadlibs() {
277 // --- Mandatory
278 NtQuerySystemInformation = psutil_GetProcAddressFromLib(
279 "ntdll.dll", "NtQuerySystemInformation");
280 if (! NtQuerySystemInformation)
281 return 1;
282 NtQueryInformationProcess = psutil_GetProcAddress(
283 "ntdll.dll", "NtQueryInformationProcess");
284 if (! NtQueryInformationProcess)
285 return 1;
286 NtSetInformationProcess = psutil_GetProcAddress(
287 "ntdll.dll", "NtSetInformationProcess");
288 if (! NtSetInformationProcess)
289 return 1;
290 NtQueryObject = psutil_GetProcAddressFromLib(
291 "ntdll.dll", "NtQueryObject");
292 if (! NtQueryObject)
293 return 1;
294 RtlIpv4AddressToStringA = psutil_GetProcAddressFromLib(
295 "ntdll.dll", "RtlIpv4AddressToStringA");
296 if (! RtlIpv4AddressToStringA)
297 return 1;
298 GetExtendedTcpTable = psutil_GetProcAddressFromLib(
299 "iphlpapi.dll", "GetExtendedTcpTable");
300 if (! GetExtendedTcpTable)
301 return 1;
302 GetExtendedUdpTable = psutil_GetProcAddressFromLib(
303 "iphlpapi.dll", "GetExtendedUdpTable");
304 if (! GetExtendedUdpTable)
305 return 1;
306 RtlGetVersion = psutil_GetProcAddressFromLib(
307 "ntdll.dll", "RtlGetVersion");
308 if (! RtlGetVersion)
309 return 1;
310 NtSuspendProcess = psutil_GetProcAddressFromLib(
311 "ntdll", "NtSuspendProcess");
312 if (! NtSuspendProcess)
313 return 1;
314 NtResumeProcess = psutil_GetProcAddressFromLib(
315 "ntdll", "NtResumeProcess");
316 if (! NtResumeProcess)
317 return 1;
318 NtQueryVirtualMemory = psutil_GetProcAddressFromLib(
319 "ntdll", "NtQueryVirtualMemory");
320 if (! NtQueryVirtualMemory)
321 return 1;
322 RtlNtStatusToDosErrorNoTeb = psutil_GetProcAddressFromLib(
323 "ntdll", "RtlNtStatusToDosErrorNoTeb");
324 if (! RtlNtStatusToDosErrorNoTeb)
325 return 1;
326 GetTickCount64 = psutil_GetProcAddress(
327 "kernel32", "GetTickCount64");
328 if (! GetTickCount64)
329 return 1;
330 RtlIpv6AddressToStringA = psutil_GetProcAddressFromLib(
331 "ntdll.dll", "RtlIpv6AddressToStringA");
332 if (! RtlIpv6AddressToStringA)
333 return 1;
334
335 // --- Optional
336 // minimum requirement: Win 7
337 GetActiveProcessorCount = psutil_GetProcAddress(
338 "kernel32", "GetActiveProcessorCount");
339 // minumum requirement: Win 7
340 GetLogicalProcessorInformationEx = psutil_GetProcAddressFromLib(
341 "kernel32", "GetLogicalProcessorInformationEx");
342 // minimum requirements: Windows Server Core
343 WTSEnumerateSessionsW = psutil_GetProcAddressFromLib(
344 "wtsapi32.dll", "WTSEnumerateSessionsW");
345 WTSQuerySessionInformationW = psutil_GetProcAddressFromLib(
346 "wtsapi32.dll", "WTSQuerySessionInformationW");
347 WTSFreeMemory = psutil_GetProcAddressFromLib(
348 "wtsapi32.dll", "WTSFreeMemory");
349
350 PyErr_Clear();
351 return 0;
352 }
353
354
355 static int
psutil_set_winver()356 psutil_set_winver() {
357 RTL_OSVERSIONINFOEXW versionInfo;
358 ULONG maj;
359 ULONG min;
360
361 versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
362 memset(&versionInfo, 0, sizeof(RTL_OSVERSIONINFOEXW));
363 RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo);
364 maj = versionInfo.dwMajorVersion;
365 min = versionInfo.dwMinorVersion;
366 if (maj == 6 && min == 0)
367 PSUTIL_WINVER = PSUTIL_WINDOWS_VISTA; // or Server 2008
368 else if (maj == 6 && min == 1)
369 PSUTIL_WINVER = PSUTIL_WINDOWS_7;
370 else if (maj == 6 && min == 2)
371 PSUTIL_WINVER = PSUTIL_WINDOWS_8;
372 else if (maj == 6 && min == 3)
373 PSUTIL_WINVER = PSUTIL_WINDOWS_8_1;
374 else if (maj == 10 && min == 0)
375 PSUTIL_WINVER = PSUTIL_WINDOWS_10;
376 else
377 PSUTIL_WINVER = PSUTIL_WINDOWS_NEW;
378 return 0;
379 }
380
381
382 int
psutil_load_globals()383 psutil_load_globals() {
384 if (psutil_loadlibs() != 0)
385 return 1;
386 if (psutil_set_winver() != 0)
387 return 1;
388 GetSystemInfo(&PSUTIL_SYSTEM_INFO);
389 InitializeCriticalSection(&PSUTIL_CRITICAL_SECTION);
390 return 0;
391 }
392
393
394 /*
395 * Convert the hi and lo parts of a FILETIME structure or a LARGE_INTEGER
396 * to a UNIX time.
397 * A FILETIME contains a 64-bit value representing the number of
398 * 100-nanosecond intervals since January 1, 1601 (UTC).
399 * A UNIX time is the number of seconds that have elapsed since the
400 * UNIX epoch, that is the time 00:00:00 UTC on 1 January 1970.
401 */
402 static double
_to_unix_time(ULONGLONG hiPart,ULONGLONG loPart)403 _to_unix_time(ULONGLONG hiPart, ULONGLONG loPart) {
404 ULONGLONG ret;
405
406 // 100 nanosecond intervals since January 1, 1601.
407 ret = hiPart << 32;
408 ret += loPart;
409 // Change starting time to the Epoch (00:00:00 UTC, January 1, 1970).
410 ret -= 116444736000000000ull;
411 // Convert nano secs to secs.
412 return (double) ret / 10000000ull;
413 }
414
415
416 double
psutil_FiletimeToUnixTime(FILETIME ft)417 psutil_FiletimeToUnixTime(FILETIME ft) {
418 return _to_unix_time((ULONGLONG)ft.dwHighDateTime,
419 (ULONGLONG)ft.dwLowDateTime);
420 }
421
422
423 double
psutil_LargeIntegerToUnixTime(LARGE_INTEGER li)424 psutil_LargeIntegerToUnixTime(LARGE_INTEGER li) {
425 return _to_unix_time((ULONGLONG)li.HighPart,
426 (ULONGLONG)li.LowPart);
427 }
428 #endif // PSUTIL_WINDOWS
429