Commit a53a068c authored by Jondy Zhao's avatar Jondy Zhao

Add snapshot of psutil-0.6.1

parent 3f0f7a79
Intro
=====
We would like to recognize some of the people who have been instrumental in the
development of psutil.
I'm sure we are forgetting some people (feel free to email us), but here is a
short list.
It's modeled after the Linux CREDITS file where the fields are:
name (N), e-mail (E), web-address (W), country (C), description (D), (I) issues
(issue tracker is at http://code.google.com/p/psutil/issues/list).
Really thanks to all of you.
Maintainers
===========
N: Giampaolo Rodola'
C: Italy
E: g.rodola@gmail.com
N: Jay Loden
C: NJ, USA
E: jloden@gmail.com
W: http://www.jayloden.com
Contributors
============
N: Jeremy Whitlock
E: jcscoobyrs@gmail.com
I: 125, 150, 174, 206
N: wj32
E: wj32.64@gmail.com
D: process username() and get_connections() on Windows
I: 114, 115
N: Yan Raber
C: Bologna, Italy
E: yanraber@gmail.com
D: help on Windows development
N: Dave Daeschler
C: USA
E: david.daeschler@gmail.com
D: initial design/bootstrap and continuing bug fixes
N: cjgohlke
E: cjgohlke@gmail.com
D: Windows 64 bit support
I: 107
N: Jeffery Kline
E: jeffery.kline@gmail.com
I: 130
N: Grabriel Monnerat
E: gabrielmonnerat@gmail.com
I: 146
N: Philip Roberts
E: philip.roberts@gmail.com
I: 168
N: jcscoobyrs
E: jcscoobyrs@gmail.com
I: 125
N: Sandro Tosi
E: sandro.tosi@gmail.com
I: 200, 201
N: Andrew Colin
E: andrew.colin@gmail.com
I: 248
N: Amoser
E: amoser@google.com
I: 266, 267
N: Matthew Grant
E: matthewgrant5@gmail.com
I: 271
N: oweidner
E: oweidner@cct.lsu.edu
I: 275
N: Tarek Ziade
E: ziade.tarek
I: 281
N: Luca Cipriani
C: Turin, Italy
E: luca.opensource@gmail.com
I: 278
N: Maciej Lach,
E: maciej.lach@gmail.com
I: 294
N: James Pye
E: james.pye@gmail.com
I: 305, 306
N: Stanchev Emil
E: stanchev.emil
I: 314
N: Kim Gräsman
E: kim.grasman@gmail.com
D: ...also kindly donated some money.
I: 316
N: Riccardo Murri
C: Italy
I: 318
Bug tracker at http://code.google.com/p/psutil/issues
0.6.1 - 2012-08-16
------------------
NEW FEATURES
* Issue 316: process cmdline property now makes a better job at guessing the
process executable from the cmdline.
BUG FIXES
* Issue 316: process exe was resolved in case it was a symlink.
* Issue 318: python 2.4 compatibility was broken.
API CHANGES
* process exe can now return an empty string instead of raising AccessDenied.
* process exe is no longer resolved in case it's a symlink.
0.6.0 - 2012-08-13
------------------
NEW FEATURES
* Issue 216: (UNIX) get_connections() UNIX sockets support.
* Issue 220: (BSD) get_connections() has been rewritten in C and no longer
requires lsof.
* Issue 222: (OSX) add support for process cwd.
* Issue 261: process extended memory info.
* Issue 295: (OSX) process executable path is now determined by asking the OS
instead of being guessed from process cmdline.
* Issue 297: (OSX) the Process methods below were always raising AccessDenied
for any process except the current one. Now this is no longer true. Also they
are 2.5x faster.
- name
- get_memory_info()
- get_memory_percent()
- get_cpu_times()
- get_cpu_percent()
- get_num_threads()
* Issue 300: examples/pmap.py script.
* Issue 301: process_iter() now yields processes sorted by their PIDs.
* Issue 302: process number of voluntary and involuntary context switches.
* Issue 303: (Windows) the Process methods below were always raising
AccessDenied for any process not owned by current user. Now this is no longer
true:
- create_time
- get_cpu_times()
- get_cpu_percent()
- get_memory_info()
- get_memory_percent()
- get_num_handles()
- get_io_counters()
* Issue 305: add examples/netstat.py script.
* Issue 311: system memory functions has been refactorized and rewritten and
now provide a more detailed and consistent representation of the system
memory.
New psutil.virtual_memory() function provides the following memory amounts:
- total
- available
- percent
- used
- active (UNIX)
- inactive (UNIX)
- buffers (BSD, Linux)
- cached (BSD, OSX)
- wired (OSX, BSD)
- shared (BSD)
New psutil.swap_memory() provides:
- total
- used
- free
- percent
- sin (no. of bytes the system has swapped in from disk (cumulative))
- sout (no. of bytes the system has swapped out from disk (cumulative))
All old memory-related functions are deprecated.
Also two new example scripts were added: free.py and meminfo.py.
* Issue 312: psutil.network_io_counters() namedtuple includes 4 new fields:
errin, errout dropin and dropout, reflecting the number of packets dropped
and with errors.
BUGFIXES
* Issue 298: (OSX - BSD) memory leak in get_num_fds().
* Issue 299: potential memory leak every time PyList_New(0) is used.
* Issue 303: (Windows) potential heap corruption in get_num_threads() and
get_status() Process methods.
* Issue 305: (BSD) psutil can't compile on FreeBSD 9 due to removal of utmp.h.
* Issue 306: at C level, errors are not checked when invoking Py* functions
which create or manipulate Python objects leading to potential memory related
errors and/or segmentation faults.
* Issue 307: (BSD) values returned by psutil.network_io_counters() are wrong.
* Issue 308: (BSD / Windows) psutil.virtmem_usage() wasn't actually returning
information about swap memory usage as it was supposed to do. It does now.
* Issue 309: get_open_files() might not return files which can not be accessed
due to limited permissions. AccessDenied is now raised instead.
API CHANGES
* psutil.phymem_usage() is deprecated (use psutil.virtual_memory())
* psutil.virtmem_usage() is deprecated (use psutil.swap_memory())
* psutil.phymem_buffers() on Linux is deprecated (use psutil.virtual_memory())
* psutil.cached_phymem() on Linux is deprecated (use psutil.virtual_memory())
* (Windows and BSD) psutil.virtmem_usage() now returns information about swap
memory instead of virtual memory.
0.5.1 - 2012-06-29
------------------
NEW FEATURES
* Issue 293: (Windows) process executable path is now determined by asking the
OS instead of being guessed from process cmdline.
BUGFIXES
* Issue 292: (Linux) race condition in process files/threads/connections.
* Issue 294: (Windows) Process CPU affinity is only able to set CPU #0.
0.5.0 - 2012-06-27
------------------
NEW FEATURES
* Issue #195: (Windows) number of handles opened by process.
* Issue #209: psutil.disk_partitions() now provides also mount options.
* Issue #229: list users currently connected on the system (psutil.get_users()).
* Issue #238: (Linux, Windows) process CPU affinity (get and set).
* Issue #242: Process.get_children(recursive=True): return all process
descendants.
* Issue #245: (POSIX) Process.wait() incrementally consumes less CPU cycles.
* Issue #257: (Windows) removed Windows 2000 support.
* Issue #258: (Linux) Process.get_memory_info() is now 0.5x faster.
* Issue #260: process's mapped memory regions. (Windows patch by wj32.64, OSX
patch by Jeremy Whitlock)
* Issue #262: (Windows) psutil.disk_partitions() was slow due to inspecting
the floppy disk drive also when "all" argument was False.
* Issue #273: psutil.get_process_list() is deprecated.
* Issue #274: psutil no longer requires 2to3 at installation time in order to
work with Python 3.
* Issue #278: new Process.as_dict() method.
* Issue #281: ppid, name, exe, cmdline and create_time properties of Process
class are now cached after being accessed.
* Issue #282: psutil.STATUS_* constants can now be compared by using their
string representation.
* Issue #283: speedup Process.is_running() by caching its return value in case
the process is terminated.
* Issue #284: (POSIX) per-process number of opened file descriptors.
* Issue #287: psutil.process_iter() now caches Process instances between calls.
* Issue #290: Process.nice property is deprecated in favor of new get_nice()
and set_nice() methods.
BUGFIXES
* Issue #193: psutil.Popen constructor can throw an exception if the spawned
process terminates quickly.
* Issue #240: (OSX) incorrect use of free() for Process.get_connections().
* Issue #244: (POSIX) Process.wait() can hog CPU resources if called against
a process which is not our children.
* Issue #248: (Linux) psutil.network_io_counters() might return erroneous NIC
names.
* Issue #252: (Windows) process getcwd() erroneously raise NoSuchProcess for
processes owned by another user. It now raises AccessDenied instead.
* Issue #266: (Windows) psutil.get_pid_list() only shows 1024 processes.
(patch by Amoser)
* Issue #267: (OSX) Process.get_connections() - an erroneous remote address
was returned. (Patch by Amoser)
* Issue #272: (Linux) Porcess.get_open_files() - potential race condition can
lead to unexpected NoSuchProcess exception. Also, we can get incorrect
reports of not absolutized path names.
* Issue #275: (Linux) Process.get_io_counters() erroneously raise NoSuchProcess
on old Linux versions. Where not available it now raises NotImplementedError.
* Issue #286: Process.is_running() doesn't actually check whether PID has been
reused.
* Issue #314: Process.get_children() can sometimes return non-children.
API CHANGES
* Process.nice property is deprecated in favor of new get_nice() and set_nice()
methods.
* psutil.get_process_list() is deprecated.
* ppid, name, exe, cmdline and create_time properties of Process class are now
cached after being accessed, meaning NoSuchProcess will no longer be raised
in case the process is gone in the meantime.
* psutil.STATUS_* constants can now be compared by using their string
representation.
0.4.1 - 2011-12-14
------------------
BUGFIXES
* Issue 228: some example scripts were not working with python 3.
* Issue 230: (Windows / OSX) memory leak in Process.get_connections().
* Issue 232: (Linux) psutil.phymem_usage() can report erroneous values which
are different than "free" command.
* Issue 236: (Windows) memory/handle leak in Process's get_memory_info(),
suspend() and resume() methods.
0.4.0 - 2011-10-29
------------------
NEW FEATURES
* Issue 150: network I/O counters. (OSX and Windows patch by Jeremy Whitlock)
* Issue 154: (FreeBSD) add support for process getcwd()
* Issue 157: (Windows) provide installer for Python 3.2 64-bit.
* Issue 198: Process.wait(timeout=0) can now be used to make wait() return
immediately.
* Issue 206: disk I/O counters. (OSX and Windows patch by Jeremy Whitlock)
* Issue 213: examples/iotop.py script.
* Issue 217: Process.get_connections() now has a "kind" argument to filter
for connections with different criteria.
* Issue 221: (FreeBSD) Process.get_open_files has been rewritten in C and no
longer relies on lsof.
* Issue 223: examples/top.py script.
* Issue 227: examples/nettop.py script.
BUGFIXES
* Issue 135: (OS X) psutil cannot create Process object
* Issue 144: (Linux) no longer support 0 special PID.
* Issue 188: (Linux) psutil import error on Linux ARM architectures.
* Issue 194: (POSIX) psutil.Process.get_cpu_percent() now reports a percentage
over 100 on multicore processors.
* Issue 197: (Linux) Process.get_connections() is broken on platforms not
supporting IPv6.
* Issue 200: (Linux) psutil.NUM_CPUS not working on armel and sparc
architectures and causing crash on module import.
* Issue 201: (Linux) Process.get_connections() is broken on big-endian
architectures.
* Issue 211: Process instance can unexpectedly raise NoSuchProcess if tested
for equality with another object.
* Issue 218: (Linux) crash at import time on Debian 64-bit because of a missing
line in /proc/meminfo.
* Issue 226: (FreeBSD) crash at import time on FreeBSD 7 and minor.
0.3.0 - 2011-07-08
------------------
NEW FEATURES
* Issue 125: system per-cpu percentage utilization and times.
* Issue 163: per-process associated terminal (TTY).
* Issue 171: added get_phymem() and get_virtmem() functions returning system
memory information (total, used, free) and memory percent usage.
total_* avail_* and used_* memory functions are deprecated.
* Issue 172: disk usage statistics.
* Issue 174: mounted disk partitions.
* Issue 179: setuptools is now used in setup.py
BUGFIXES
* Issue 159: SetSeDebug() does not close handles or unset impersonation on
return.
* Issue 164: wait function raises a TimeoutException when a process returns
-1 (Windows).
* Issue 165: process.status raises an unhandled exception.
* Issue 166: get_memory_info() leaks handles hogging system resources.
* Issue 168: psutil.cpu_percent() returns erroneous results when used in
non-blocking mode. (patch by Philip Roberts)
* Issue 178: OSX - Process.get_threads() leaks memory
* Issue 180: Windows - Process's get_num_threads() and get_threads() methods
can raise NoSuchProcess exception while process still exists.
0.2.1 - 2011-03-20
------------------
NEW FEATURES
* Issue 64: per-process I/O counters.
* Issue 116: per-process wait() (wait for process to terminate and return its
exit code).
* Issue 134: per-process get_threads() returning information (id, user and
kernel times) about threads opened by process.
* Issue 136: process executable path on FreeBSD is now determined by asking
the kernel instead of guessing it from cmdline[0].
* Issue 137: per-process real, effective and saved user and group ids.
* Issue 140: system boot time.
* Issue 142: per-process get and set niceness (priority).
* Issue 143: per-process status.
* Issue 147: per-process I/O nice (priority) - Linux only.
* Issue 148: psutil.Popen class which tidies up subprocess.Popen and
psutil.Process in a unique interface.
* Issue 152: (OSX) get_process_open_files() implementation has been rewritten
in C and no longer relies on lsof resulting in a 3x speedup.
* Issue 153: (OSX) get_process_connection() implementation has been rewritten
in C and no longer relies on lsof resulting in a 3x speedup.
BUGFIXES
* Issue 83: process cmdline is empty on OSX 64-bit.
* Issue 130: a race condition can cause IOError exception be raised on
Linux if process disappears between open() and subsequent read() calls.
* Issue 145: WindowsError was raised instead of psutil.AccessDenied when using
process resume() or suspend() on Windows.
* Issue 146: 'exe' property on Linux can raise TypeError if path contains NULL
bytes.
* Issue 151: exe and getcwd() for PID 0 on Linux return inconsistent data.
API CHANGES
* Process "uid" and "gid" properties are deprecated in favor of "uids" and
"gids" properties.
0.2.0 - 2010-11-13
------------------
NEW FEATURES
* Issue 79: per-process open files.
* Issue 88: total system physical cached memory.
* Issue 88: total system physical memory buffers used by the kernel.
* Issue 91: per-process send_signal() and terminate() methods.
* Issue 95: NoSuchProcess and AccessDenied exception classes now provide "pid",
"name" and "msg" attributes.
* Issue 97: per-process children.
* Issue 98: Process.get_cpu_times() and Process.get_memory_info now return
a namedtuple instead of a tuple.
* Issue 103: per-process opened TCP and UDP connections.
* Issue 107: add support for Windows 64 bit. (patch by cjgohlke)
* Issue 111: per-process executable name.
* Issue 113: exception messages now include process name and pid.
* Issue 114: process username Windows implementation has been rewritten in pure
C and no longer uses WMI resulting in a big speedup. Also, pywin32 is no
longer required as a third-party dependancy. (patch by wj32)
* Issue 117: added support for Windows 2000.
* Issue 123: psutil.cpu_percent() and psutil.Process.cpu_percent() accept a
new 'interval' parameter.
* Issue 129: per-process number of threads.
BUGFIXES
* Issue 80: fixed warnings when installing psutil with easy_install.
* Issue 81: psutil fails to compile with Visual Studio.
* Issue 94: suspend() raises OSError instead of AccessDenied.
* Issue 86: psutil didn't compile against FreeBSD 6.x.
* Issue 102: orphaned process handles obtained by using OpenProcess in C were
left behind every time Process class was instantiated.
* Issue 111: path and name Process properties report truncated or erroneous
values on UNIX.
* Issue 120: cpu_percent() always returning 100% on OS X.
* Issue 112: uid and gid properties don't change if process changes effective
user/group id at some point.
* Issue 126: ppid, uid, gid, name, exe, cmdline and create_time properties are
no longer cached and correctly raise NoSuchProcess exception if the process
disappears.
API CHANGES
* psutil.Process.path property is deprecated and works as an alias for "exe"
property.
* psutil.Process.kill(): signal argument was removed - to send a signal to the
process use send_signal(signal) method instead.
* psutil.Process.get_memory_info() returns a nametuple instead of a tuple.
* psutil.cpu_times() returns a nametuple instead of a tuple.
* New psutil.Process methods: get_open_files(), get_connections(),
send_signal() and terminate().
* ppid, uid, gid, name, exe, cmdline and create_time properties are no longer
cached and raise NoSuchProcess exception if process disappears.
* psutil.cpu_percent() no longer returns immediately (see issue 123).
* psutil.Process.get_cpu_percent() and psutil.cpu_percent() no longer returns
immediately by default (see issue 123).
0.1.3 - 2010-03-02
------------------
NEW FEATURES
* Issue 14: per-process username
* Issue 51: per-process current working directory (Windows and Linux only)
* Issue 59: Process.is_running() is now 10 times faster
* Issue 61: added supoprt for FreeBSD 64 bit
* Issue 71: implemented suspend/resume process
* Issue 75: python 3 support
BUGFIXES
* Issue 36: process cpu_times() and memory_info() functions succeeded also for
dead processes while a NoSuchProcess exception is supposed to be raised.
* Issue 48: incorrect size for mib array defined in getcmdargs for BSD
* Issue 49: possible memory leak due to missing free() on error condition on
* Issue 50: fixed getcmdargs() memory fragmentation on BSD
* Issue 55: test_pid_4 was failing on Windows Vista
* Issue 57: some unit tests were failing on systems where no swap memory is
available
* Issue 58: is_running() is now called before kill() to make sure we are going
to kill the correct process.
* Issue 73: virtual memory size reported on OS X includes shared library size
* Issue 77: NoSuchProcess wasn't raised on Process.create_time if kill() was
used first.
0.1.2 - 2009-05-06
------------------
NEW FEATURES
* Issue 32: Per-process CPU user/kernel times
* Issue 33: Process create time
* Issue 34: Per-process CPU utilization percentage
* Issue 38: Per-process memory usage (bytes)
* Issue 41: Per-process memory utilization (percent)
* Issue 39: System uptime
* Issue 43: Total system virtual memory
* Issue 46: Total system physical memory
* Issue 44: Total system used/free virtual and physical memory
BUGFIXES
* Issue 36: NoSuchProcess not raised on Windows when accessing timing methods
* Issue 40: test_get_cpu_times() failing on FreeBSD and OS X
* Issue 42: get_memory_percent() raises AccessDenied on Windows
0.1.1 - 2009-03-06
------------------
NEW FEATURES
* Issue 4: FreeBSD support for all functions of psutil
* Issue 9: Process.uid and Process.gid now retrieve process UID and GID.
* Issue 11: Support for parent/ppid - Process.parent property returns a
Process object representing the parent process, and Process.ppid returns
the parent PID.
* Issue 12 & 15: NoSuchProcess exception now raised when creating an object
for a nonexistent process, or when retrieving information about a process
that has gone away.
* Issue 21: AccessDenied exception created for raising access denied errors
from OSError or WindowsError on individual platforms.
* Issue 26: psutil.process_iter() function to iterate over processes as
Process objects with a generator.
* Process objects can now also be compared with == operator for equality
(PID, name, command line are compared).
BUGFIXES
* Issue 16: Special case for Windows' "System Idle Process" (PID 0) which
otherwise would return an "invalid parameter" exception.
* Issue 17: get_process_list() ignores NoSuchProcess and AccessDenied
exceptions during building of the list.
* Issue 22: Process(0).kill() was failing on Windows with an unset exception
* Issue 23: Special case for pid_exists(0)
* Issue 24: Process(0).kill() now raises AccessDenied exception instead of
WindowsError.
* Issue 30: psutil.get_pid_list() was returning two instances of PID 0 on OS
X and FreeBSD platforms.
0.1.0 - 2009-01-27
------------------
* Initial release.
==================
Using easy_install
==================
The easiest way to install psutil from sources is using easy_install.
Get the latest easy_install version from http://pypi.python.org/pypi/setuptools
and just run:
easy_install psutil
This should get the most updated psutil version from the Python pypi repository,
unpack it, compile it and install it automatically.
===================================
Installing on Windows using mingw32
===================================
After the mingw [1] environment is properly set up on your system you can
compile Windows sources by entering:
setup.py build -c mingw32
To compile and install just append the "install" keyword at the end of the
command line above, like this:
setup.py build -c mingw32 install
It might be possible that distutils will complain about missing gcc executable.
That means you have to add mingw bin PATH variable first.
Entering this line in the command prompt should do the work:
SET PATH=C:\MinGW\bin;%PATH%
NOTE: this assumes MinGW is installed in C:\MinGW, if not simply replace the
path in the command above with an appropriate location.
[1] http://www.mingw.org/
=========================================
Installing on Windows using Visual Studio
=========================================
To use Visual Studio to install psutil, you must have the same version of
Visual Studio used to compile your installation of Python. For older versions
of Python that will be Visual Studio 2003. For 2.6 and later it should be
Visual Studio 2008. If you do not have the requisite version of Visual Studio
available then it is recommended to use MinGW to compile psutil instead.
If you do have Visual Studio installed, you can use the basic distutils
commands:
setup.py build
...or to install and build:
setup.py install
distutils should take care of any necessary magic to compile from there.
==================
Installing on OS X
==================
OS X installation from source will require gcc which you can obtain as part of
the 'XcodeTools' installer from Apple. Then you can run the standard distutils
commands.
To build only:
python setup.py build
To install and build:
python setup.py install
NOTE: due to developer's hardware limitations psutil has only been compiled and
tested on OS X 10.4.11 so may or may not work on other versions.
=====================
Installing on FreeBSD
=====================
The same compiler used to install Python must be present on the system in order
to build modules using distutils. Assuming it is installed, you can build using
the standard distutils commands.
Build only:
python setup.py build
Install and build:
python setup.py install
===================
Installing on Linux
===================
gcc is required and so the python headers. They can easily be installed by using
the distro package manager. For example, on Ubuntu:
sudo apt-get install python-dev
Once done, you can install/build psutil with:
python setup.py install
psutil is distributed under BSD license reproduced below.
Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the psutil authors nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include CREDITS
include HISTORY
include LICENSE
include MANIFEST.in
include README
include setup.py
recursive-include psutil *.py *.c *.h
recursive-include test *.py
recursive-include examples *.py
Metadata-Version: 1.1
Name: psutil
Version: 0.6.1
Summary: A process and system utilities module for Python
Home-page: http://code.google.com/p/psutil/
Author: Giampaolo Rodola
Author-email: g.rodola <at> gmail <dot> com
License: License :: OSI Approved :: BSD License
Download-URL: http://psutil.googlecode.com/files/psutil-0.6.1.tar.gz
Description: ===========
Quick links
===========
* `Home page <http://code.google.com/p/psutil>`_
* `Download <http://code.google.com/p/psutil/downloads/list>`_
* `Documentation <http://code.google.com/p/psutil/wiki/Documentation>`_
=======
Summary
=======
psutil is a module providing an interface for retrieving information on all
running processes and system utilization (CPU, memory, disks, network, users) in
a portable way by using Python, implementing many functionalities offered by
command line tools such as: **ps, top, df, kill, free, lsof, free, netstat,
ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**.
It currently supports **Linux**, **Windows**, **OSX** and **FreeBSD** both
**32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using
a single code base.
==============
Example usages
==============
CPU
===
>>> import psutil
>>> psutil.cpu_times()
cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540,
iowait=629.509, irq=0.0, softirq=19.422)
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1)
...
4.0
5.9
3.8
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1, percpu=True)
...
[4.0, 6.9]
[7.0, 8.5]
[1.2, 9.0]
>>>
Memory
======
>>> psutil.virtual_memory()
vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L,
free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L,
cached=1251086336)
>>> psutil.swap_memory()
swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1,
sin=304193536, sout=677842944)
>>>
Disks
=====
>>> psutil.disk_partitions()
[partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
>>>
>>> psutil.disk_usage('/')
usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
>>>
>>> psutil.disk_io_counters()
iostat(read_count=719566, write_count=1082197, read_bytes=18626220032,
write_bytes=24081764352, read_time=5023392, write_time=63199568)
>>>
Network
=======
>>> psutil.network_io_counters(pernic=True)
{'lo': iostat(bytes_sent=799953745, bytes_recv=799953745,
packets_sent=453698, packets_recv=453698),
'eth0': iostat(bytes_sent=734324837, bytes_recv=4163935363,
packets_sent=3605828, packets_recv=4096685)}
>>>
Users
=====
>>> psutil.get_users()
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
>>>
Process management
==================
>>> import psutil
>>> psutil.get_pid_list()
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
>>>
>>> p = psutil.Process(7055)
>>> p.name
'python'
>>> p.exe
'/usr/bin/python'
>>> p.getcwd()
'/home/giampaolo'
>>> p.cmdline
['/usr/bin/python', 'main.py']
>>>
>>> str(p.status)
'running'
>>> p.username
'giampaolo'
>>> p.create_time
1267551141.5019531
>>> p.terminal
'/dev/pts/0'
>>>
>>> p.uids
user(real=1000, effective=1000, saved=1000)
>>> p.gids
group(real=1000, effective=1000, saved=1000)
>>>
>>> p.get_cpu_times()
cputimes(user=1.02, system=0.31)
>>> p.get_cpu_percent(interval=1.0)
12.1
>>> p.get_cpu_affinity()
[0, 1, 2, 3]
>>> p.set_cpu_affinity([0])
>>>
>>> p.get_memory_percent()
0.63423
>>>
>>> p.get_memory_info()
meminfo(rss=7471104, vms=68513792)
>>> p.get_ext_memory_info()
meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
>>> p.get_memory_maps()
[mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
mmap(path='[heap]', rss=54653, anonymous=8192, swap=0),
mmap(path='[stack]', rss=1542, anonymous=166, swap=0),
...]
>>>
>>> p.get_io_counters()
io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
>>>
>>> p.get_open_files()
[openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
>>>
>>> p.get_connections()
[connection(fd=115, family=2, type=1, local_address=('10.0.0.1', 48776),
remote_address=('93.186.135.91', 80), status='ESTABLISHED'),
connection(fd=117, family=2, type=1, local_address=('10.0.0.1', 43761),
remote_address=('72.14.234.100', 80), status='CLOSING'),
connection(fd=119, family=2, type=1, local_address=('10.0.0.1', 60759),
remote_address=('72.14.234.104', 80), status='ESTABLISHED'),
connection(fd=123, family=2, type=1, local_address=('10.0.0.1', 51314),
remote_address=('72.14.234.83', 443), status='SYN_SENT')]
>>>
>>> p.get_num_threads()
4
>>> p.get_num_fds()
8
>>> p.get_threads()
[thread(id=5234, user_time=22.5, system_time=9.2891),
thread(id=5235, user_time=0.0, system_time=0.0),
thread(id=5236, user_time=0.0, system_time=0.0),
thread(id=5237, user_time=0.0707, system_time=1.1)]
>>>
>>> p.get_num_ctx_switches()
amount(voluntary=78, involuntary=19)
>>>
>>> p.get_nice()
0
>>> p.set_nice(10)
>>>
>>> p.suspend()
>>> p.resume()
>>>
>>> p.terminate()
>>> p.wait(timeout=3)
0
>>>
>>> psutil.test()
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
root 1 0.0 0.0 24584 2240 ? Jun17 00:00 init
root 2 0.0 0.0 0 0 ? Jun17 00:00 kthreadd
root 3 0.0 0.0 0 0 ? Jun17 00:05 ksoftirqd/0
...
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
giampaolo 31721 0.0 2.2 773060 181896 ? 00:04 10:30 chrome
root 31763 0.0 0.0 0 0 ? 00:05 00:00 kworker/0:1
>>>
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,monitoring
Platform: Platform Independent
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft
Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.4
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.0
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Networking :: Monitoring
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: System :: Hardware
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
===========
Quick links
===========
* `Home page <http://code.google.com/p/psutil>`_
* `Download <http://code.google.com/p/psutil/downloads/list>`_
* `Documentation <http://code.google.com/p/psutil/wiki/Documentation>`_
=======
Summary
=======
psutil is a module providing an interface for retrieving information on all
running processes and system utilization (CPU, memory, disks, network, users) in
a portable way by using Python, implementing many functionalities offered by
command line tools such as: **ps, top, df, kill, free, lsof, free, netstat,
ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**.
It currently supports **Linux**, **Windows**, **OSX** and **FreeBSD** both
**32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using
a single code base.
==============
Example usages
==============
CPU
===
>>> import psutil
>>> psutil.cpu_times()
cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540,
iowait=629.509, irq=0.0, softirq=19.422)
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1)
...
4.0
5.9
3.8
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1, percpu=True)
...
[4.0, 6.9]
[7.0, 8.5]
[1.2, 9.0]
>>>
Memory
======
>>> psutil.virtual_memory()
vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L,
free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L,
cached=1251086336)
>>> psutil.swap_memory()
swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1,
sin=304193536, sout=677842944)
>>>
Disks
=====
>>> psutil.disk_partitions()
[partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
>>>
>>> psutil.disk_usage('/')
usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
>>>
>>> psutil.disk_io_counters()
iostat(read_count=719566, write_count=1082197, read_bytes=18626220032,
write_bytes=24081764352, read_time=5023392, write_time=63199568)
>>>
Network
=======
>>> psutil.network_io_counters(pernic=True)
{'lo': iostat(bytes_sent=799953745, bytes_recv=799953745,
packets_sent=453698, packets_recv=453698),
'eth0': iostat(bytes_sent=734324837, bytes_recv=4163935363,
packets_sent=3605828, packets_recv=4096685)}
>>>
Users
=====
>>> psutil.get_users()
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
>>>
Process management
==================
>>> import psutil
>>> psutil.get_pid_list()
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
>>>
>>> p = psutil.Process(7055)
>>> p.name
'python'
>>> p.exe
'/usr/bin/python'
>>> p.getcwd()
'/home/giampaolo'
>>> p.cmdline
['/usr/bin/python', 'main.py']
>>>
>>> str(p.status)
'running'
>>> p.username
'giampaolo'
>>> p.create_time
1267551141.5019531
>>> p.terminal
'/dev/pts/0'
>>>
>>> p.uids
user(real=1000, effective=1000, saved=1000)
>>> p.gids
group(real=1000, effective=1000, saved=1000)
>>>
>>> p.get_cpu_times()
cputimes(user=1.02, system=0.31)
>>> p.get_cpu_percent(interval=1.0)
12.1
>>> p.get_cpu_affinity()
[0, 1, 2, 3]
>>> p.set_cpu_affinity([0])
>>>
>>> p.get_memory_percent()
0.63423
>>>
>>> p.get_memory_info()
meminfo(rss=7471104, vms=68513792)
>>> p.get_ext_memory_info()
meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
>>> p.get_memory_maps()
[mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
mmap(path='[heap]', rss=54653, anonymous=8192, swap=0),
mmap(path='[stack]', rss=1542, anonymous=166, swap=0),
...]
>>>
>>> p.get_io_counters()
io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
>>>
>>> p.get_open_files()
[openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
>>>
>>> p.get_connections()
[connection(fd=115, family=2, type=1, local_address=('10.0.0.1', 48776),
remote_address=('93.186.135.91', 80), status='ESTABLISHED'),
connection(fd=117, family=2, type=1, local_address=('10.0.0.1', 43761),
remote_address=('72.14.234.100', 80), status='CLOSING'),
connection(fd=119, family=2, type=1, local_address=('10.0.0.1', 60759),
remote_address=('72.14.234.104', 80), status='ESTABLISHED'),
connection(fd=123, family=2, type=1, local_address=('10.0.0.1', 51314),
remote_address=('72.14.234.83', 443), status='SYN_SENT')]
>>>
>>> p.get_num_threads()
4
>>> p.get_num_fds()
8
>>> p.get_threads()
[thread(id=5234, user_time=22.5, system_time=9.2891),
thread(id=5235, user_time=0.0, system_time=0.0),
thread(id=5236, user_time=0.0, system_time=0.0),
thread(id=5237, user_time=0.0707, system_time=1.1)]
>>>
>>> p.get_num_ctx_switches()
amount(voluntary=78, involuntary=19)
>>>
>>> p.get_nice()
0
>>> p.set_nice(10)
>>>
>>> p.suspend()
>>> p.resume()
>>>
>>> p.terminate()
>>> p.wait(timeout=3)
0
>>>
>>> psutil.test()
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
root 1 0.0 0.0 24584 2240 ? Jun17 00:00 init
root 2 0.0 0.0 0 0 ? Jun17 00:00 kthreadd
root 3 0.0 0.0 0 0 ? Jun17 00:05 ksoftirqd/0
...
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
giampaolo 31721 0.0 2.2 773060 181896 ? 00:04 10:30 chrome
root 31763 0.0 0.0 0 0 ? 00:05 00:00 kworker/0:1
>>>
#!/usr/bin/env python
#
# $Id: disk_usage.py 1340 2012-06-09 13:42:21Z g.rodola $
#
# 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.
"""
List all mounted disk partitions a-la "df -h" command.
"""
import sys
import psutil
from psutil._compat import print_
def bytes2human(n):
# http://code.activestate.com/recipes/578019
# >>> bytes2human(10000)
# '9.8K'
# >>> bytes2human(100001221)
# '95.4M'
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i+1)*10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.1f%s' % (value, s)
return "%sB" % n
def main():
templ = "%-17s %8s %8s %8s %5s%% %9s %s"
print_(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount"))
for part in psutil.disk_partitions(all=False):
usage = psutil.disk_usage(part.mountpoint)
print_(templ % (part.device,
bytes2human(usage.total),
bytes2human(usage.used),
bytes2human(usage.free),
int(usage.percent),
part.fstype,
part.mountpoint))
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python
#
# $Id: free.py 1508 2012-08-13 12:30:07Z g.rodola $
#
# 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.
"""
A clone of 'free' cmdline utility.
"""
import psutil
from psutil._compat import print_
def main():
virt = psutil.virtual_memory()
swap = psutil.swap_memory()
templ = "%-7s %10s %10s %10s %10s %10s %10s"
print_(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache'))
print_(templ % ('Mem:', int(virt.total / 1024),
int(virt.used / 1024),
int(virt.free / 1024),
int(getattr(virt, 'shared', 0) / 1024),
int(getattr(virt, 'buffers', 0) / 1024),
int(getattr(virt, 'cached', 0) / 1024)))
print_(templ % ('Swap:', int(swap.total / 1024),
int(swap.used / 1024),
int(swap.free / 1024),
'', '', ''))
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: iotop.py 1236 2011-12-13 19:00:35Z g.rodola $
#
# 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.
"""
A clone of iotop (http://guichaz.free.fr/iotop/) showing real time
disk I/O statistics.
It works on Linux only (FreeBSD and OSX are missing support for IO
counters).
It doesn't work on Windows as curses module is required.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
import os
import sys
import psutil
if not hasattr(psutil.Process, 'get_io_counters') or os.name != 'posix':
sys.exit('platform not supported')
import time
import curses
import atexit
# --- curses stuff
def tear_down():
win.keypad(0)
curses.nocbreak()
curses.echo()
curses.endwin()
win = curses.initscr()
atexit.register(tear_down)
curses.endwin()
lineno = 0
def print_line(line, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
if highlight:
line += " " * (win.getmaxyx()[1] - len(line))
win.addstr(lineno, 0, line, curses.A_REVERSE)
else:
win.addstr(lineno, 0, line, 0)
except curses.error:
lineno = 0
win.refresh()
raise
else:
lineno += 1
# --- /curses stuff
def bytes2human(n):
"""
>>> bytes2human(10000)
'9.8 K/s'
>>> bytes2human(100001221)
'95.4 M/s'
"""
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i+1)*10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f %s/s' % (value, s)
return '%.2f B/s' % (n)
def poll(interval):
"""Calculate IO usage by comparing IO statics before and
after the interval.
Return a tuple including all currently running processes
sorted by IO activity and total disks I/O activity.
"""
# first get a list of all processes and disk io counters
procs = [p for p in psutil.process_iter()]
for p in procs[:]:
try:
p._before = p.get_io_counters()
except psutil.Error:
procs.remove(p)
continue
disks_before = psutil.disk_io_counters()
# sleep some time
time.sleep(interval)
# then retrieve the same info again
for p in procs[:]:
try:
p._after = p.get_io_counters()
p._cmdline = ' '.join(p.cmdline)
if not p._cmdline:
p._cmdline = p.name
p._username = p.username
except psutil.NoSuchProcess:
procs.remove(p)
disks_after = psutil.disk_io_counters()
# finally calculate results by comparing data before and
# after the interval
for p in procs:
p._read_per_sec = p._after.read_bytes - p._before.read_bytes
p._write_per_sec = p._after.write_bytes - p._before.write_bytes
p._total = p._read_per_sec + p._write_per_sec
disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes
disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes
# sort processes by total disk IO so that the more intensive
# ones get listed first
processes = sorted(procs, key=lambda p: p._total, reverse=True)
return (processes, disks_read_per_sec, disks_write_per_sec)
def refresh_window(procs, disks_read, disks_write):
"""Print results on screen by using curses."""
curses.endwin()
templ = "%-5s %-7s %11s %11s %s"
win.erase()
disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
% (bytes2human(disks_read), bytes2human(disks_write))
print_line(disks_tot)
header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
print_line(header, highlight=True)
for p in procs:
line = templ % (p.pid,
p._username[:7],
bytes2human(p._read_per_sec),
bytes2human(p._write_per_sec),
p._cmdline)
try:
print_line(line)
except curses.error:
break
win.refresh()
def main():
try:
interval = 0
while 1:
args = poll(interval)
refresh_window(*args)
interval = 1
except (KeyboardInterrupt, SystemExit):
pass
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: killall.py 1143 2011-10-05 19:11:59Z g.rodola $
#
# 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.
"""
Kill a process by name.
"""
import os
import sys
import psutil
def main():
if len(sys.argv) != 2:
sys.exit('usage: %s name' % __file__)
else:
NAME = sys.argv[1]
killed = []
for proc in psutil.process_iter():
if proc.name == NAME and proc.pid != os.getpid():
proc.kill()
killed.append(proc.pid)
if not killed:
sys.exit('%s: no process found' % NAME)
else:
sys.exit(0)
sys.exit(main())
#!/usr/bin/env python
#
# $Id: meminfo.py 1509 2012-08-13 12:31:18Z g.rodola $
#
# 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.
"""
Print system memory information.
"""
import psutil
from psutil._compat import print_
def to_meg(n):
return str(int(n / 1024 / 1024)) + "M"
def pprint_ntuple(nt):
for name in nt._fields:
value = getattr(nt, name)
if name != 'percent':
value = to_meg(value)
print_('%-10s : %7s' % (name.capitalize(), value))
def main():
print_('MEMORY\n------')
pprint_ntuple(psutil.virtual_memory())
print_('\nSWAP\n----')
pprint_ntuple(psutil.swap_memory())
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: netstat.py 1457 2012-07-14 18:09:36Z g.rodola $
#
# 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.
"""
A clone of 'netstat'.
"""
import socket
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
import psutil
from psutil._compat import print_
AD = "-"
AF_INET6 = getattr(socket, 'AF_INET6', object())
proto_map = {(AF_INET, SOCK_STREAM) : 'tcp',
(AF_INET6, SOCK_STREAM) : 'tcp6',
(AF_INET, SOCK_DGRAM) : 'udp',
(AF_INET6, SOCK_DGRAM) : 'udp6'}
def main():
templ = "%-5s %-22s %-22s %-13s %-6s %s"
print_(templ % ("Proto", "Local addr", "Remote addr", "Status", "PID",
"Program name"))
for p in psutil.process_iter():
name = '?'
try:
name = p.name
cons = p.get_connections(kind='inet')
except psutil.AccessDenied:
print_(templ % (AD, AD, AD, AD, p.pid, name))
else:
for c in cons:
raddr = ""
laddr = "%s:%s" % (c.local_address)
if c.remote_address:
raddr = "%s:%s" % (c.remote_address)
print_(templ % (proto_map[(c.family, c.type)],
laddr,
raddr,
str(c.status),
p.pid,
name[:15]))
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: iotop.py 1160 2011-10-14 18:50:36Z g.rodola@gmail.com $
#
# 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.
"""
Shows real-time network statistics.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
import sys
import os
if os.name != 'posix':
sys.exit('platform not supported')
import curses
import atexit
import time
import psutil
# --- curses stuff
def tear_down():
win.keypad(0)
curses.nocbreak()
curses.echo()
curses.endwin()
win = curses.initscr()
atexit.register(tear_down)
curses.endwin()
lineno = 0
def print_line(line, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
if highlight:
line += " " * (win.getmaxyx()[1] - len(line))
win.addstr(lineno, 0, line, curses.A_REVERSE)
else:
win.addstr(lineno, 0, line, 0)
except curses.error:
lineno = 0
win.refresh()
raise
else:
lineno += 1
# --- curses stuff
def bytes2human(n):
"""
>>> bytes2human(10000)
'9.8 K'
>>> bytes2human(100001221)
'95.4 M'
"""
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i+1)*10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.2f %s' % (value, s)
return '%.2f B' % (n)
def poll(interval):
"""Retrieve raw stats within an interval window."""
tot_before = psutil.network_io_counters()
pnic_before = psutil.network_io_counters(pernic=True)
# sleep some time
time.sleep(interval)
tot_after = psutil.network_io_counters()
pnic_after = psutil.network_io_counters(pernic=True)
return (tot_before, tot_after, pnic_before, pnic_after)
def refresh_window(tot_before, tot_after, pnic_before, pnic_after):
"""Print stats on screen."""
global lineno
# totals
print_line("total bytes: sent: %-10s received: %s" \
% (bytes2human(tot_after.bytes_sent),
bytes2human(tot_after.bytes_recv))
)
print_line("total packets: sent: %-10s received: %s" \
% (tot_after.packets_sent, tot_after.packets_recv)
)
# per-network interface details: let's sort network interfaces so
# that the ones which generated more traffic are shown first
print_line("")
nic_names = list(pnic_after.keys())
nic_names.sort(key=lambda x: sum(pnic_after[x]), reverse=True)
for name in nic_names:
stats_before = pnic_before[name]
stats_after = pnic_after[name]
templ = "%-15s %15s %15s"
print_line(templ % (name, "TOTAL", "PER-SEC"), highlight=True)
print_line(templ % (
"bytes-sent",
bytes2human(stats_after.bytes_sent),
bytes2human(stats_after.bytes_sent - stats_before.bytes_sent) + '/s',
))
print_line(templ % (
"bytes-recv",
bytes2human(stats_after.bytes_recv),
bytes2human(stats_after.bytes_recv - stats_before.bytes_recv) + '/s',
))
print_line(templ % (
"pkts-sent",
stats_after.packets_sent,
stats_after.packets_sent - stats_before.packets_sent,
))
print_line(templ % (
"pkts-recv",
stats_after.packets_recv,
stats_after.packets_recv - stats_before.packets_recv,
))
print_line("")
win.refresh()
lineno = 0
def main():
try:
interval = 0
while 1:
args = poll(interval)
refresh_window(*args)
interval = 1
except (KeyboardInterrupt, SystemExit):
pass
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: pmap.py 1420 2012-07-08 12:12:01Z g.rodola $
#
# 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.
"""
A clone of 'pmap' utility on Linux, 'vmmap' on OSX and 'procstat -v' on BSD.
Report memory map of a process.
"""
import sys
import psutil
from psutil._compat import print_
def main():
if len(sys.argv) != 2:
sys.exit('usage: pmap pid')
p = psutil.Process(int(sys.argv[1]))
print_("pid=%s, name=%s" % (p.pid, p.name))
templ = "%-16s %10s %-7s %s"
print_(templ % ("Address", "RSS", "Mode", "Mapping"))
total_rss = 0
for m in p.get_memory_maps(grouped=False):
total_rss += m.rss
print_(templ % (m.addr.split('-')[0].zfill(16),
str(m.rss / 1024) + 'K' ,
m.perms,
m.path))
print_("-" * 33)
print_(templ % ("Total", str(total_rss / 1024) + 'K', '', ''))
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: process_detail.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""
Print detailed information about a process.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
import os
import datetime
import socket
import sys
import psutil
def convert_bytes(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i+1)*10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.1f%s' % (value, s)
return "%sB" % n
def print_(a, b):
if sys.stdout.isatty() and os.name == 'posix':
fmt = '\x1b[1;32m%-17s\x1b[0m %s' %(a, b)
else:
fmt = '%-15s %s' %(a, b)
# python 2/3 compatibility layer
sys.stdout.write(fmt + '\n')
sys.stdout.flush()
def run(pid):
ACCESS_DENIED = ''
try:
p = psutil.Process(pid)
pinfo = p.as_dict(ad_value=ACCESS_DENIED)
except psutil.NoSuchProcess:
sys.exit(str(sys.exc_info()[1]))
try:
if p.parent:
parent = '(%s)' % p.parent.name
else:
parent = ''
except psutil.Error:
parent = ''
started = datetime.datetime.fromtimestamp(pinfo['create_time']
).strftime('%Y-%M-%d %H:%M')
io = pinfo.get('io_counters', None)
mem = '%s%% (resident=%s, virtual=%s) ' % (
round(pinfo['memory_percent'], 1),
convert_bytes(pinfo['memory_info'].rss),
convert_bytes(pinfo['memory_info'].vms))
children = p.get_children()
print_('pid', pinfo['pid'])
print_('name', pinfo['name'])
print_('exe', pinfo['exe'])
print_('parent', '%s %s' % (pinfo['ppid'], parent))
print_('cmdline', ' '.join(pinfo['cmdline']))
print_('started', started)
print_('user', pinfo['username'])
if os.name == 'posix':
print_('uids', 'real=%s, effective=%s, saved=%s' % pinfo['uids'])
print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids'])
print_('terminal', pinfo['terminal'] or '')
if hasattr(p, 'getcwd'):
print_('cwd', pinfo['cwd'])
print_('memory', mem)
print_('cpu', '%s%% (user=%s, system=%s)' % (pinfo['cpu_percent'],
pinfo['cpu_times'].user,
pinfo['cpu_times'].system))
print_('status', pinfo['status'])
print_('niceness', pinfo['nice'])
print_('num threads', pinfo['num_threads'])
if io != ACCESS_DENIED:
print_('I/O', 'bytes-read=%s, bytes-written=%s' % \
(convert_bytes(io.read_bytes),
convert_bytes(io.write_bytes)))
if children:
print_('children', '')
for child in children:
print_('', 'pid=%s name=%s' % (child.pid, child.name))
if pinfo['open_files'] != ACCESS_DENIED:
print_('open files', '')
for file in pinfo['open_files']:
print_('', 'fd=%s %s ' % (file.fd, file.path))
if pinfo['threads']:
print_('running threads', '')
for thread in pinfo['threads']:
print_('', 'id=%s, user-time=%s, sys-time=%s' \
% (thread.id, thread.user_time, thread.system_time))
if pinfo['connections'] != ACCESS_DENIED:
print_('open connections', '')
for conn in pinfo['connections']:
if conn.type == socket.SOCK_STREAM:
type = 'TCP'
elif conn.type == socket.SOCK_DGRAM:
type = 'UDP'
else:
type = 'UNIX'
lip, lport = conn.local_address
if not conn.remote_address:
rip, rport = '*', '*'
else:
rip, rport = conn.remote_address
print_('', '%s:%s -> %s:%s type=%s status=%s' \
% (lip, lport, rip, rport, type, conn.status))
def main(argv=None):
if argv is None:
argv = sys.argv
if len(argv) == 1:
sys.exit(run(os.getpid()))
elif len(argv) == 2:
sys.exit(run(int(argv[1])))
else:
sys.exit('usage: %s [pid]' % __file__)
if __name__ == '__main__':
sys.exit(main())
#!/usr/bin/env python
#
# $Id: top.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""
A clone of top / htop.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
import os
import sys
if os.name != 'posix':
sys.exit('platform not supported')
import time
import curses
import atexit
from datetime import datetime, timedelta
import psutil
# --- curses stuff
def tear_down():
win.keypad(0)
curses.nocbreak()
curses.echo()
curses.endwin()
win = curses.initscr()
atexit.register(tear_down)
curses.endwin()
lineno = 0
def print_line(line, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
if highlight:
line += " " * (win.getmaxyx()[1] - len(line))
win.addstr(lineno, 0, line, curses.A_REVERSE)
else:
win.addstr(lineno, 0, line, 0)
except curses.error:
lineno = 0
win.refresh()
raise
else:
lineno += 1
# --- /curses stuff
def bytes2human(n):
"""
>>> bytes2human(10000)
'9K'
>>> bytes2human(100001221)
'95M'
"""
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i+1)*10
for s in reversed(symbols):
if n >= prefix[s]:
value = int(float(n) / prefix[s])
return '%s%s' % (value, s)
return "%sB" % n
def poll(interval):
# sleep some time
time.sleep(interval)
procs = []
procs_status = {}
for p in psutil.process_iter():
try:
p.dict = p.as_dict(['username', 'get_nice', 'get_memory_info',
'get_memory_percent', 'get_cpu_percent',
'get_cpu_times', 'name', 'status'])
try:
procs_status[str(p.dict['status'])] += 1
except KeyError:
procs_status[str(p.dict['status'])] = 1
except psutil.NoSuchProcess:
pass
else:
procs.append(p)
# return processes sorted by CPU percent usage
processes = sorted(procs, key=lambda p: p.dict['cpu_percent'], reverse=True)
return (processes, procs_status)
def print_header(procs_status, num_procs):
"""Print system-related info, above the process list."""
def get_dashes(perc):
dashes = "|" * int((float(perc) / 10 * 4))
empty_dashes = " " * (40 - len(dashes))
return dashes, empty_dashes
# cpu usage
for cpu_num, perc in enumerate(psutil.cpu_percent(interval=0, percpu=True)):
dashes, empty_dashes = get_dashes(perc)
print_line(" CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes,
perc))
mem = psutil.virtual_memory()
dashes, empty_dashes = get_dashes(mem.percent)
used = mem.total - mem.available
line = " Mem [%s%s] %5s%% %6s/%s" % (
dashes, empty_dashes,
mem.percent,
str(int(used / 1024 / 1024)) + "M",
str(int(mem.total / 1024 / 1024)) + "M"
)
print_line(line)
# swap usage
swap = psutil.swap_memory()
dashes, empty_dashes = get_dashes(swap.percent)
line = " Swap [%s%s] %5s%% %6s/%s" % (
dashes, empty_dashes,
swap.percent,
str(int(swap.used / 1024 / 1024)) + "M",
str(int(swap.total / 1024 / 1024)) + "M"
)
print_line(line)
# processes number and status
st = []
for x, y in procs_status.items():
if y:
st.append("%s=%s" % (x, y))
st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
print_line(" Processes: %s (%s)" % (num_procs, ' '.join(st)))
# load average, uptime
uptime = datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME)
av1, av2, av3 = os.getloadavg()
line = " Load average: %.2f %.2f %.2f Uptime: %s" \
% (av1, av2, av3, str(uptime).split('.')[0])
print_line(line)
def refresh_window(procs, procs_status):
"""Print results on screen by using curses."""
curses.endwin()
templ = "%-6s %-8s %4s %5s %5s %6s %4s %9s %2s"
win.erase()
header = templ % ("PID", "USER", "NI", "VIRT", "RES", "CPU%", "MEM%",
"TIME+", "NAME")
print_header(procs_status, len(procs))
print_line("")
print_line(header, highlight=True)
for p in procs:
# TIME+ column shows process CPU cumulative time and it
# is expressed as: "mm:ss.ms"
if p.dict['cpu_times'] != None:
ctime = timedelta(seconds=sum(p.dict['cpu_times']))
ctime = "%s:%s.%s" % (ctime.seconds // 60 % 60,
str((ctime.seconds % 60)).zfill(2),
str(ctime.microseconds)[:2])
else:
ctime = ''
if p.dict['memory_percent'] is not None:
p.dict['memory_percent'] = round(p.dict['memory_percent'], 1)
else:
p.dict['memory_percent'] = ''
if p.dict['cpu_percent'] is None:
p.dict['cpu_percent'] = ''
line = templ % (p.pid,
p.dict['username'][:8],
p.dict['nice'],
bytes2human(getattr(p.dict['memory_info'], 'vms', 0)),
bytes2human(getattr(p.dict['memory_info'], 'rss', 0)),
p.dict['cpu_percent'],
p.dict['memory_percent'],
ctime,
p.dict['name'] or '',
)
try:
print_line(line)
except curses.error:
break
win.refresh()
def main():
try:
interval = 0
while 1:
args = poll(interval)
refresh_window(*args)
interval = 1
except (KeyboardInterrupt, SystemExit):
pass
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: who.py 1340 2012-06-09 13:42:21Z g.rodola $
#
# 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.
"""
A clone of 'who' command; print information about users who are
currently logged in.
"""
import sys
from datetime import datetime
import psutil
from psutil._compat import print_
def main():
users = psutil.get_users()
for user in users:
print_("%-15s %-15s %s (%s)" % \
(user.name,
user.terminal or '-',
datetime.fromtimestamp(user.started).strftime("%Y-%m-%d %H:%M"),
user.host)
)
if __name__ == '__main__':
main()
Metadata-Version: 1.1
Name: psutil
Version: 0.6.1
Summary: A process and system utilities module for Python
Home-page: http://code.google.com/p/psutil/
Author: Giampaolo Rodola
Author-email: g.rodola <at> gmail <dot> com
License: License :: OSI Approved :: BSD License
Download-URL: http://psutil.googlecode.com/files/psutil-0.6.1.tar.gz
Description: ===========
Quick links
===========
* `Home page <http://code.google.com/p/psutil>`_
* `Download <http://code.google.com/p/psutil/downloads/list>`_
* `Documentation <http://code.google.com/p/psutil/wiki/Documentation>`_
=======
Summary
=======
psutil is a module providing an interface for retrieving information on all
running processes and system utilization (CPU, memory, disks, network, users) in
a portable way by using Python, implementing many functionalities offered by
command line tools such as: **ps, top, df, kill, free, lsof, free, netstat,
ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**.
It currently supports **Linux**, **Windows**, **OSX** and **FreeBSD** both
**32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using
a single code base.
==============
Example usages
==============
CPU
===
>>> import psutil
>>> psutil.cpu_times()
cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540,
iowait=629.509, irq=0.0, softirq=19.422)
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1)
...
4.0
5.9
3.8
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1, percpu=True)
...
[4.0, 6.9]
[7.0, 8.5]
[1.2, 9.0]
>>>
Memory
======
>>> psutil.virtual_memory()
vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L,
free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L,
cached=1251086336)
>>> psutil.swap_memory()
swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1,
sin=304193536, sout=677842944)
>>>
Disks
=====
>>> psutil.disk_partitions()
[partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
>>>
>>> psutil.disk_usage('/')
usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
>>>
>>> psutil.disk_io_counters()
iostat(read_count=719566, write_count=1082197, read_bytes=18626220032,
write_bytes=24081764352, read_time=5023392, write_time=63199568)
>>>
Network
=======
>>> psutil.network_io_counters(pernic=True)
{'lo': iostat(bytes_sent=799953745, bytes_recv=799953745,
packets_sent=453698, packets_recv=453698),
'eth0': iostat(bytes_sent=734324837, bytes_recv=4163935363,
packets_sent=3605828, packets_recv=4096685)}
>>>
Users
=====
>>> psutil.get_users()
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
>>>
Process management
==================
>>> import psutil
>>> psutil.get_pid_list()
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
>>>
>>> p = psutil.Process(7055)
>>> p.name
'python'
>>> p.exe
'/usr/bin/python'
>>> p.getcwd()
'/home/giampaolo'
>>> p.cmdline
['/usr/bin/python', 'main.py']
>>>
>>> str(p.status)
'running'
>>> p.username
'giampaolo'
>>> p.create_time
1267551141.5019531
>>> p.terminal
'/dev/pts/0'
>>>
>>> p.uids
user(real=1000, effective=1000, saved=1000)
>>> p.gids
group(real=1000, effective=1000, saved=1000)
>>>
>>> p.get_cpu_times()
cputimes(user=1.02, system=0.31)
>>> p.get_cpu_percent(interval=1.0)
12.1
>>> p.get_cpu_affinity()
[0, 1, 2, 3]
>>> p.set_cpu_affinity([0])
>>>
>>> p.get_memory_percent()
0.63423
>>>
>>> p.get_memory_info()
meminfo(rss=7471104, vms=68513792)
>>> p.get_ext_memory_info()
meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
>>> p.get_memory_maps()
[mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
mmap(path='[heap]', rss=54653, anonymous=8192, swap=0),
mmap(path='[stack]', rss=1542, anonymous=166, swap=0),
...]
>>>
>>> p.get_io_counters()
io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
>>>
>>> p.get_open_files()
[openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
>>>
>>> p.get_connections()
[connection(fd=115, family=2, type=1, local_address=('10.0.0.1', 48776),
remote_address=('93.186.135.91', 80), status='ESTABLISHED'),
connection(fd=117, family=2, type=1, local_address=('10.0.0.1', 43761),
remote_address=('72.14.234.100', 80), status='CLOSING'),
connection(fd=119, family=2, type=1, local_address=('10.0.0.1', 60759),
remote_address=('72.14.234.104', 80), status='ESTABLISHED'),
connection(fd=123, family=2, type=1, local_address=('10.0.0.1', 51314),
remote_address=('72.14.234.83', 443), status='SYN_SENT')]
>>>
>>> p.get_num_threads()
4
>>> p.get_num_fds()
8
>>> p.get_threads()
[thread(id=5234, user_time=22.5, system_time=9.2891),
thread(id=5235, user_time=0.0, system_time=0.0),
thread(id=5236, user_time=0.0, system_time=0.0),
thread(id=5237, user_time=0.0707, system_time=1.1)]
>>>
>>> p.get_num_ctx_switches()
amount(voluntary=78, involuntary=19)
>>>
>>> p.get_nice()
0
>>> p.set_nice(10)
>>>
>>> p.suspend()
>>> p.resume()
>>>
>>> p.terminate()
>>> p.wait(timeout=3)
0
>>>
>>> psutil.test()
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
root 1 0.0 0.0 24584 2240 ? Jun17 00:00 init
root 2 0.0 0.0 0 0 ? Jun17 00:00 kthreadd
root 3 0.0 0.0 0 0 ? Jun17 00:05 ksoftirqd/0
...
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
giampaolo 31721 0.0 2.2 773060 181896 ? 00:04 10:30 chrome
root 31763 0.0 0.0 0 0 ? 00:05 00:00 kworker/0:1
>>>
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,monitoring
Platform: Platform Independent
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft
Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.4
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.0
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Networking :: Monitoring
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: System :: Hardware
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
CREDITS
HISTORY
INSTALL
LICENSE
MANIFEST.in
README
setup.py
examples/disk_usage.py
examples/free.py
examples/iotop.py
examples/killall.py
examples/meminfo.py
examples/netstat.py
examples/nettop.py
examples/pmap.py
examples/process_detail.py
examples/top.py
examples/who.py
psutil/__init__.py
psutil/_common.py
psutil/_compat.py
psutil/_psbsd.py
psutil/_pslinux.py
psutil/_psmswindows.py
psutil/_psosx.py
psutil/_psposix.py
psutil/_psutil_bsd.c
psutil/_psutil_bsd.h
psutil/_psutil_common.c
psutil/_psutil_common.h
psutil/_psutil_linux.c
psutil/_psutil_linux.h
psutil/_psutil_mswindows.c
psutil/_psutil_mswindows.h
psutil/_psutil_osx.c
psutil/_psutil_osx.h
psutil/_psutil_posix.c
psutil/_psutil_posix.h
psutil/error.py
psutil.egg-info/PKG-INFO
psutil.egg-info/SOURCES.txt
psutil.egg-info/dependency_links.txt
psutil.egg-info/top_level.txt
psutil/arch/bsd/process_info.c
psutil/arch/bsd/process_info.h
psutil/arch/mswindows/ntextapi.h
psutil/arch/mswindows/process_handles.c
psutil/arch/mswindows/process_handles.h
psutil/arch/mswindows/process_info.c
psutil/arch/mswindows/process_info.h
psutil/arch/mswindows/security.c
psutil/arch/mswindows/security.h
psutil/arch/osx/process_info.c
psutil/arch/osx/process_info.h
test/_bsd.py
test/_linux.py
test/_osx.py
test/_posix.py
test/_windows.py
test/test_memory_leaks.py
test/test_psutil.py
\ No newline at end of file
psutil
_psutil_linux
_psutil_posix
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# $Id: __init__.py 1525 2012-08-16 16:32:03Z g.rodola $
#
# 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.
"""psutil is a module providing convenience functions for managing
processes and gather system information in a portable way by using
Python.
"""
from __future__ import division
__version__ = "0.6.1"
version_info = tuple([int(num) for num in __version__.split('.')])
__all__ = [
# exceptions
"Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired",
# constants
"NUM_CPUS", "TOTAL_PHYMEM", "BOOT_TIME",
"version_info", "__version__",
"STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
"STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
"STATUS_WAKING", "STATUS_LOCKED",
# classes
"Process", "Popen",
# functions
"test", "pid_exists", "get_pid_list", "process_iter", "get_process_list",
"virtual_memory", "swap_memory",
"cpu_times", "cpu_percent", "per_cpu_percent",
"network_io_counters", "disk_io_counters",
]
import sys
import os
import time
import signal
import warnings
import errno
import subprocess
try:
import pwd
except ImportError:
pwd = None
from psutil.error import Error, NoSuchProcess, AccessDenied, TimeoutExpired
from psutil._compat import property, callable, defaultdict
from psutil._common import cached_property
from psutil._common import (deprecated as _deprecated,
nt_disk_iostat as _nt_disk_iostat,
nt_net_iostat as _nt_net_iostat,
nt_sysmeminfo as _nt_sysmeminfo,
isfile_strict as _isfile_strict)
from psutil._common import (STATUS_RUNNING, STATUS_IDLE, STATUS_SLEEPING,
STATUS_DISK_SLEEP, STATUS_STOPPED,
STATUS_TRACING_STOP, STATUS_ZOMBIE, STATUS_DEAD,
STATUS_WAKING, STATUS_LOCKED)
# import the appropriate module for our platform only
if sys.platform.startswith("linux"):
import psutil._pslinux as _psplatform
from psutil._pslinux import (phymem_buffers,
cached_phymem,
IOPRIO_CLASS_NONE,
IOPRIO_CLASS_RT,
IOPRIO_CLASS_BE,
IOPRIO_CLASS_IDLE)
phymem_buffers = _psplatform.phymem_buffers
cached_phymem = _psplatform.cached_phymem
elif sys.platform.startswith("win32"):
import psutil._psmswindows as _psplatform
from psutil._psmswindows import (ABOVE_NORMAL_PRIORITY_CLASS,
BELOW_NORMAL_PRIORITY_CLASS,
HIGH_PRIORITY_CLASS,
IDLE_PRIORITY_CLASS,
NORMAL_PRIORITY_CLASS,
REALTIME_PRIORITY_CLASS)
elif sys.platform.startswith("cygwin"):
import psutil._psmswindows as _psplatform
from psutil._psmswindows import (ABOVE_NORMAL_PRIORITY_CLASS,
BELOW_NORMAL_PRIORITY_CLASS,
HIGH_PRIORITY_CLASS,
IDLE_PRIORITY_CLASS,
NORMAL_PRIORITY_CLASS,
REALTIME_PRIORITY_CLASS)
elif sys.platform.startswith("darwin"):
import psutil._psosx as _psplatform
elif sys.platform.startswith("freebsd"):
import psutil._psbsd as _psplatform
else:
raise NotImplementedError('platform %s is not supported' % sys.platform)
__all__.extend(_psplatform.__extra__all__)
NUM_CPUS = _psplatform.NUM_CPUS
BOOT_TIME = _psplatform.BOOT_TIME
TOTAL_PHYMEM = _psplatform.TOTAL_PHYMEM
class Process(object):
"""Represents an OS process."""
def __init__(self, pid):
"""Create a new Process object for the given pid.
Raises NoSuchProcess if pid does not exist.
"""
self._pid = pid
self._gone = False
# platform-specific modules define an _psplatform.Process
# implementation class
self._platform_impl = _psplatform.Process(pid)
self._last_sys_cpu_times = None
self._last_proc_cpu_times = None
# cache creation time for later use in is_running() method
try:
self.create_time
except AccessDenied:
pass
except NoSuchProcess:
raise NoSuchProcess(pid, None, 'no process found with pid %s' % pid)
def __str__(self):
try:
pid = self.pid
name = repr(self.name)
except NoSuchProcess:
details = "(pid=%s (terminated))" % self.pid
except AccessDenied:
details = "(pid=%s)" % (self.pid)
else:
details = "(pid=%s, name=%s)" % (pid, name)
return "%s.%s%s" % (self.__class__.__module__,
self.__class__.__name__, details)
def __repr__(self):
return "<%s at %s>" % (self.__str__(), id(self))
def as_dict(self, attrs=[], ad_value=None):
"""Utility method returning process information as a hashable
dictionary.
If 'attrs' is specified it must be a list of strings reflecting
available Process class's attribute names (e.g. ['get_cpu_times',
'name']) else all public (read only) attributes are assumed.
'ad_value' is the value which gets assigned to a dict key in case
AccessDenied exception is raised when retrieving that particular
process information.
"""
excluded_names = set(['send_signal', 'suspend', 'resume', 'terminate',
'kill', 'wait', 'is_running', 'as_dict', 'parent',
'get_children', 'nice'])
retdict = dict()
for name in set(attrs or dir(self)):
if name.startswith('_'):
continue
if name.startswith('set_'):
continue
if name in excluded_names:
continue
try:
attr = getattr(self, name)
if callable(attr):
if name == 'get_cpu_percent':
ret = attr(interval=0)
else:
ret = attr()
else:
ret = attr
except AccessDenied:
ret = ad_value
except NotImplementedError:
# in case of not implemented functionality (may happen
# on old or exotic systems) we want to crash only if
# the user explicitly asked for that particular attr
if attrs:
raise
continue
if name.startswith('get'):
if name[3] == '_':
name = name[4:]
elif name == 'getcwd':
name = 'cwd'
retdict[name] = ret
return retdict
@property
def pid(self):
"""The process pid."""
return self._pid
@cached_property
def ppid(self):
"""The process parent pid."""
return self._platform_impl.get_process_ppid()
@property
def parent(self):
"""Return the parent process as a Process object. If no parent
pid is known return None.
"""
ppid = self.ppid
if ppid is not None:
try:
return Process(ppid)
except NoSuchProcess:
pass
@cached_property
def name(self):
"""The process name."""
name = self._platform_impl.get_process_name()
if os.name == 'posix':
# On UNIX the name gets truncated to the first 15 characters.
# If it matches the first part of the cmdline we return that
# one instead because it's usually more explicative.
# Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon".
try:
cmdline = self.cmdline
except AccessDenied:
pass
else:
if cmdline:
extended_name = os.path.basename(cmdline[0])
if extended_name.startswith(name):
name = extended_name
# XXX - perhaps needs refactoring
self._platform_impl._process_name = name
return name
@cached_property
def exe(self):
"""The process executable path. May also be an empty string."""
def guess_it(fallback):
# try to guess exe from cmdline[0] in absence of a native
# exe representation
cmdline = self.cmdline
if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'):
exe = cmdline[0] # the possible exe
rexe = os.path.realpath(exe) # ...in case it's a symlink
if os.path.isabs(rexe) and os.path.isfile(rexe) \
and os.access(rexe, os.X_OK):
return exe
if isinstance(fallback, AccessDenied):
raise fallback
return fallback
try:
exe = self._platform_impl.get_process_exe()
except AccessDenied:
err = sys.exc_info()[1]
return guess_it(fallback=err)
else:
if not exe:
# underlying implementation can legitimately return an
# empty string; if that's the case we don't want to
# raise AD while guessing from the cmdline
try:
exe = guess_it(fallback=exe)
except AccessDenied:
pass
return exe
@cached_property
def cmdline(self):
"""The command line process has been called with."""
return self._platform_impl.get_process_cmdline()
@property
def status(self):
"""The process current status as a STATUS_* constant."""
return self._platform_impl.get_process_status()
if os.name == 'posix':
@property
def uids(self):
"""Return a named tuple denoting the process real,
effective, and saved user ids.
"""
return self._platform_impl.get_process_uids()
@property
def gids(self):
"""Return a named tuple denoting the process real,
effective, and saved group ids.
"""
return self._platform_impl.get_process_gids()
@property
def terminal(self):
"""The terminal associated with this process, if any,
else None.
"""
return self._platform_impl.get_process_terminal()
@property
def username(self):
"""The name of the user that owns the process.
On UNIX this is calculated by using *real* process uid.
"""
if os.name == 'posix':
if pwd is None:
# might happen if python was installed from sources
raise ImportError("requires pwd module shipped with standard python")
return pwd.getpwuid(self.uids.real).pw_name
else:
return self._platform_impl.get_process_username()
@cached_property
def create_time(self):
"""The process creation time as a floating point number
expressed in seconds since the epoch, in UTC.
"""
return self._platform_impl.get_process_create_time()
def getcwd(self):
"""Return a string representing the process current working
directory.
"""
return self._platform_impl.get_process_cwd()
# Linux, BSD and Windows only
if hasattr(_psplatform.Process, "get_process_io_counters"):
def get_io_counters(self):
"""Return process I/O statistics as a namedtuple including
the number of read/write calls performed and the amount of
bytes read and written by the process.
"""
return self._platform_impl.get_process_io_counters()
def get_nice(self):
"""Get process niceness (priority)."""
return self._platform_impl.get_process_nice()
def set_nice(self, value):
"""Set process niceness (priority)."""
return self._platform_impl.set_process_nice(value)
# available only on Linux
if hasattr(_psplatform.Process, "get_process_ionice"):
def get_ionice(self):
"""Return process I/O niceness (priority) as a namedtuple."""
return self._platform_impl.get_process_ionice()
def set_ionice(self, ioclass, value=None):
"""Set process I/O niceness (priority).
ioclass is one of the IOPRIO_CLASS_* constants.
iodata is a number which goes from 0 to 7. The higher the
value, the lower the I/O priority of the process.
"""
return self._platform_impl.set_process_ionice(ioclass, value)
# available on Windows and Linux only
if hasattr(_psplatform.Process, "get_process_cpu_affinity"):
def get_cpu_affinity(self):
"""Get process current CPU affinity."""
return self._platform_impl.get_process_cpu_affinity()
def set_cpu_affinity(self, cpus):
"""Set process current CPU affinity.
'cpus' is a list of CPUs for which you want to set the
affinity (e.g. [0, 1]).
"""
return self._platform_impl.set_process_cpu_affinity(cpus)
if os.name == 'nt':
def get_num_handles(self):
"""Return the number of handles opened by this process
(Windows only).
"""
return self._platform_impl.get_num_handles()
if os.name == 'posix':
def get_num_fds(self):
"""Return the number of file descriptors opened by this
process (POSIX only).
"""
return self._platform_impl.get_num_fds()
def get_num_ctx_switches(self):
"""Return the number voluntary and involuntary context switches
performed by this process.
"""
return self._platform_impl.get_num_ctx_switches()
def get_num_threads(self):
"""Return the number of threads used by this process."""
return self._platform_impl.get_process_num_threads()
def get_threads(self):
"""Return threads opened by process as a list of namedtuples
including thread id and thread CPU times (user/system).
"""
return self._platform_impl.get_process_threads()
def get_children(self, recursive=False):
"""Return the children of this process as a list of Process
objects.
If recursive is True return all the parent descendants.
Example (A == this process):
A ─┐
├─ B (child) ─┐
│ └─ X (grandchild) ─┐
│ └─ Y (great grandchild)
├─ C (child)
└─ D (child)
>>> p.get_children()
B, C, D
>>> p.get_children(recursive=True)
B, X, Y, C, D
Note that in the example above if process X disappears
process Y won't be returned either as the reference to
process A is lost.
"""
if not self.is_running():
name = self._platform_impl._process_name
raise NoSuchProcess(self.pid, name)
ret = []
if not recursive:
for p in process_iter():
try:
if p.ppid == self.pid:
# if child happens to be older than its parent
# (self) it means child's PID has been reused
if self.create_time <= p.create_time:
ret.append(p)
except NoSuchProcess:
pass
else:
# construct a dict where 'values' are all the processes
# having 'key' as their parent
table = defaultdict(list)
for p in process_iter():
try:
table[p.ppid].append(p)
except NoSuchProcess:
pass
# At this point we have a mapping table where table[self.pid]
# are the current process's children.
# Below, we look for all descendants recursively, similarly
# to a recursive function call.
checkpids = [self.pid]
for pid in checkpids:
for child in table[pid]:
try:
# if child happens to be older than its parent
# (self) it means child's PID has been reused
intime = self.create_time <= child.create_time
except NoSuchProcess:
pass
else:
if intime:
ret.append(child)
if child.pid not in checkpids:
checkpids.append(child.pid)
return ret
def get_cpu_percent(self, interval=0.1):
"""Return a float representing the current process CPU
utilization as a percentage.
When interval is > 0.0 compares process times to system CPU
times elapsed before and after the interval (blocking).
When interval is 0.0 or None compares process times to system CPU
times elapsed since last call, returning immediately.
In this case is recommended for accuracy that this function be
called with at least 0.1 seconds between calls.
"""
blocking = interval is not None and interval > 0.0
if blocking:
st1 = sum(cpu_times())
pt1 = self._platform_impl.get_cpu_times()
time.sleep(interval)
st2 = sum(cpu_times())
pt2 = self._platform_impl.get_cpu_times()
else:
st1 = self._last_sys_cpu_times
pt1 = self._last_proc_cpu_times
st2 = sum(cpu_times())
pt2 = self._platform_impl.get_cpu_times()
if st1 is None or pt1 is None:
self._last_sys_cpu_times = st2
self._last_proc_cpu_times = pt2
return 0.0
delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system)
delta_time = st2 - st1
# reset values for next call in case of interval == None
self._last_sys_cpu_times = st2
self._last_proc_cpu_times = pt2
try:
# the utilization split between all CPUs
overall_percent = (delta_proc / delta_time) * 100
except ZeroDivisionError:
# interval was too low
return 0.0
# the utilization of a single CPU
single_cpu_percent = overall_percent * NUM_CPUS
# on posix a percentage > 100 is legitimate
# http://stackoverflow.com/questions/1032357/comprehending-top-cpu-usage
# on windows we use this ugly hack to avoid troubles with float
# precision issues
if os.name != 'posix':
if single_cpu_percent > 100.0:
return 100.0
return round(single_cpu_percent, 1)
def get_cpu_times(self):
"""Return a tuple whose values are process CPU user and system
times. The same as os.times() but per-process.
"""
return self._platform_impl.get_cpu_times()
def get_memory_info(self):
"""Return a tuple representing RSS (Resident Set Size) and VMS
(Virtual Memory Size) in bytes.
On UNIX RSS and VMS are the same values shown by ps.
On Windows RSS and VMS refer to "Mem Usage" and "VM Size" columns
of taskmgr.exe.
"""
return self._platform_impl.get_memory_info()
def get_ext_memory_info(self):
"""Return a namedtuple with variable fields depending on the
platform representing extended memory information about
the process. All numbers are expressed in bytes.
"""
return self._platform_impl.get_ext_memory_info()
def get_memory_percent(self):
"""Compare physical system memory to process resident memory and
calculate process memory utilization as a percentage.
"""
rss = self._platform_impl.get_memory_info()[0]
try:
return (rss / float(TOTAL_PHYMEM)) * 100
except ZeroDivisionError:
return 0.0
def get_memory_maps(self, grouped=True):
"""Return process's mapped memory regions as a list of nameduples
whose fields are variable depending on the platform.
If 'grouped' is True the mapped regions with the same 'path'
are grouped together and the different memory fields are summed.
If 'grouped' is False every mapped region is shown as a single
entity and the namedtuple will also include the mapped region's
address space ('addr') and permission set ('perms').
"""
it = self._platform_impl.get_memory_maps()
if grouped:
d = {}
for tupl in it:
path = tupl[2]
nums = tupl[3:]
try:
d[path] = map(lambda x, y: x+y, d[path], nums)
except KeyError:
d[path] = nums
nt = self._platform_impl.nt_mmap_grouped
return [nt(path, *d[path]) for path in d]
else:
nt = self._platform_impl.nt_mmap_ext
return [nt(*x) for x in it]
def get_open_files(self):
"""Return files opened by process as a list of namedtuples
including absolute file name and file descriptor number.
"""
return self._platform_impl.get_open_files()
def get_connections(self, kind='inet'):
"""Return connections opened by process as a list of namedtuples.
The kind parameter filters for connections that fit the following
criteria:
Kind Value Connections using
inet IPv4 and IPv6
inet4 IPv4
inet6 IPv6
tcp TCP
tcp4 TCP over IPv4
tcp6 TCP over IPv6
udp UDP
udp4 UDP over IPv4
udp6 UDP over IPv6
unix UNIX socket (both UDP and TCP protocols)
all the sum of all the possible families and protocols
"""
return self._platform_impl.get_connections(kind)
def is_running(self):
"""Return whether this process is running."""
if self._gone:
return False
try:
# Checking if pid is alive is not enough as the pid might
# have been reused by another process.
# pid + creation time, on the other hand, is supposed to
# identify a process univocally.
return self.create_time == \
self._platform_impl.get_process_create_time()
except NoSuchProcess:
self._gone = True
return False
def send_signal(self, sig):
"""Send a signal to process (see signal module constants).
On Windows only SIGTERM is valid and is treated as an alias
for kill().
"""
# safety measure in case the current process has been killed in
# meantime and the kernel reused its PID
if not self.is_running():
name = self._platform_impl._process_name
raise NoSuchProcess(self.pid, name)
if os.name == 'posix':
try:
os.kill(self.pid, sig)
except OSError:
err = sys.exc_info()[1]
name = self._platform_impl._process_name
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, name)
if err.errno == errno.EPERM:
raise AccessDenied(self.pid, name)
raise
else:
if sig == signal.SIGTERM:
self._platform_impl.kill_process()
else:
raise ValueError("only SIGTERM is supported on Windows")
def suspend(self):
"""Suspend process execution."""
# safety measure in case the current process has been killed in
# meantime and the kernel reused its PID
if not self.is_running():
name = self._platform_impl._process_name
raise NoSuchProcess(self.pid, name)
# windows
if hasattr(self._platform_impl, "suspend_process"):
self._platform_impl.suspend_process()
else:
# posix
self.send_signal(signal.SIGSTOP)
def resume(self):
"""Resume process execution."""
# safety measure in case the current process has been killed in
# meantime and the kernel reused its PID
if not self.is_running():
name = self._platform_impl._process_name
raise NoSuchProcess(self.pid, name)
# windows
if hasattr(self._platform_impl, "resume_process"):
self._platform_impl.resume_process()
else:
# posix
self.send_signal(signal.SIGCONT)
def terminate(self):
"""Terminate the process with SIGTERM.
On Windows this is an alias for kill().
"""
self.send_signal(signal.SIGTERM)
def kill(self):
"""Kill the current process."""
# safety measure in case the current process has been killed in
# meantime and the kernel reused its PID
if not self.is_running():
name = self._platform_impl._process_name
raise NoSuchProcess(self.pid, name)
if os.name == 'posix':
self.send_signal(signal.SIGKILL)
else:
self._platform_impl.kill_process()
def wait(self, timeout=None):
"""Wait for process to terminate and, if process is a children
of the current one also return its exit code, else None.
"""
if timeout is not None and not timeout >= 0:
raise ValueError("timeout must be a positive integer")
return self._platform_impl.process_wait(timeout)
# --- deprecated API
@property
def nice(self):
"""Get or set process niceness (priority).
Deprecated, use get_nice() instead.
"""
msg = "this property is deprecated; use Process.get_nice() method instead"
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
return self.get_nice()
@nice.setter
def nice(self, value):
# invoked on "p.nice = num"; change process niceness
# deprecated in favor of set_nice()
msg = "this property is deprecated; use Process.set_nice() method instead"
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
return self.set_nice(value)
class Popen(Process):
"""A more convenient interface to stdlib subprocess module.
It starts a sub process and deals with it exactly as when using
subprocess.Popen class but in addition also provides all the
property and methods of psutil.Process class in a single interface:
>>> import psutil
>>> from subprocess import PIPE
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print 'hi'"], stdout=PIPE)
>>> p.name
'python'
>>> p.uids
user(real=1000, effective=1000, saved=1000)
>>> p.username
'giampaolo'
>>> p.communicate()
('hi\n', None)
>>> p.terminate()
>>> p.wait(timeout=2)
0
>>>
For method names common to both classes such as kill(), terminate()
and wait(), psutil.Process implementation takes precedence.
For a complete documentation refers to:
http://docs.python.org/library/subprocess.html
"""
def __init__(self, *args, **kwargs):
self.__subproc = subprocess.Popen(*args, **kwargs)
self._pid = self.__subproc.pid
self._gone = False
self._platform_impl = _psplatform.Process(self._pid)
self._last_sys_cpu_times = None
self._last_proc_cpu_times = None
try:
self.create_time
except AccessDenied:
pass
except NoSuchProcess:
raise NoSuchProcess(self._pid, None,
"no process found with pid %s" % pid)
def __dir__(self):
return list(set(dir(Popen) + dir(subprocess.Popen)))
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
try:
return object.__getattribute__(self.__subproc, name)
except AttributeError:
raise AttributeError("%s instance has no attribute '%s'"
%(self.__class__.__name__, name))
# =====================================================================
# --- system processes related functions
# =====================================================================
get_pid_list = _psplatform.get_pid_list
pid_exists = _psplatform.pid_exists
_pmap = {}
def process_iter():
"""Return a generator yielding a Process class instance for all
running processes on the local machine.
Every new Process instance is only created once and then cached
into an internal table which is updated every time this is used.
The sorting order in which processes are yielded is based on
their PIDs.
"""
def add(pid):
proc = Process(pid)
_pmap[proc.pid] = proc
return proc
def remove(pid):
_pmap.pop(pid, None)
a = set(get_pid_list())
b = set(_pmap.keys())
new_pids = a - b
gone_pids = b - a
for pid in gone_pids:
remove(pid)
for pid, proc in sorted(list(_pmap.items()) + \
list(dict.fromkeys(new_pids).items())):
try:
if proc is None: # new process
yield add(pid)
else:
# use is_running() to check whether PID has been reused by
# another process in which case yield a new Process instance
if proc.is_running():
yield proc
else:
yield add(pid)
except NoSuchProcess:
remove(pid)
except AccessDenied:
# Process creation time can't be determined hence there's
# no way to tell whether the pid of the cached process
# has been reused. Just return the cached version.
yield proc
# =====================================================================
# --- CPU related functions
# =====================================================================
def cpu_times(percpu=False):
"""Return system-wide CPU times as a namedtuple object.
Every CPU time represents the time CPU has spent in the given mode.
The attributes availability varies depending on the platform.
Here follows a list of all available attributes:
- user
- system
- idle
- nice (UNIX)
- iowait (Linux)
- irq (Linux, FreeBSD)
- softirq (Linux)
When percpu is True return a list of nameduples for each CPU.
First element of the list refers to first CPU, second element
to second CPU and so on.
The order of the list is consistent across calls.
"""
if not percpu:
return _psplatform.get_system_cpu_times()
else:
return _psplatform.get_system_per_cpu_times()
_last_cpu_times = cpu_times()
_last_per_cpu_times = cpu_times(percpu=True)
def cpu_percent(interval=0.1, percpu=False):
"""Return a float representing the current system-wide CPU
utilization as a percentage.
When interval is > 0.0 compares system CPU times elapsed before
and after the interval (blocking).
When interval is 0.0 or None compares system CPU times elapsed
since last call or module import, returning immediately.
In this case is recommended for accuracy that this function be
called with at least 0.1 seconds between calls.
When percpu is True returns a list of floats representing the
utilization as a percentage for each CPU.
First element of the list refers to first CPU, second element
to second CPU and so on.
The order of the list is consistent across calls.
"""
global _last_cpu_times
global _last_per_cpu_times
blocking = interval is not None and interval > 0.0
def calculate(t1, t2):
t1_all = sum(t1)
t1_busy = t1_all - t1.idle
t2_all = sum(t2)
t2_busy = t2_all - t2.idle
# this usually indicates a float precision issue
if t2_busy <= t1_busy:
return 0.0
busy_delta = t2_busy - t1_busy
all_delta = t2_all - t1_all
busy_perc = (busy_delta / all_delta) * 100
return round(busy_perc, 1)
# system-wide usage
if not percpu:
if blocking:
t1 = cpu_times()
time.sleep(interval)
else:
t1 = _last_cpu_times
_last_cpu_times = cpu_times()
return calculate(t1, _last_cpu_times)
# per-cpu usage
else:
ret = []
if blocking:
tot1 = cpu_times(percpu=True)
time.sleep(interval)
else:
tot1 = _last_per_cpu_times
_last_per_cpu_times = cpu_times(percpu=True)
for t1, t2 in zip(tot1, _last_per_cpu_times):
ret.append(calculate(t1, t2))
return ret
# =====================================================================
# --- system memory related functions
# =====================================================================
def virtual_memory():
"""Return statistics about system memory usage as a namedtuple
including the following fields, expressed in bytes:
- total:
total physical memory available.
- available:
the actual amount of available memory that can be given
instantly to processes that request more memory in bytes; this
is calculated by summing different memory values depending on
the platform (e.g. free + buffers + cached on Linux) and it is
supposed to be used to monitor actual memory usage in a cross
platform fashion.
- percent:
the percentage usage calculated as (total - available) / total * 100
- used:
memory used, calculated differently depending on the platform and
designed for informational purposes only:
OSX: active + inactive + wired
BSD: active + wired + cached
LINUX: total - free
- free:
memory not being used at all (zeroed) that is readily available;
note that this doesn't reflect the actual memory available
(use 'available' instead)
Platform-specific fields:
- active (UNIX):
memory currently in use or very recently used, and so it is in RAM.
- inactive (UNIX):
memory that is marked as not used.
- buffers (BSD, Linux):
cache for things like file system metadata.
- cached (BSD, OSX):
cache for various things.
- wired (OSX, BSD):
memory that is marked to always stay in RAM. It is never moved to disk.
- shared (BSD):
memory that may be simultaneously accessed by multiple processes.
The sum of 'used' and 'available' does not necessarily equal total.
On Windows 'available' and 'free' are the same.
"""
return _psplatform.virtual_memory()
def swap_memory():
"""Return system swap memory statistics as a namedtuple including
the following attributes:
- total: total swap memory in bytes
- used: used swap memory in bytes
- free: free swap memory in bytes
- percent: the percentage usage
- sin: no. of bytes the system has swapped in from disk (cumulative)
- sout: no. of bytes the system has swapped out from disk (cumulative)
'sin' and 'sout' on Windows are meaningless and always set to 0.
"""
return _psplatform.swap_memory()
# =====================================================================
# --- disks/paritions related functions
# =====================================================================
def disk_usage(path):
"""Return disk usage statistics about the given path as a namedtuple
including total, used and free space expressed in bytes plus the
percentage usage.
"""
return _psplatform.get_disk_usage(path)
def disk_partitions(all=False):
"""Return mounted partitions as a list of namedtuples including
device, mount point, filesystem type and mount options (a raw
string separated by commas which may vary depending on the platform).
If "all" parameter is False return physical devices only and ignore
all others.
"""
return _psplatform.disk_partitions(all)
def disk_io_counters(perdisk=False):
"""Return system disk I/O statistics as a namedtuple including
the following attributes:
- read_count: number of reads
- write_count: number of writes
- read_bytes: number of bytes read
- write_bytes: number of bytes written
- read_time: time spent reading from disk (in milliseconds)
- write_time: time spent writing to disk (in milliseconds)
If perdisk is True return the same information for every
physical disk installed on the system as a dictionary
with partition names as the keys and the namedutuple
described above as the values.
"""
rawdict = _psplatform.disk_io_counters()
if not rawdict:
raise RuntimeError("couldn't find any physical disk")
if perdisk:
for disk, fields in rawdict.items():
rawdict[disk] = _nt_disk_iostat(*fields)
return rawdict
else:
return _nt_disk_iostat(*[sum(x) for x in zip(*rawdict.values())])
# =====================================================================
# --- network related functions
# =====================================================================
def network_io_counters(pernic=False):
"""Return network I/O statistics as a namedtuple including
the following attributes:
- bytes_sent: number of bytes sent
- bytes_recv: number of bytes received
- packets_sent: number of packets sent
- packets_recv: number of packets received
- errin: total number of errors while receiving
- errout: total number of errors while sending
- dropin: total number of incoming packets which were dropped
- dropout: total number of outgoing packets which were dropped
(always 0 on OSX and BSD)
If pernic is True return the same information for every
network interface installed on the system as a dictionary
with network interface names as the keys and the namedtuple
described above as the values.
"""
rawdict = _psplatform.network_io_counters()
if not rawdict:
raise RuntimeError("couldn't find any network interface")
if pernic:
for nic, fields in rawdict.items():
rawdict[nic] = _nt_net_iostat(*fields)
return rawdict
else:
return _nt_net_iostat(*[sum(x) for x in zip(*rawdict.values())])
# =====================================================================
# --- other system related functions
# =====================================================================
def get_users():
"""Return users currently connected on the system as a list of
namedtuples including the following attributes.
- user: the name of the user
- terminal: the tty or pseudo-tty associated with the user, if any.
- host: the host name associated with the entry, if any.
- started: the creation time as a floating point number expressed in
seconds since the epoch.
"""
return _psplatform.get_system_users()
# =====================================================================
# --- deprecated functions
# =====================================================================
@_deprecated()
def get_process_list():
"""Return a list of Process class instances for all running
processes on the local machine (deprecated).
"""
return list(process_iter())
@_deprecated()
def phymem_usage():
"""Return the amount of total, used and free physical memory
on the system in bytes plus the percentage usage.
Deprecated by psutil.virtual_memory().
"""
mem = virtual_memory()
return _nt_sysmeminfo(mem.total, mem.used, mem.free, mem.percent)
@_deprecated("psutil.swap_memory()")
def virtmem_usage():
return swap_memory()
@_deprecated("psutil.phymem_usage().free")
def avail_phymem():
return phymem_usage().free
@_deprecated("psutil.phymem_usage().used")
def used_phymem():
return phymem_usage().used
@_deprecated("psutil.virtmem_usage().total")
def total_virtmem():
return virtmem_usage().total
@_deprecated("psutil.virtmem_usage().used")
def used_virtmem():
return virtmem_usage().used
@_deprecated("psutil.virtmem_usage().free")
def avail_virtmem():
return virtmem_usage().free
def test():
"""List info of all currently running processes emulating ps aux
output.
"""
import datetime
from psutil._compat import print_
today_day = datetime.date.today()
templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s"
attrs = ['pid', 'username', 'get_cpu_percent', 'get_memory_percent', 'name',
'get_cpu_times', 'create_time', 'get_memory_info']
if os.name == 'posix':
attrs.append('terminal')
print_(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "START",
"TIME", "COMMAND"))
for p in sorted(process_iter(), key=lambda p: p.pid):
try:
pinfo = p.as_dict(attrs, ad_value='')
except NoSuchProcess:
pass
else:
if pinfo['create_time']:
ctime = datetime.datetime.fromtimestamp(pinfo['create_time'])
if ctime.date() == today_day:
ctime = ctime.strftime("%H:%M")
else:
ctime = ctime.strftime("%b%d")
cputime = time.strftime("%M:%S", time.localtime(sum(pinfo['cpu_times'])))
user = pinfo['username']
if os.name == 'nt' and '\\' in user:
user = user.split('\\')[1]
vms = pinfo['memory_info'] and \
int(pinfo['memory_info'].vms / 1024) or '?'
rss = pinfo['memory_info'] and \
int(pinfo['memory_info'].rss / 1024) or '?'
memp = pinfo['memory_percent'] and \
round(pinfo['memory_percent'], 1) or '?'
print_(templ % (user[:10],
pinfo['pid'],
pinfo['cpu_percent'],
memp,
vms,
rss,
pinfo.get('terminal', '') or '?',
ctime,
cputime,
pinfo['name'].strip() or '?'))
if __name__ == "__main__":
test()
del property, cached_property, division
if sys.version_info < (3, 0):
del num
#/usr/bin/env python
#
#$Id: _common.py 1524 2012-08-16 15:06:32Z g.rodola $
#
# 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.
"""Common objects shared by all _ps* modules."""
from __future__ import division
import sys
import os
import stat
import errno
import warnings
from psutil._compat import namedtuple, long, wraps
# --- functions
def usage_percent(used, total, _round=None):
"""Calculate percentage usage of 'used' against 'total'."""
try:
ret = (used / total) * 100
except ZeroDivisionError:
ret = 0
if _round is not None:
return round(ret, _round)
else:
return ret
class constant(int):
"""A constant type; overrides base int to provide a useful name on str()."""
def __new__(cls, value, name, doc=None):
inst = super(constant, cls).__new__(cls, value)
inst._name = name
if doc is not None:
inst.__doc__ = doc
return inst
def __str__(self):
return self._name
def __eq__(self, other):
# Use both int or str values when comparing for equality
# (useful for serialization):
# >>> st = constant(0, "running")
# >>> st == 0
# True
# >>> st == 'running'
# True
if isinstance(other, int):
return int(self) == other
if isinstance(other, long):
return long(self) == other
if isinstance(other, str):
return self._name == other
return False
def __ne__(self, other):
return not self.__eq__(other)
def memoize(f):
"""A simple memoize decorator for functions."""
cache= {}
def memf(*x):
if x not in cache:
cache[x] = f(*x)
return cache[x]
return memf
class cached_property(object):
"""A memoize decorator for class properties."""
enabled = True
def __init__(self, func):
self.func = func
def __get__(self, instance, type):
ret = self.func(instance)
if self.enabled:
instance.__dict__[self.func.__name__] = ret
return ret
# http://goo.gl/jYLvf
def deprecated(replacement=None):
"""A decorator which can be used to mark functions as deprecated."""
def outer(fun):
msg = "psutil.%s is deprecated" % fun.__name__
if replacement is not None:
msg += "; use %s instead" % replacement
if fun.__doc__ is None:
fun.__doc__ = msg
@wraps(fun)
def inner(*args, **kwargs):
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
return fun(*args, **kwargs)
return inner
return outer
def isfile_strict(path):
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
exceptions, see:
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
"""
try:
st = os.stat(path)
except OSError:
err = sys.exc_info()[1]
if err.errno in (errno.EPERM, errno.EACCES):
raise
return False
else:
return stat.S_ISREG(st.st_mode)
# --- constants
STATUS_RUNNING = constant(0, "running")
STATUS_SLEEPING = constant(1, "sleeping")
STATUS_DISK_SLEEP = constant(2, "disk sleep")
STATUS_STOPPED = constant(3, "stopped")
STATUS_TRACING_STOP = constant(4, "tracing stop")
STATUS_ZOMBIE = constant(5, "zombie")
STATUS_DEAD = constant(6, "dead")
STATUS_WAKE_KILL = constant(7, "wake kill")
STATUS_WAKING = constant(8, "waking")
STATUS_IDLE = constant(9, "idle") # BSD
STATUS_LOCKED = constant(10, "locked") # BSD
STATUS_WAITING = constant(11, "waiting") # BSD
# --- Process.get_connections() 'kind' parameter mapping
import socket
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
AF_INET6 = getattr(socket, 'AF_INET6', None)
AF_UNIX = getattr(socket, 'AF_UNIX', None)
conn_tmap = {
"all" : ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
"tcp" : ([AF_INET, AF_INET6], [SOCK_STREAM]),
"tcp4" : ([AF_INET], [SOCK_STREAM]),
"udp" : ([AF_INET, AF_INET6], [SOCK_DGRAM]),
"udp4" : ([AF_INET], [SOCK_DGRAM]),
"inet" : ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
"inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
"inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
}
if AF_INET6 is not None:
conn_tmap.update({
"tcp6" : ([AF_INET6], [SOCK_STREAM]),
"udp6" : ([AF_INET6], [SOCK_DGRAM]),
})
if AF_UNIX is not None:
conn_tmap.update({
"unix" : ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
})
del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM, socket
# --- namedtuples
# system
nt_sys_cputimes = namedtuple('cputimes', 'user nice system idle iowait irq softirq')
nt_sysmeminfo = namedtuple('usage', 'total used free percent')
# XXX - would 'available' be better than 'free' as for virtual_memory() nt?
nt_swapmeminfo = namedtuple('swap', 'total used free percent sin sout')
nt_diskinfo = namedtuple('usage', 'total used free percent')
nt_partition = namedtuple('partition', 'device mountpoint fstype opts')
nt_net_iostat = namedtuple('iostat',
'bytes_sent bytes_recv packets_sent packets_recv errin errout dropin dropout')
nt_disk_iostat = namedtuple('iostat', 'read_count write_count read_bytes write_bytes read_time write_time')
nt_user = namedtuple('user', 'name terminal host started')
# processes
nt_meminfo = namedtuple('meminfo', 'rss vms')
nt_cputimes = namedtuple('cputimes', 'user system')
nt_openfile = namedtuple('openfile', 'path fd')
nt_connection = namedtuple('connection', 'fd family type local_address remote_address status')
nt_thread = namedtuple('thread', 'id user_time system_time')
nt_uids = namedtuple('user', 'real effective saved')
nt_gids = namedtuple('group', 'real effective saved')
nt_io = namedtuple('io', 'read_count write_count read_bytes write_bytes')
nt_ionice = namedtuple('ionice', 'ioclass value')
nt_ctxsw = namedtuple('amount', 'voluntary involuntary')
#!/usr/bin/env python
#
# $Id: _compat.py 1524 2012-08-16 15:06:32Z g.rodola $
#
# 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.
"""Module which provides compatibility with older Python versions."""
__all__ = ["PY3", "int", "long", "xrange", "exec_", "callable",
"namedtuple", "property", "defaultdict"]
import sys
# --- python 2/3 compatibility layer
PY3 = sys.version_info >= (3,)
try:
import __builtin__
except ImportError:
import builtins as __builtin__ # py3
if PY3:
int = int
long = int
xrange = range
exec_ = getattr(__builtin__, "exec")
print_ = getattr(__builtin__, "print")
else:
int = int
long = long
xrange = xrange
def exec_(code, globs=None, locs=None):
if globs is None:
frame = _sys._getframe(1)
globs = frame.f_globals
if locs is None:
locs = frame.f_locals
del frame
elif locs is None:
locs = globs
exec("""exec code in globs, locs""")
def print_(s):
sys.stdout.write(s + '\n')
sys.stdout.flush()
# removed in 3.0, reintroduced in 3.2
try:
callable = callable
except Exception:
def callable(obj):
for klass in type(obj).__mro__:
if "__call__" in klass.__dict__:
return True
return False
# --- stdlib additions
try:
from collections import namedtuple
except ImportError:
from operator import itemgetter as _itemgetter
from keyword import iskeyword as _iskeyword
import sys as _sys
def namedtuple(typename, field_names, verbose=False, rename=False):
"""A collections.namedtuple implementation written in Python
to support Python versions < 2.6.
Taken from: http://code.activestate.com/recipes/500261/
"""
# Parse and validate the field names. Validation serves two
# purposes, generating informative error messages and preventing
# template injection attacks.
if isinstance(field_names, basestring):
# names separated by whitespace and/or commas
field_names = field_names.replace(',', ' ').split()
field_names = tuple(map(str, field_names))
if rename:
names = list(field_names)
seen = set()
for i, name in enumerate(names):
if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
or not name or name[0].isdigit() or name.startswith('_')
or name in seen):
names[i] = '_%d' % i
seen.add(name)
field_names = tuple(names)
for name in (typename,) + field_names:
if not min(c.isalnum() or c=='_' for c in name):
raise ValueError('Type names and field names can only contain ' \
'alphanumeric characters and underscores: %r'
% name)
if _iskeyword(name):
raise ValueError('Type names and field names cannot be a keyword: %r' \
% name)
if name[0].isdigit():
raise ValueError('Type names and field names cannot start with a ' \
'number: %r' % name)
seen_names = set()
for name in field_names:
if name.startswith('_') and not rename:
raise ValueError('Field names cannot start with an underscore: %r'
% name)
if name in seen_names:
raise ValueError('Encountered duplicate field name: %r' % name)
seen_names.add(name)
# Create and fill-in the class template
numfields = len(field_names)
# tuple repr without parens or quotes
argtxt = repr(field_names).replace("'", "")[1:-1]
reprtxt = ', '.join('%s=%%r' % name for name in field_names)
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)' \n
__slots__ = () \n
_fields = %(field_names)r \n
def __new__(_cls, %(argtxt)s):
return _tuple.__new__(_cls, (%(argtxt)s)) \n
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new %(typename)s object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != %(numfields)d:
raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
return result \n
def __repr__(self):
return '%(typename)s(%(reprtxt)s)' %% self \n
def _asdict(self):
'Return a new dict which maps field names to their values'
return dict(zip(self._fields, self)) \n
def _replace(_self, **kwds):
'Return a new %(typename)s object replacing specified fields with new values'
result = _self._make(map(kwds.pop, %(field_names)r, _self))
if kwds:
raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
return result \n
def __getnewargs__(self):
return tuple(self) \n\n''' % locals()
for i, name in enumerate(field_names):
template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
if verbose:
sys.stdout.write(template + '\n')
sys.stdout.flush()
# Execute the template string in a temporary namespace
namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
_property=property, _tuple=tuple)
try:
exec_(template, namespace)
except SyntaxError:
e = sys.exc_info()[1]
raise SyntaxError(e.message + ':\n' + template)
result = namespace[typename]
# For pickling to work, the __module__ variable needs to be set
# to the frame where the named tuple is created. Bypass this
# step in enviroments where sys._getframe is not defined (Jython
# for example) or sys._getframe is not defined for arguments
# greater than 0 (IronPython).
try:
result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
pass
return result
# hack to support property.setter/deleter on python < 2.6
# http://docs.python.org/library/functions.html?highlight=property#property
if hasattr(property, 'setter'):
property = property
else:
class property(__builtin__.property):
__metaclass__ = type
def __init__(self, fget, *args, **kwargs):
super(property, self).__init__(fget, *args, **kwargs)
self.__doc__ = fget.__doc__
def getter(self, method):
return property(method, self.fset, self.fdel)
def setter(self, method):
return property(self.fget, method, self.fdel)
def deleter(self, method):
return property(self.fget, self.fset, method)
# py 2.5 collections.defauldict
# Taken from:
# http://code.activestate.com/recipes/523034-emulate-collectionsdefaultdict/
# credits: Jason Kirtland
try:
from collections import defaultdict
except ImportError:
class defaultdict(dict):
def __init__(self, default_factory=None, *a, **kw):
if (default_factory is not None and
not hasattr(default_factory, '__call__')):
raise TypeError('first argument must be callable')
dict.__init__(self, *a, **kw)
self.default_factory = default_factory
def __getitem__(self, key):
try:
return dict.__getitem__(self, key)
except KeyError:
return self.__missing__(key)
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
self[key] = value = self.default_factory()
return value
def __reduce__(self):
if self.default_factory is None:
args = tuple()
else:
args = self.default_factory,
return type(self), args, None, None, self.items()
def copy(self):
return self.__copy__()
def __copy__(self):
return type(self)(self.default_factory, self)
def __deepcopy__(self, memo):
import copy
return type(self)(self.default_factory,
copy.deepcopy(self.items()))
def __repr__(self):
return 'defaultdict(%s, %s)' % (self.default_factory,
dict.__repr__(self))
# py 2.5 functools.wraps
try:
from functools import wraps
except ImportError:
def wraps(original):
def inner(fn):
# see functools.WRAPPER_ASSIGNMENTS
for attribute in ['__module__',
'__name__',
'__doc__'
]:
setattr(fn, attribute, getattr(original, attribute))
# see functools.WRAPPER_UPDATES
for attribute in ['__dict__',
]:
if hasattr(fn, attribute):
getattr(fn, attribute).update(getattr(original, attribute))
else:
setattr(fn, attribute,
getattr(original, attribute).copy())
return fn
return inner
#!/usr/bin/env python
#
# $Id: _psbsd.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""FreeBSD platform implementation."""
import errno
import os
import sys
import _psutil_bsd
import _psutil_posix
from psutil import _psposix
from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
from psutil._compat import namedtuple
from psutil._common import *
__extra__all__ = []
# --- constants
NUM_CPUS = _psutil_bsd.get_num_cpus()
BOOT_TIME = _psutil_bsd.get_system_boot_time()
TOTAL_PHYMEM = _psutil_bsd.get_virtual_mem()[0]
_TERMINAL_MAP = _psposix._get_terminal_map()
_PAGESIZE = os.sysconf("SC_PAGE_SIZE")
_cputimes_ntuple = namedtuple('cputimes', 'user nice system idle irq')
# --- public functions
nt_virtmem_info = namedtuple('vmem', ' '.join([
# all platforms
'total', 'available', 'percent', 'used', 'free',
# FreeBSD specific
'active',
'inactive',
'buffers',
'cached',
'shared',
'wired']))
def virtual_memory():
"""System virtual memory as a namedutple."""
mem = _psutil_bsd.get_virtual_mem()
total, free, active, inactive, wired, cached, buffers, shared = mem
avail = inactive + cached + free
used = active + wired + cached
percent = usage_percent((total - avail), total, _round=1)
return nt_virtmem_info(total, avail, percent, used, free,
active, inactive, buffers, cached, shared, wired)
def swap_memory():
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
total, used, free, sin, sout = \
[x * _PAGESIZE for x in _psutil_bsd.get_swap_mem()]
percent = usage_percent(used, total, _round=1)
return nt_swapmeminfo(total, used, free, percent, sin, sout)
def get_system_cpu_times():
"""Return system per-CPU times as a named tuple"""
user, nice, system, idle, irq = _psutil_bsd.get_system_cpu_times()
return _cputimes_ntuple(user, nice, system, idle, irq)
def get_system_per_cpu_times():
"""Return system CPU times as a named tuple"""
ret = []
for cpu_t in _psutil_bsd.get_system_per_cpu_times():
user, nice, system, idle, irq = cpu_t
item = _cputimes_ntuple(user, nice, system, idle, irq)
ret.append(item)
return ret
# XXX
# Ok, this is very dirty.
# On FreeBSD < 8 we cannot gather per-cpu information, see:
# http://code.google.com/p/psutil/issues/detail?id=226
# If NUM_CPUS > 1, on first call we return single cpu times to avoid a
# crash at psutil import time.
# Next calls will fail with NotImplementedError
if not hasattr(_psutil_bsd, "get_system_per_cpu_times"):
def get_system_per_cpu_times():
if NUM_CPUS == 1:
return [get_system_cpu_times]
if get_system_per_cpu_times.__called__:
raise NotImplementedError("supported only starting from FreeBSD 8")
get_system_per_cpu_times.__called__ = True
return [get_system_cpu_times]
get_system_per_cpu_times.__called__ = False
def disk_partitions(all=False):
retlist = []
partitions = _psutil_bsd.get_disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
if device == 'none':
device = ''
if not all:
if not os.path.isabs(device) \
or not os.path.exists(device):
continue
ntuple = nt_partition(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
def get_system_users():
retlist = []
rawlist = _psutil_bsd.get_system_users()
for item in rawlist:
user, tty, hostname, tstamp = item
if tty == '~':
continue # reboot or shutdown
nt = nt_user(user, tty or None, hostname, tstamp)
retlist.append(nt)
return retlist
get_pid_list = _psutil_bsd.get_pid_list
pid_exists = _psposix.pid_exists
get_disk_usage = _psposix.get_disk_usage
network_io_counters = _psutil_bsd.get_network_io_counters
disk_io_counters = _psutil_bsd.get_disk_io_counters
def wrap_exceptions(method):
"""Call method(self, pid) into a try/except clause so that if an
OSError "No such process" exception is raised we assume the process
has died and raise psutil.NoSuchProcess instead.
"""
def wrapper(self, *args, **kwargs):
try:
return method(self, *args, **kwargs)
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
raise
return wrapper
_status_map = {
_psutil_bsd.SSTOP : STATUS_STOPPED,
_psutil_bsd.SSLEEP : STATUS_SLEEPING,
_psutil_bsd.SRUN : STATUS_RUNNING,
_psutil_bsd.SIDL : STATUS_IDLE,
_psutil_bsd.SWAIT : STATUS_WAITING,
_psutil_bsd.SLOCK : STATUS_LOCKED,
_psutil_bsd.SZOMB : STATUS_ZOMBIE,
}
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
self.pid = pid
self._process_name = None
@wrap_exceptions
def get_process_name(self):
"""Return process name as a string of limited len (15)."""
return _psutil_bsd.get_process_name(self.pid)
@wrap_exceptions
def get_process_exe(self):
"""Return process executable pathname."""
return _psutil_bsd.get_process_exe(self.pid)
@wrap_exceptions
def get_process_cmdline(self):
"""Return process cmdline as a list of arguments."""
return _psutil_bsd.get_process_cmdline(self.pid)
@wrap_exceptions
def get_process_terminal(self):
tty_nr = _psutil_bsd.get_process_tty_nr(self.pid)
try:
return _TERMINAL_MAP[tty_nr]
except KeyError:
return None
@wrap_exceptions
def get_process_ppid(self):
"""Return process parent pid."""
return _psutil_bsd.get_process_ppid(self.pid)
# XXX - available on FreeBSD >= 8 only
if hasattr(_psutil_bsd, "get_process_cwd"):
@wrap_exceptions
def get_process_cwd(self):
"""Return process current working directory."""
# sometimes we get an empty string, in which case we turn
# it into None
return _psutil_bsd.get_process_cwd(self.pid) or None
@wrap_exceptions
def get_process_uids(self):
"""Return real, effective and saved user ids."""
real, effective, saved = _psutil_bsd.get_process_uids(self.pid)
return nt_uids(real, effective, saved)
@wrap_exceptions
def get_process_gids(self):
"""Return real, effective and saved group ids."""
real, effective, saved = _psutil_bsd.get_process_gids(self.pid)
return nt_gids(real, effective, saved)
@wrap_exceptions
def get_cpu_times(self):
"""return a tuple containing process user/kernel time."""
user, system = _psutil_bsd.get_process_cpu_times(self.pid)
return nt_cputimes(user, system)
@wrap_exceptions
def get_memory_info(self):
"""Return a tuple with the process' RSS and VMS size."""
rss, vms = _psutil_bsd.get_process_memory_info(self.pid)[:2]
return nt_meminfo(rss, vms)
_nt_ext_mem = namedtuple('meminfo', 'rss vms text data stack')
@wrap_exceptions
def get_ext_memory_info(self):
return self._nt_ext_mem(*_psutil_bsd.get_process_memory_info(self.pid))
@wrap_exceptions
def get_process_create_time(self):
"""Return the start time of the process as a number of seconds since
the epoch."""
return _psutil_bsd.get_process_create_time(self.pid)
@wrap_exceptions
def get_process_num_threads(self):
"""Return the number of threads belonging to the process."""
return _psutil_bsd.get_process_num_threads(self.pid)
@wrap_exceptions
def get_num_ctx_switches(self):
return nt_ctxsw(*_psutil_bsd.get_process_num_ctx_switches(self.pid))
@wrap_exceptions
def get_num_fds(self):
"""Return the number of file descriptors opened by this process."""
return _psutil_bsd.get_process_num_fds(self.pid)
@wrap_exceptions
def get_process_threads(self):
"""Return the number of threads belonging to the process."""
rawlist = _psutil_bsd.get_process_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = nt_thread(thread_id, utime, stime)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def get_open_files(self):
"""Return files opened by process as a list of namedtuples."""
# XXX - C implementation available on FreeBSD >= 8 only
# else fallback on lsof parser
if hasattr(_psutil_bsd, "get_process_open_files"):
rawlist = _psutil_bsd.get_process_open_files(self.pid)
return [nt_openfile(path, fd) for path, fd in rawlist]
else:
lsof = _psposix.LsofParser(self.pid, self._process_name)
return lsof.get_process_open_files()
@wrap_exceptions
def get_connections(self, kind='inet'):
"""Return etwork connections opened by a process as a list of
namedtuples.
"""
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
ret = _psutil_bsd.get_process_connections(self.pid, families, types)
return [nt_connection(*conn) for conn in ret]
@wrap_exceptions
def process_wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except TimeoutExpired:
raise TimeoutExpired(self.pid, self._process_name)
@wrap_exceptions
def get_process_nice(self):
return _psutil_posix.getpriority(self.pid)
@wrap_exceptions
def set_process_nice(self, value):
return _psutil_posix.setpriority(self.pid, value)
@wrap_exceptions
def get_process_status(self):
code = _psutil_bsd.get_process_status(self.pid)
if code in _status_map:
return _status_map[code]
return constant(-1, "?")
@wrap_exceptions
def get_process_io_counters(self):
rc, wc, rb, wb = _psutil_bsd.get_process_io_counters(self.pid)
return nt_io(rc, wc, rb, wb)
nt_mmap_grouped = namedtuple('mmap',
'path rss, private, ref_count, shadow_count')
nt_mmap_ext = namedtuple('mmap',
'addr, perms path rss, private, ref_count, shadow_count')
@wrap_exceptions
def get_memory_maps(self):
return _psutil_bsd.get_process_memory_maps(self.pid)
# FreeBSD < 8 does not support kinfo_getfile() and kinfo_getvmmap()
if not hasattr(_psutil_bsd, 'get_process_open_files'):
def _not_implemented(self):
raise NotImplementedError("supported only starting from FreeBSD 8")
get_open_files = _not_implemented
get_process_cwd = _not_implemented
get_memory_maps = _not_implemented
get_num_fds = _not_implemented
#!/usr/bin/env python
#
# $Id: _pslinux.py 1513 2012-08-14 11:01:37Z g.rodola $
#
# 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.
"""Linux platform implementation."""
from __future__ import division
import os
import errno
import socket
import struct
import sys
import base64
import re
import _psutil_posix
import _psutil_linux
from psutil import _psposix
from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
from psutil._common import *
from psutil._compat import PY3, xrange, long, namedtuple
__extra__all__ = [
"IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE",
"IOPRIO_CLASS_IDLE",
"phymem_buffers", "cached_phymem"]
def _get_boot_time():
"""Return system boot time (epoch in seconds)"""
f = open('/proc/stat', 'r')
try:
for line in f:
if line.startswith('btime'):
return float(line.strip().split()[1])
raise RuntimeError("line not found")
finally:
f.close()
def _get_num_cpus():
"""Return the number of CPUs on the system"""
# we try to determine num CPUs by using different approaches.
# SC_NPROCESSORS_ONLN seems to be the safer and it is also
# used by multiprocessing module
try:
return os.sysconf("SC_NPROCESSORS_ONLN")
except ValueError:
# as a second fallback we try to parse /proc/cpuinfo
num = 0
f = open('/proc/cpuinfo', 'r')
try:
lines = f.readlines()
finally:
f.close()
for line in lines:
if line.lower().startswith('processor'):
num += 1
# unknown format (e.g. amrel/sparc architectures), see:
# http://code.google.com/p/psutil/issues/detail?id=200
# try to parse /proc/stat as a last resort
if num == 0:
f = open('/proc/stat', 'r')
try:
lines = f.readlines()
finally:
f.close()
search = re.compile('cpu\d')
for line in lines:
line = line.split(' ')[0]
if search.match(line):
num += 1
if num == 0:
raise RuntimeError("can't determine number of CPUs")
return num
# Number of clock ticks per second
_CLOCK_TICKS = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
_PAGESIZE = os.sysconf("SC_PAGE_SIZE")
_TERMINAL_MAP = _psposix._get_terminal_map()
BOOT_TIME = _get_boot_time()
NUM_CPUS = _get_num_cpus()
TOTAL_PHYMEM = _psutil_linux.get_sysinfo()[0]
# ioprio_* constants http://linux.die.net/man/2/ioprio_get
IOPRIO_CLASS_NONE = 0
IOPRIO_CLASS_RT = 1
IOPRIO_CLASS_BE = 2
IOPRIO_CLASS_IDLE = 3
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
_TCP_STATES_TABLE = {"01" : "ESTABLISHED",
"02" : "SYN_SENT",
"03" : "SYN_RECV",
"04" : "FIN_WAIT1",
"05" : "FIN_WAIT2",
"06" : "TIME_WAIT",
"07" : "CLOSE",
"08" : "CLOSE_WAIT",
"09" : "LAST_ACK",
"0A" : "LISTEN",
"0B" : "CLOSING"
}
# --- system memory functions
nt_virtmem_info = namedtuple('vmem', ' '.join([
# all platforms
'total', 'available', 'percent', 'used', 'free',
# linux specific
'active',
'inactive',
'buffers',
'cached']))
def virtual_memory():
total, free, buffers, shared, _, _ = _psutil_linux.get_sysinfo()
cached = active = inactive = None
f = open('/proc/meminfo', 'r')
try:
for line in f:
if line.startswith('Cached:'):
cached = int(line.split()[1]) * 1024
elif line.startswith('Active:'):
active = int(line.split()[1]) * 1024
elif line.startswith('Inactive:'):
inactive = int(line.split()[1]) * 1024
if cached is not None \
and active is not None \
and inactive is not None:
break
else:
raise RuntimeError("line(s) not found")
finally:
f.close()
avail = free + buffers + cached
used = total - free
percent = usage_percent((total - avail), total, _round=1)
return nt_virtmem_info(total, avail, percent, used, free,
active, inactive, buffers, cached)
def swap_memory():
_, _, _, _, total, free = _psutil_linux.get_sysinfo()
used = total - free
percent = usage_percent(used, total, _round=1)
# get pgin/pgouts
f = open("/proc/vmstat", "r")
sin = sout = None
try:
for line in f:
# values are expressed in 4 kilo bytes, we want bytes instead
if line.startswith('pswpin'):
sin = int(line.split(' ')[1]) * 4 * 1024
elif line.startswith('pswpout'):
sout = int(line.split(' ')[1]) * 4 * 1024
if sin is not None and sout is not None:
break
else:
raise RuntimeError("line(s) not found")
finally:
f.close()
return nt_swapmeminfo(total, used, free, percent, sin, sout)
# --- XXX deprecated memory functions
@deprecated('psutil.virtual_memory().cached')
def cached_phymem():
return virtual_memory().cached
@deprecated('psutil.virtual_memory().buffers')
def phymem_buffers():
return virtual_memory().buffers
# --- system CPU functions
def get_system_cpu_times():
"""Return a named tuple representing the following CPU times:
user, nice, system, idle, iowait, irq, softirq.
"""
f = open('/proc/stat', 'r')
try:
values = f.readline().split()
finally:
f.close()
values = values[1:8]
values = tuple([float(x) / _CLOCK_TICKS for x in values])
return nt_sys_cputimes(*values[:7])
def get_system_per_cpu_times():
"""Return a list of namedtuple representing the CPU times
for every CPU available on the system.
"""
cpus = []
f = open('/proc/stat', 'r')
# get rid of the first line who refers to system wide CPU stats
try:
f.readline()
for line in f.readlines():
if line.startswith('cpu'):
values = line.split()[1:8]
values = tuple([float(x) / _CLOCK_TICKS for x in values])
entry = nt_sys_cputimes(*values[:7])
cpus.append(entry)
return cpus
finally:
f.close()
# --- system disk functions
def disk_partitions(all=False):
"""Return mounted disk partitions as a list of nameduples"""
phydevs = []
f = open("/proc/filesystems", "r")
try:
for line in f:
if not line.startswith("nodev"):
phydevs.append(line.strip())
finally:
f.close()
retlist = []
partitions = _psutil_linux.get_disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
if device == 'none':
device = ''
if not all:
if device == '' or fstype not in phydevs:
continue
ntuple = nt_partition(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
get_disk_usage = _psposix.get_disk_usage
# --- other sysetm functions
def get_system_users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = _psutil_linux.get_system_users()
for item in rawlist:
user, tty, hostname, tstamp, user_process = item
# XXX the underlying C function includes entries about
# system boot, run level and others. We might want
# to use them in the future.
if not user_process:
continue
if hostname == ':0.0':
hostname = 'localhost'
nt = nt_user(user, tty or None, hostname, tstamp)
retlist.append(nt)
return retlist
# --- process functions
def get_pid_list():
"""Returns a list of PIDs currently running on the system."""
pids = [int(x) for x in os.listdir('/proc') if x.isdigit()]
return pids
def pid_exists(pid):
"""Check For the existence of a unix pid."""
return _psposix.pid_exists(pid)
def network_io_counters():
"""Return network I/O statistics for every network interface
installed on the system as a dict of raw tuples.
"""
f = open("/proc/net/dev", "r")
try:
lines = f.readlines()
finally:
f.close()
retdict = {}
for line in lines[2:]:
colon = line.find(':')
assert colon > 0, line
name = line[:colon].strip()
fields = line[colon+1:].strip().split()
bytes_recv = int(fields[0])
packets_recv = int(fields[1])
errin = int(fields[2])
dropin = int(fields[2])
bytes_sent = int(fields[8])
packets_sent = int(fields[9])
errout = int(fields[10])
dropout = int(fields[11])
retdict[name] = (bytes_sent, bytes_recv, packets_sent, packets_recv,
errin, errout, dropin, dropout)
return retdict
def disk_io_counters():
"""Return disk I/O statistics for every disk installed on the
system as a dict of raw tuples.
"""
# man iostat states that sectors are equivalent with blocks and
# have a size of 512 bytes since 2.4 kernels. This value is
# needed to calculate the amount of disk I/O in bytes.
SECTOR_SIZE = 512
# determine partitions we want to look for
partitions = []
f = open("/proc/partitions", "r")
try:
lines = f.readlines()[2:]
finally:
f.close()
for line in lines:
_, _, _, name = line.split()
if name[-1].isdigit():
partitions.append(name)
#
retdict = {}
f = open("/proc/diskstats", "r")
try:
lines = f.readlines()
finally:
f.close()
for line in lines:
_, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \
line.split()[:11]
if name in partitions:
rbytes = int(rbytes) * SECTOR_SIZE
wbytes = int(wbytes) * SECTOR_SIZE
reads = int(reads)
writes = int(writes)
# TODO: times are expressed in milliseconds while OSX/BSD has
# these expressed in nanoseconds; figure this out.
rtime = int(rtime)
wtime = int(wtime)
retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime)
return retdict
# taken from /fs/proc/array.c
_status_map = {"R" : STATUS_RUNNING,
"S" : STATUS_SLEEPING,
"D" : STATUS_DISK_SLEEP,
"T" : STATUS_STOPPED,
"t" : STATUS_TRACING_STOP,
"Z" : STATUS_ZOMBIE,
"X" : STATUS_DEAD,
"x" : STATUS_DEAD,
"K" : STATUS_WAKE_KILL,
"W" : STATUS_WAKING}
# --- decorators
def wrap_exceptions(callable):
"""Call callable into a try/except clause and translate ENOENT,
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
"""
def wrapper(self, *args, **kwargs):
try:
return callable(self, *args, **kwargs)
except EnvironmentError:
# ENOENT (no such file or directory) gets raised on open().
# ESRCH (no such process) can get raised on read() if
# process is gone in meantime.
err = sys.exc_info()[1]
if err.errno in (errno.ENOENT, errno.ESRCH):
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
raise
return wrapper
class Process(object):
"""Linux process implementation."""
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
if not isinstance(pid, int):
raise TypeError('pid must be an integer')
self.pid = pid
self._process_name = None
@wrap_exceptions
def get_process_name(self):
f = open("/proc/%s/stat" % self.pid)
try:
name = f.read().split(' ')[1].replace('(', '').replace(')', '')
finally:
f.close()
# XXX - gets changed later and probably needs refactoring
return name
def get_process_exe(self):
try:
exe = os.readlink("/proc/%s/exe" % self.pid)
except (OSError, IOError):
err = sys.exc_info()[1]
if err.errno == errno.ENOENT:
# no such file error; might be raised also if the
# path actually exists for system processes with
# low pids (about 0-20)
if os.path.lexists("/proc/%s/exe" % self.pid):
return ""
else:
# ok, it is a process which has gone away
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
raise
# readlink() might return paths containing null bytes causing
# problems when used with other fs-related functions (os.*,
# open(), ...)
exe = exe.replace('\x00', '')
# Certain names have ' (deleted)' appended. Usually this is
# bogus as the file actually exists. Either way that's not
# important as we don't want to discriminate executables which
# have been deleted.
if exe.endswith(" (deleted)") and not os.path.exists(exe):
exe = exe[:-10]
return exe
@wrap_exceptions
def get_process_cmdline(self):
f = open("/proc/%s/cmdline" % self.pid)
try:
# return the args as a list
return [x for x in f.read().split('\x00') if x]
finally:
f.close()
@wrap_exceptions
def get_process_terminal(self):
f = open("/proc/%s/stat" % self.pid)
try:
tty_nr = int(f.read().split(' ')[6])
finally:
f.close()
try:
return _TERMINAL_MAP[tty_nr]
except KeyError:
return None
@wrap_exceptions
def get_process_io_counters(self):
f = open("/proc/%s/io" % self.pid)
try:
for line in f:
if line.startswith("rchar"):
read_count = int(line.split()[1])
elif line.startswith("wchar"):
write_count = int(line.split()[1])
elif line.startswith("read_bytes"):
read_bytes = int(line.split()[1])
elif line.startswith("write_bytes"):
write_bytes = int(line.split()[1])
return nt_io(read_count, write_count, read_bytes, write_bytes)
finally:
f.close()
if not os.path.exists('/proc/%s/io' % os.getpid()):
def get_process_io_counters(self):
raise NotImplementedError('/proc/PID/io is not available')
@wrap_exceptions
def get_cpu_times(self):
f = open("/proc/%s/stat" % self.pid)
try:
st = f.read().strip()
finally:
f.close()
# ignore the first two values ("pid (exe)")
st = st[st.find(')') + 2:]
values = st.split(' ')
utime = float(values[11]) / _CLOCK_TICKS
stime = float(values[12]) / _CLOCK_TICKS
return nt_cputimes(utime, stime)
@wrap_exceptions
def process_wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except TimeoutExpired:
raise TimeoutExpired(self.pid, self._process_name)
@wrap_exceptions
def get_process_create_time(self):
f = open("/proc/%s/stat" % self.pid)
try:
st = f.read().strip()
finally:
f.close()
# ignore the first two values ("pid (exe)")
st = st[st.rfind(')') + 2:]
values = st.split(' ')
# According to documentation, starttime is in field 21 and the
# unit is jiffies (clock ticks).
# We first divide it for clock ticks and then add uptime returning
# seconds since the epoch, in UTC.
starttime = (float(values[19]) / _CLOCK_TICKS) + BOOT_TIME
return starttime
@wrap_exceptions
def get_memory_info(self):
f = open("/proc/%s/statm" % self.pid)
try:
vms, rss = f.readline().split()[:2]
return nt_meminfo(int(rss) * _PAGESIZE,
int(vms) * _PAGESIZE)
finally:
f.close()
_nt_ext_mem = namedtuple('meminfo', 'rss vms shared text lib data dirty')
@wrap_exceptions
def get_ext_memory_info(self):
# ============================================================
# | FIELD | DESCRIPTION | AKA | TOP |
# ============================================================
# | rss | resident set size | | RES |
# | vms | total program size | size | VIRT |
# | shared | shared pages (from shared mappings) | | SHR |
# | text | text ('code') | trs | CODE |
# | lib | library (unused in Linux 2.6) | lrs | |
# | data | data + stack | drs | DATA |
# | dirty | dirty pages (unused in Linux 2.6) | dt | |
# ============================================================
f = open("/proc/%s/statm" % self.pid)
try:
vms, rss, shared, text, lib, data, dirty = \
[int(x) * _PAGESIZE for x in f.readline().split()[:7]]
finally:
f.close()
return self._nt_ext_mem(rss, vms, shared, text, lib, data, dirty)
_mmap_base_fields = ['path', 'rss', 'size', 'pss', 'shared_clean',
'shared_dirty', 'private_clean', 'private_dirty',
'referenced', 'anonymous', 'swap',]
nt_mmap_grouped = namedtuple('mmap', ' '.join(_mmap_base_fields))
nt_mmap_ext = namedtuple('mmap', 'addr perms ' + ' '.join(_mmap_base_fields))
def get_memory_maps(self):
"""Return process's mapped memory regions as a list of nameduples.
Fields are explained in 'man proc'; here is an updated (Apr 2012)
version: http://goo.gl/fmebo
"""
f = None
try:
f = open("/proc/%s/smaps" % self.pid)
first_line = f.readline()
current_block = [first_line]
def get_blocks():
data = {}
for line in f:
fields = line.split(None, 5)
if len(fields) >= 5:
yield (current_block.pop(), data)
current_block.append(line)
else:
data[fields[0]] = int(fields[1]) * 1024
yield (current_block.pop(), data)
if first_line: # smaps file can be empty
for header, data in get_blocks():
hfields = header.split(None, 5)
try:
addr, perms, offset, dev, inode, path = hfields
except ValueError:
addr, perms, offset, dev, inode, path = hfields + ['']
if not path:
path = '[anon]'
else:
path = path.strip()
yield (addr, perms, path,
data['Rss:'],
data['Size:'],
data.get('Pss:', 0),
data['Shared_Clean:'], data['Shared_Clean:'],
data['Private_Clean:'], data['Private_Dirty:'],
data['Referenced:'],
data['Anonymous:'],
data['Swap:'])
f.close()
except EnvironmentError:
# XXX - Can't use wrap_exceptions decorator as we're
# returning a generator; this probably needs some
# refactoring in order to avoid this code duplication.
if f is not None:
f.close()
err = sys.exc_info()[1]
if err.errno in (errno.ENOENT, errno.ESRCH):
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
raise
except:
if f is not None:
f.close()
raise
if not os.path.exists('/proc/%s/smaps' % os.getpid()):
def get_shared_libs(self, ext):
msg = "this Linux version does not support /proc/PID/smaps " \
"(kernel < 2.6.14 or CONFIG_MMU kernel configuration " \
"option is not enabled)"
raise NotImplementedError(msg)
@wrap_exceptions
def get_process_cwd(self):
# readlink() might return paths containing null bytes causing
# problems when used with other fs-related functions (os.*,
# open(), ...)
path = os.readlink("/proc/%s/cwd" % self.pid)
return path.replace('\x00', '')
@wrap_exceptions
def get_num_ctx_switches(self):
vol = unvol = None
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith("voluntary_ctxt_switches"):
vol = int(line.split()[1])
elif line.startswith("nonvoluntary_ctxt_switches"):
unvol = int(line.split()[1])
if vol is not None and unvol is not None:
return nt_ctxsw(vol, unvol)
raise RuntimeError("line not found")
finally:
f.close()
@wrap_exceptions
def get_process_num_threads(self):
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith("Threads:"):
return int(line.split()[1])
raise RuntimeError("line not found")
finally:
f.close()
@wrap_exceptions
def get_process_threads(self):
thread_ids = os.listdir("/proc/%s/task" % self.pid)
thread_ids.sort()
retlist = []
hit_enoent = False
for thread_id in thread_ids:
try:
f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id))
except EnvironmentError:
err = sys.exc_info()[1]
if err.errno == errno.ENOENT:
# no such file or directory; it means thread
# disappeared on us
hit_enoent = True
continue
raise
try:
st = f.read().strip()
finally:
f.close()
# ignore the first two values ("pid (exe)")
st = st[st.find(')') + 2:]
values = st.split(' ')
utime = float(values[11]) / _CLOCK_TICKS
stime = float(values[12]) / _CLOCK_TICKS
ntuple = nt_thread(int(thread_id), utime, stime)
retlist.append(ntuple)
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('/proc/%s' % self.pid)
return retlist
@wrap_exceptions
def get_process_nice(self):
#f = open('/proc/%s/stat' % self.pid, 'r')
#try:
# data = f.read()
# return int(data.split()[18])
#finally:
# f.close()
# Use C implementation
return _psutil_posix.getpriority(self.pid)
@wrap_exceptions
def set_process_nice(self, value):
return _psutil_posix.setpriority(self.pid, value)
@wrap_exceptions
def get_process_cpu_affinity(self):
from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x]
bitmask = _psutil_linux.get_process_cpu_affinity(self.pid)
return from_bitmask(bitmask)
@wrap_exceptions
def set_process_cpu_affinity(self, value):
def to_bitmask(l):
if not l:
raise ValueError("invalid argument %r" % l)
out = 0
for b in l:
if not isinstance(b, (int, long)) or b < 0:
raise ValueError("invalid argument %r" % b)
out |= 2**b
return out
bitmask = to_bitmask(value)
try:
_psutil_linux.set_process_cpu_affinity(self.pid, bitmask)
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.EINVAL:
allcpus = list(range(len(get_system_per_cpu_times())))
for cpu in value:
if cpu not in allcpus:
raise ValueError("invalid CPU %i" % cpu)
raise
# only starting from kernel 2.6.13
if hasattr(_psutil_linux, "ioprio_get"):
@wrap_exceptions
def get_process_ionice(self):
ioclass, value = _psutil_linux.ioprio_get(self.pid)
return nt_ionice(ioclass, value)
@wrap_exceptions
def set_process_ionice(self, ioclass, value):
if ioclass in (IOPRIO_CLASS_NONE, None):
if value:
raise ValueError("can't specify value with IOPRIO_CLASS_NONE")
ioclass = IOPRIO_CLASS_NONE
value = 0
if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE):
if value is None:
value = 4
elif ioclass == IOPRIO_CLASS_IDLE:
if value:
raise ValueError("can't specify value with IOPRIO_CLASS_IDLE")
value = 0
else:
value = 0
if not 0 <= value <= 8:
raise ValueError("value argument range expected is between 0 and 8")
return _psutil_linux.ioprio_set(self.pid, ioclass, value)
@wrap_exceptions
def get_process_status(self):
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith("State:"):
letter = line.split()[1]
if letter in _status_map:
return _status_map[letter]
return constant(-1, '?')
finally:
f.close()
@wrap_exceptions
def get_open_files(self):
retlist = []
files = os.listdir("/proc/%s/fd" % self.pid)
hit_enoent = False
for fd in files:
file = "/proc/%s/fd/%s" % (self.pid, fd)
if os.path.islink(file):
try:
file = os.readlink(file)
except OSError:
# ENOENT == file which is gone in the meantime
err = sys.exc_info()[1]
if err.errno == errno.ENOENT:
hit_enoent = True
continue
raise
else:
# If file is not an absolute path there's no way
# to tell whether it's a regular file or not,
# so we skip it. A regular file is always supposed
# to be absolutized though.
if file.startswith('/') and isfile_strict(file):
ntuple = nt_openfile(file, int(fd))
retlist.append(ntuple)
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('/proc/%s' % self.pid)
return retlist
@wrap_exceptions
def get_connections(self, kind='inet'):
"""Return connections opened by process as a list of namedtuples.
The kind parameter filters for connections that fit the following
criteria:
Kind Value Number of connections using
inet IPv4 and IPv6
inet4 IPv4
inet6 IPv6
tcp TCP
tcp4 TCP over IPv4
tcp6 TCP over IPv6
udp UDP
udp4 UDP over IPv4
udp6 UDP over IPv6
all the sum of all the possible families and protocols
"""
# Note: in case of UNIX sockets we're only able to determine the
# local bound path while the remote endpoint is not retrievable:
# http://goo.gl/R3GHM
inodes = {}
# os.listdir() is gonna raise a lot of access denied
# exceptions in case of unprivileged user; that's fine:
# lsof does the same so it's unlikely that we can to better.
for fd in os.listdir("/proc/%s/fd" % self.pid):
try:
inode = os.readlink("/proc/%s/fd/%s" % (self.pid, fd))
except OSError:
continue
if inode.startswith('socket:['):
# the process is using a socket
inode = inode[8:][:-1]
inodes[inode] = fd
if not inodes:
# no connections for this process
return []
def process(file, family, type_):
retlist = []
try:
f = open(file, 'r')
except IOError:
# IPv6 not supported on this platform
err = sys.exc_info()[1]
if err.errno == errno.ENOENT and file.endswith('6'):
return []
else:
raise
try:
f.readline() # skip the first line
for line in f:
# IPv4 / IPv6
if family in (socket.AF_INET, socket.AF_INET6):
_, laddr, raddr, status, _, _, _, _, _, inode = \
line.split()[:10]
if inode in inodes:
laddr = self._decode_address(laddr, family)
raddr = self._decode_address(raddr, family)
if type_ == socket.SOCK_STREAM:
status = _TCP_STATES_TABLE[status]
else:
status = ""
fd = int(inodes[inode])
conn = nt_connection(fd, family, type_, laddr,
raddr, status)
retlist.append(conn)
elif family == socket.AF_UNIX:
tokens = line.split()
_, _, _, _, type_, _, inode = tokens[0:7]
if inode in inodes:
if len(tokens) == 8:
path = tokens[-1]
else:
path = ""
fd = int(inodes[inode])
type_ = int(type_)
conn = nt_connection(fd, family, type_, path,
None, "")
retlist.append(conn)
else:
raise ValueError(family)
return retlist
finally:
f.close()
tcp4 = ("tcp" , socket.AF_INET , socket.SOCK_STREAM)
tcp6 = ("tcp6", socket.AF_INET6, socket.SOCK_STREAM)
udp4 = ("udp" , socket.AF_INET , socket.SOCK_DGRAM)
udp6 = ("udp6", socket.AF_INET6, socket.SOCK_DGRAM)
unix = ("unix", socket.AF_UNIX, None)
tmap = {
"all" : (tcp4, tcp6, udp4, udp6, unix),
"tcp" : (tcp4, tcp6),
"tcp4" : (tcp4,),
"tcp6" : (tcp6,),
"udp" : (udp4, udp6),
"udp4" : (udp4,),
"udp6" : (udp6,),
"unix" : (unix,),
"inet" : (tcp4, tcp6, udp4, udp6),
"inet4": (tcp4, udp4),
"inet6": (tcp6, udp6),
}
if kind not in tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in tmap])))
ret = []
for f, family, type_ in tmap[kind]:
ret += process("/proc/net/%s" % f, family, type_)
# raise NSP if the process disappeared on us
os.stat('/proc/%s' % self.pid)
return ret
# --- lsof implementation
#
# def get_connections(self):
# lsof = _psposix.LsofParser(self.pid, self._process_name)
# return lsof.get_process_connections()
@wrap_exceptions
def get_num_fds(self):
return len(os.listdir("/proc/%s/fd" % self.pid))
@wrap_exceptions
def get_process_ppid(self):
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith("PPid:"):
# PPid: nnnn
return int(line.split()[1])
raise RuntimeError("line not found")
finally:
f.close()
@wrap_exceptions
def get_process_uids(self):
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith('Uid:'):
_, real, effective, saved, fs = line.split()
return nt_uids(int(real), int(effective), int(saved))
raise RuntimeError("line not found")
finally:
f.close()
@wrap_exceptions
def get_process_gids(self):
f = open("/proc/%s/status" % self.pid)
try:
for line in f:
if line.startswith('Gid:'):
_, real, effective, saved, fs = line.split()
return nt_gids(int(real), int(effective), int(saved))
raise RuntimeError("line not found")
finally:
f.close()
@staticmethod
def _decode_address(addr, family):
"""Accept an "ip:port" address as displayed in /proc/net/*
and convert it into a human readable form, like:
"0500000A:0016" -> ("10.0.0.5", 22)
"0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521)
The IP address portion is a little or big endian four-byte
hexadecimal number; that is, the least significant byte is listed
first, so we need to reverse the order of the bytes to convert it
to an IP address.
The port is represented as a two-byte hexadecimal number.
Reference:
http://linuxdevcenter.com/pub/a/linux/2000/11/16/LinuxAdmin.html
"""
ip, port = addr.split(':')
port = int(port, 16)
if PY3:
ip = ip.encode('ascii')
# this usually refers to a local socket in listen mode with
# no end-points connected
if not port:
return ()
if family == socket.AF_INET:
# see: http://code.google.com/p/psutil/issues/detail?id=201
if sys.byteorder == 'little':
ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1])
else:
ip = socket.inet_ntop(family, base64.b16decode(ip))
else: # IPv6
# old version - let's keep it, just in case...
#ip = ip.decode('hex')
#return socket.inet_ntop(socket.AF_INET6,
# ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4)))
ip = base64.b16decode(ip)
# see: http://code.google.com/p/psutil/issues/detail?id=201
if sys.byteorder == 'little':
ip = socket.inet_ntop(socket.AF_INET6,
struct.pack('>4I', *struct.unpack('<4I', ip)))
else:
ip = socket.inet_ntop(socket.AF_INET6,
struct.pack('<4I', *struct.unpack('<4I', ip)))
return (ip, port)
#!/usr/bin/env python
#
# $Id: _psmswindows.py 1514 2012-08-14 11:16:56Z g.rodola $
#
# 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 implementation."""
import errno
import os
import sys
import platform
import _psutil_mswindows
from _psutil_mswindows import ERROR_ACCESS_DENIED
from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
from psutil._common import *
from psutil._compat import PY3, xrange, long
# Windows specific extended namespace
__extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS"]
# --- module level constants (gets pushed up to psutil module)
NUM_CPUS = _psutil_mswindows.get_num_cpus()
BOOT_TIME = _psutil_mswindows.get_system_uptime()
TOTAL_PHYMEM = _psutil_mswindows.get_virtual_mem()[0]
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED])
# process priority constants:
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
from _psutil_mswindows import (ABOVE_NORMAL_PRIORITY_CLASS,
BELOW_NORMAL_PRIORITY_CLASS,
HIGH_PRIORITY_CLASS,
IDLE_PRIORITY_CLASS,
NORMAL_PRIORITY_CLASS,
REALTIME_PRIORITY_CLASS,
INFINITE)
@memoize
def _win32_QueryDosDevice(s):
return _psutil_mswindows.win32_QueryDosDevice(s)
def _convert_raw_path(s):
# convert paths using native DOS format like:
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
# into: "C:\Windows\systemew\file.txt"
if PY3 and not isinstance(s, str):
s = s.decode('utf8')
rawdrive = '\\'.join(s.split('\\')[:3])
driveletter = _win32_QueryDosDevice(rawdrive)
return os.path.join(driveletter, s[len(rawdrive):])
# --- public functions
nt_virtmem_info = namedtuple('vmem', ' '.join([
# all platforms
'total', 'available', 'percent', 'used', 'free']))
def virtual_memory():
"""System virtual memory as a namedtuple."""
mem = _psutil_mswindows.get_virtual_mem()
totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem
#
total = totphys
avail = availphys
free = availphys
used = total - avail
percent = usage_percent((total - avail), total, _round=1)
return nt_virtmem_info(total, avail, percent, used, free)
def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
mem = _psutil_mswindows.get_virtual_mem()
total = mem[2]
free = mem[3]
used = total - free
percent = usage_percent(used, total, _round=1)
return nt_swapmeminfo(total, used, free, percent, 0, 0)
def get_disk_usage(path):
"""Return disk usage associated with path."""
try:
total, free = _psutil_mswindows.get_disk_usage(path)
except WindowsError:
err = sys.exc_info()[1]
if not os.path.exists(path):
raise OSError(errno.ENOENT, "No such file or directory: '%s'" % path)
raise
used = total - free
percent = usage_percent(used, total, _round=1)
return nt_diskinfo(total, used, free, percent)
def disk_partitions(all):
"""Return disk partitions."""
rawlist = _psutil_mswindows.get_disk_partitions(all)
return [nt_partition(*x) for x in rawlist]
_cputimes_ntuple = namedtuple('cputimes', 'user system idle')
def get_system_cpu_times():
"""Return system CPU times as a named tuple."""
user, system, idle = 0, 0, 0
# computes system global times summing each processor value
for cpu_time in _psutil_mswindows.get_system_cpu_times():
user += cpu_time[0]
system += cpu_time[1]
idle += cpu_time[2]
return _cputimes_ntuple(user, system, idle)
def get_system_per_cpu_times():
"""Return system per-CPU times as a list of named tuples."""
ret = []
for cpu_t in _psutil_mswindows.get_system_cpu_times():
user, system, idle = cpu_t
item = _cputimes_ntuple(user, system, idle)
ret.append(item)
return ret
def get_system_users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = _psutil_mswindows.get_system_users()
for item in rawlist:
user, hostname, tstamp = item
nt = nt_user(user, None, hostname, tstamp)
retlist.append(nt)
return retlist
get_pid_list = _psutil_mswindows.get_pid_list
pid_exists = _psutil_mswindows.pid_exists
network_io_counters = _psutil_mswindows.get_network_io_counters
disk_io_counters = _psutil_mswindows.get_disk_io_counters
# --- decorator
def wrap_exceptions(callable):
"""Call callable into a try/except clause so that if a
WindowsError 5 AccessDenied exception is raised we translate it
into psutil.AccessDenied
"""
def wrapper(self, *args, **kwargs):
try:
return callable(self, *args, **kwargs)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
raise AccessDenied(self.pid, self._process_name)
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._process_name)
raise
return wrapper
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
self.pid = pid
self._process_name = None
@wrap_exceptions
def get_process_name(self):
"""Return process name as a string of limited len (15)."""
return _psutil_mswindows.get_process_name(self.pid)
@wrap_exceptions
def get_process_exe(self):
# Note: os.path.exists(path) may return False even if the file
# is there, see:
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
return _convert_raw_path(_psutil_mswindows.get_process_exe(self.pid))
@wrap_exceptions
def get_process_cmdline(self):
"""Return process cmdline as a list of arguments."""
return _psutil_mswindows.get_process_cmdline(self.pid)
@wrap_exceptions
def get_process_ppid(self):
"""Return process parent pid."""
return _psutil_mswindows.get_process_ppid(self.pid)
def _get_raw_meminfo(self):
try:
return _psutil_mswindows.get_process_memory_info(self.pid)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
return _psutil_mswindows.get_process_memory_info_2(self.pid)
raise
@wrap_exceptions
def get_memory_info(self):
"""Returns a tuple or RSS/VMS memory usage in bytes."""
# on Windows RSS == WorkingSetSize and VSM == PagefileUsage
# fields of PROCESS_MEMORY_COUNTERS struct:
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx
t = self._get_raw_meminfo()
return nt_meminfo(t[2], t[7])
_nt_ext_mem = namedtuple('meminfo',
' '.join(['num_page_faults',
'peak_wset',
'wset',
'peak_paged_pool',
'paged_pool',
'peak_nonpaged_pool',
'nonpaged_pool',
'pagefile',
'peak_pagefile',
'private',]))
@wrap_exceptions
def get_ext_memory_info(self):
return self._nt_ext_mem(*self._get_raw_meminfo())
nt_mmap_grouped = namedtuple('mmap', 'path rss')
nt_mmap_ext = namedtuple('mmap', 'addr perms path rss')
def get_memory_maps(self):
try:
raw = _psutil_mswindows.get_process_memory_maps(self.pid)
except OSError:
# XXX - can't use wrap_exceptions decorator as we're
# returning a generator; probably needs refactoring.
err = sys.exc_info()[1]
if err.errno in (errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED):
raise AccessDenied(self.pid, self._process_name)
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._process_name)
raise
else:
for addr, perm, path, rss in raw:
path = _convert_raw_path(path)
addr = hex(addr)
yield (addr, perm, path, rss)
@wrap_exceptions
def kill_process(self):
"""Terminates the process with the given PID."""
return _psutil_mswindows.kill_process(self.pid)
@wrap_exceptions
def process_wait(self, timeout=None):
if timeout is None:
timeout = INFINITE
else:
# WaitForSingleObject() expects time in milliseconds
timeout = int(timeout * 1000)
ret = _psutil_mswindows.process_wait(self.pid, timeout)
if ret == WAIT_TIMEOUT:
raise TimeoutExpired(self.pid, self._process_name)
return ret
@wrap_exceptions
def get_process_username(self):
"""Return the name of the user that owns the process"""
if self.pid in (0, 4):
return 'NT AUTHORITY\\SYSTEM'
return _psutil_mswindows.get_process_username(self.pid)
@wrap_exceptions
def get_process_create_time(self):
# special case for kernel process PIDs; return system boot time
if self.pid in (0, 4):
return BOOT_TIME
try:
return _psutil_mswindows.get_process_create_time(self.pid)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
return _psutil_mswindows.get_process_create_time_2(self.pid)
raise
@wrap_exceptions
def get_process_num_threads(self):
return _psutil_mswindows.get_process_num_threads(self.pid)
@wrap_exceptions
def get_process_threads(self):
rawlist = _psutil_mswindows.get_process_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = nt_thread(thread_id, utime, stime)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def get_cpu_times(self):
try:
ret = _psutil_mswindows.get_process_cpu_times(self.pid)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
ret = _psutil_mswindows.get_process_cpu_times_2(self.pid)
else:
raise
return nt_cputimes(*ret)
@wrap_exceptions
def suspend_process(self):
return _psutil_mswindows.suspend_process(self.pid)
@wrap_exceptions
def resume_process(self):
return _psutil_mswindows.resume_process(self.pid)
@wrap_exceptions
def get_process_cwd(self):
if self.pid in (0, 4):
raise AccessDenied(self.pid, self._process_name)
# return a normalized pathname since the native C function appends
# "\\" at the and of the path
path = _psutil_mswindows.get_process_cwd(self.pid)
return os.path.normpath(path)
@wrap_exceptions
def get_open_files(self):
if self.pid in (0, 4):
return []
retlist = []
# Filenames come in in native format like:
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
# Convert the first part in the corresponding drive letter
# (e.g. "C:\") by using Windows's QueryDosDevice()
raw_file_names = _psutil_mswindows.get_process_open_files(self.pid)
for file in raw_file_names:
file = _convert_raw_path(file)
if isfile_strict(file) and file not in retlist:
ntuple = nt_openfile(file, -1)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def get_connections(self, kind='inet'):
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
ret = _psutil_mswindows.get_process_connections(self.pid, families, types)
return [nt_connection(*conn) for conn in ret]
@wrap_exceptions
def get_process_nice(self):
return _psutil_mswindows.get_process_priority(self.pid)
@wrap_exceptions
def set_process_nice(self, value):
return _psutil_mswindows.set_process_priority(self.pid, value)
@wrap_exceptions
def get_process_io_counters(self):
try:
ret = _psutil_mswindows.get_process_io_counters(self.pid)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
ret = _psutil_mswindows.get_process_io_counters_2(self.pid)
else:
raise
return nt_io(*ret)
@wrap_exceptions
def get_process_status(self):
suspended = _psutil_mswindows.is_process_suspended(self.pid)
if suspended:
return STATUS_STOPPED
else:
return STATUS_RUNNING
@wrap_exceptions
def get_process_cpu_affinity(self):
from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x]
bitmask = _psutil_mswindows.get_process_cpu_affinity(self.pid)
return from_bitmask(bitmask)
@wrap_exceptions
def set_process_cpu_affinity(self, value):
def to_bitmask(l):
if not l:
raise ValueError("invalid argument %r" % l)
out = 0
for b in l:
if not isinstance(b, (int, long)) or b < 0:
raise ValueError("invalid argument %r" % b)
out |= 2**b
return out
# SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER
# is returned for an invalid CPU but this seems not to be true,
# therefore we check CPUs validy beforehand.
allcpus = list(range(len(get_system_per_cpu_times())))
for cpu in value:
if cpu not in allcpus:
raise ValueError("invalid CPU %i" % cpu)
bitmask = to_bitmask(value)
_psutil_mswindows.set_process_cpu_affinity(self.pid, bitmask)
@wrap_exceptions
def get_num_handles(self):
try:
return _psutil_mswindows.get_process_num_handles(self.pid)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
return _psutil_mswindows.get_process_num_handles_2(self.pid)
raise
@wrap_exceptions
def get_num_ctx_switches(self):
return nt_ctxsw(*_psutil_mswindows.get_process_num_ctx_switches(self.pid))
#!/usr/bin/env python
#
# $Id: _psosx.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""OSX platform implementation."""
import errno
import os
import sys
import _psutil_osx
import _psutil_posix
from psutil import _psposix
from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
from psutil._compat import namedtuple
from psutil._common import *
__extra__all__ = []
# --- constants
NUM_CPUS = _psutil_osx.get_num_cpus()
BOOT_TIME = _psutil_osx.get_system_boot_time()
TOTAL_PHYMEM = _psutil_osx.get_virtual_mem()[0]
_PAGESIZE = os.sysconf("SC_PAGE_SIZE")
_TERMINAL_MAP = _psposix._get_terminal_map()
_cputimes_ntuple = namedtuple('cputimes', 'user nice system idle')
# --- functions
nt_virtmem_info = namedtuple('vmem', ' '.join([
# all platforms
'total', 'available', 'percent', 'used', 'free',
# OSX specific
'active',
'inactive',
'wired']))
def virtual_memory():
"""System virtual memory as a namedtuple."""
total, active, inactive, wired, free = _psutil_osx.get_virtual_mem()
avail = inactive + free
used = active + inactive + wired
percent = usage_percent((total - avail), total, _round=1)
return nt_virtmem_info(total, avail, percent, used, free,
active, inactive, wired)
def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
total, used, free, sin, sout = _psutil_osx.get_swap_mem()
percent = usage_percent(used, total, _round=1)
return nt_swapmeminfo(total, used, free, percent, sin, sout)
def get_system_cpu_times():
"""Return system CPU times as a namedtuple."""
user, nice, system, idle = _psutil_osx.get_system_cpu_times()
return _cputimes_ntuple(user, nice, system, idle)
def get_system_per_cpu_times():
"""Return system CPU times as a named tuple"""
ret = []
for cpu_t in _psutil_osx.get_system_per_cpu_times():
user, nice, system, idle = cpu_t
item = _cputimes_ntuple(user, nice, system, idle)
ret.append(item)
return ret
def disk_partitions(all=False):
retlist = []
partitions = _psutil_osx.get_disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
if device == 'none':
device = ''
if not all:
if not os.path.isabs(device) \
or not os.path.exists(device):
continue
ntuple = nt_partition(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
def get_system_users():
retlist = []
rawlist = _psutil_osx.get_system_users()
for item in rawlist:
user, tty, hostname, tstamp = item
if tty == '~':
continue # reboot or shutdown
if not tstamp:
continue
nt = nt_user(user, tty or None, hostname or None, tstamp)
retlist.append(nt)
return retlist
get_pid_list = _psutil_osx.get_pid_list
pid_exists = _psposix.pid_exists
get_disk_usage = _psposix.get_disk_usage
network_io_counters = _psutil_osx.get_network_io_counters
disk_io_counters = _psutil_osx.get_disk_io_counters
# --- decorator
def wrap_exceptions(callable):
"""Call callable into a try/except clause so that if an
OSError EPERM exception is raised we translate it into
psutil.AccessDenied.
"""
def wrapper(self, *args, **kwargs):
try:
return callable(self, *args, **kwargs)
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
raise
return wrapper
_status_map = {
_psutil_osx.SIDL : STATUS_IDLE,
_psutil_osx.SRUN : STATUS_RUNNING,
_psutil_osx.SSLEEP : STATUS_SLEEPING,
_psutil_osx.SSTOP : STATUS_STOPPED,
_psutil_osx.SZOMB : STATUS_ZOMBIE,
}
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
self.pid = pid
self._process_name = None
@wrap_exceptions
def get_process_name(self):
"""Return process name as a string of limited len (15)."""
return _psutil_osx.get_process_name(self.pid)
@wrap_exceptions
def get_process_exe(self):
return _psutil_osx.get_process_exe(self.pid)
@wrap_exceptions
def get_process_cmdline(self):
"""Return process cmdline as a list of arguments."""
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._process_name)
return _psutil_osx.get_process_cmdline(self.pid)
@wrap_exceptions
def get_process_ppid(self):
"""Return process parent pid."""
return _psutil_osx.get_process_ppid(self.pid)
@wrap_exceptions
def get_process_cwd(self):
return _psutil_osx.get_process_cwd(self.pid)
@wrap_exceptions
def get_process_uids(self):
real, effective, saved = _psutil_osx.get_process_uids(self.pid)
return nt_uids(real, effective, saved)
@wrap_exceptions
def get_process_gids(self):
real, effective, saved = _psutil_osx.get_process_gids(self.pid)
return nt_gids(real, effective, saved)
@wrap_exceptions
def get_process_terminal(self):
tty_nr = _psutil_osx.get_process_tty_nr(self.pid)
try:
return _TERMINAL_MAP[tty_nr]
except KeyError:
return None
@wrap_exceptions
def get_memory_info(self):
"""Return a tuple with the process' RSS and VMS size."""
rss, vms = _psutil_osx.get_process_memory_info(self.pid)[:2]
return nt_meminfo(rss, vms)
_nt_ext_mem = namedtuple('meminfo', 'rss vms pfaults pageins')
@wrap_exceptions
def get_ext_memory_info(self):
"""Return a tuple with the process' RSS and VMS size."""
rss, vms, pfaults, pageins = _psutil_osx.get_process_memory_info(self.pid)
return self._nt_ext_mem(rss, vms,
pfaults * _PAGESIZE,
pageins * _PAGESIZE)
@wrap_exceptions
def get_cpu_times(self):
user, system = _psutil_osx.get_process_cpu_times(self.pid)
return nt_cputimes(user, system)
@wrap_exceptions
def get_process_create_time(self):
"""Return the start time of the process as a number of seconds since
the epoch."""
return _psutil_osx.get_process_create_time(self.pid)
@wrap_exceptions
def get_num_ctx_switches(self):
return nt_ctxsw(*_psutil_osx.get_process_num_ctx_switches(self.pid))
@wrap_exceptions
def get_process_num_threads(self):
"""Return the number of threads belonging to the process."""
return _psutil_osx.get_process_num_threads(self.pid)
@wrap_exceptions
def get_open_files(self):
"""Return files opened by process."""
if self.pid == 0:
return []
files = []
rawlist = _psutil_osx.get_process_open_files(self.pid)
for path, fd in rawlist:
if isfile_strict(path):
ntuple = nt_openfile(path, fd)
files.append(ntuple)
return files
@wrap_exceptions
def get_connections(self, kind='inet'):
"""Return etwork connections opened by a process as a list of
namedtuples.
"""
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
ret = _psutil_osx.get_process_connections(self.pid, families, types)
return [nt_connection(*conn) for conn in ret]
@wrap_exceptions
def get_num_fds(self):
if self.pid == 0:
return 0
return _psutil_osx.get_process_num_fds(self.pid)
@wrap_exceptions
def process_wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except TimeoutExpired:
raise TimeoutExpired(self.pid, self._process_name)
@wrap_exceptions
def get_process_nice(self):
return _psutil_posix.getpriority(self.pid)
@wrap_exceptions
def set_process_nice(self, value):
return _psutil_posix.setpriority(self.pid, value)
@wrap_exceptions
def get_process_status(self):
code = _psutil_osx.get_process_status(self.pid)
if code in _status_map:
return _status_map[code]
return constant(-1, "?")
@wrap_exceptions
def get_process_threads(self):
"""Return the number of threads belonging to the process."""
rawlist = _psutil_osx.get_process_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = nt_thread(thread_id, utime, stime)
retlist.append(ntuple)
return retlist
nt_mmap_grouped = namedtuple('mmap',
'path rss private swapped dirtied ref_count shadow_depth')
nt_mmap_ext = namedtuple('mmap',
'addr perms path rss private swapped dirtied ref_count shadow_depth')
@wrap_exceptions
def get_memory_maps(self):
return _psutil_osx.get_process_memory_maps(self.pid)
#!/usr/bin/env python
#
# $Id: _psposix.py 1409 2012-07-04 08:21:06Z g.rodola $
#
# 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.
"""Routines common to all posix systems."""
import os
import errno
import psutil
import sys
import time
import glob
from psutil.error import TimeoutExpired
from psutil._common import nt_diskinfo, usage_percent
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if not isinstance(pid, int):
raise TypeError('an integer is required')
if pid < 0:
return False
try:
os.kill(pid, 0)
except OSError:
e = sys.exc_info()[1]
return e.errno == errno.EPERM
else:
return True
def wait_pid(pid, timeout=None):
"""Wait for process with pid 'pid' to terminate and return its
exit status code as an integer.
If pid is not a children of os.getpid() (current process) just
waits until the process disappears and return None.
If pid does not exist at all return None immediately.
Raise TimeoutExpired on timeout expired.
"""
def check_timeout(delay):
if timeout is not None:
if time.time() >= stop_at:
raise TimeoutExpired(pid)
time.sleep(delay)
return min(delay * 2, 0.04)
if timeout is not None:
waitcall = lambda: os.waitpid(pid, os.WNOHANG)
stop_at = time.time() + timeout
else:
waitcall = lambda: os.waitpid(pid, 0)
delay = 0.0001
while 1:
try:
retpid, status = waitcall()
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.EINTR:
delay = check_timeout(delay)
continue
elif err.errno == errno.ECHILD:
# This has two meanings:
# - pid is not a child of os.getpid() in which case
# we keep polling until it's gone
# - pid never existed in the first place
# In both cases we'll eventually return None as we
# can't determine its exit status code.
while 1:
if pid_exists(pid):
delay = check_timeout(delay)
else:
return
else:
raise
else:
if retpid == 0:
# WNOHANG was used, pid is still running
delay = check_timeout(delay)
continue
# process exited due to a signal; return the integer of
# that signal
if os.WIFSIGNALED(status):
return os.WTERMSIG(status)
# process exited using exit(2) system call; return the
# integer exit(2) system call has been called with
elif os.WIFEXITED(status):
return os.WEXITSTATUS(status)
else:
# should never happen
raise RuntimeError("unknown process exit status")
def get_disk_usage(path):
"""Return disk usage associated with path."""
st = os.statvfs(path)
free = (st.f_bavail * st.f_frsize)
total = (st.f_blocks * st.f_frsize)
used = (st.f_blocks - st.f_bfree) * st.f_frsize
percent = usage_percent(used, total, _round=1)
# NB: the percentage is -5% than what shown by df due to
# reserved blocks that we are currently not considering:
# http://goo.gl/sWGbH
return nt_diskinfo(total, used, free, percent)
def _get_terminal_map():
ret = {}
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
for name in ls:
assert name not in ret
ret[os.stat(name).st_rdev] = name
return ret
/*
* $Id: _psutil_bsd.c 1513 2012-08-14 11:01:37Z g.rodola $
*
* 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.
*
* FreeBSD platform-specific module methods for _psutil_bsd
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <net/route.h>
#include <sys/socket.h>
#include <sys/socketvar.h> /* for struct socket */
#include <sys/protosw.h> /* for struct proto */
#include <sys/domain.h> /* for struct domain */
#include <sys/un.h> /* for unpcb struct (UNIX sockets) */
#include <sys/unpcb.h> /* for unpcb struct (UNIX sockets) */
#include <sys/mbuf.h> /* for mbuf struct (UNIX sockets) */
/* for in_pcb struct */
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/tcp_var.h> /* for struct tcpcb */
#include <netinet/tcp_fsm.h> /* for TCP connection states */
#include <arpa/inet.h> /* for inet_ntop() */
#if __FreeBSD_version < 900000
#include <utmp.h> /* system users */
#else
#include <utmpx.h>
#endif
#include <devstat.h> /* get io counters */
#include <sys/vmmeter.h> /* needed for vmtotal struct */
#include <libutil.h> /* process open files, shared libs (kinfo_getvmmap) */
#include <sys/mount.h>
#include <net/if.h> /* net io counters */
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h> /* process open files/connections */
#include <sys/un.h>
#include "_psutil_bsd.h"
#include "_psutil_common.h"
#include "arch/bsd/process_info.h"
// convert a timeval struct to a double
#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
/*
* Utility function which fills a kinfo_proc struct based on process pid
*/
static int
get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc)
{
int mib[4];
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = pid;
size = sizeof(struct kinfo_proc);
if (sysctl((int*)mib, 4, proc, &size, NULL, 0) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
/*
* sysctl stores 0 in the size if we can't find the process information.
*/
if (size == 0) {
NoSuchProcess();
return -1;
}
return 0;
}
/*
* Return a Python list of all the PIDs running on the system.
*/
static PyObject*
get_pid_list(PyObject* self, PyObject* args)
{
kinfo_proc *proclist = NULL;
kinfo_proc *orig_address = NULL;
size_t num_processes;
size_t idx;
PyObject* retlist = PyList_New(0);
PyObject* pid = NULL;
if (get_proc_list(&proclist, &num_processes) != 0) {
PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list.");
goto error;
}
if (num_processes > 0) {
orig_address = proclist; // save so we can free it after we're done
for (idx=0; idx < num_processes; idx++) {
pid = Py_BuildValue("i", proclist->ki_pid);
if (!pid)
goto error;
if (PyList_Append(retlist, pid))
goto error;
Py_DECREF(pid);
proclist++;
}
free(orig_address);
}
return retlist;
error:
Py_XDECREF(pid);
Py_DECREF(retlist);
if (orig_address != NULL) {
free(orig_address);
}
return NULL;
}
/*
* Return a Python float indicating the system boot time expressed in
* seconds since the epoch.
*/
static PyObject*
get_system_boot_time(PyObject* self, PyObject* args)
{
/* fetch sysctl "kern.boottime" */
static int request[2] = { CTL_KERN, KERN_BOOTTIME };
struct timeval result;
size_t result_len = sizeof result;
time_t boot_time = 0;
if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
return NULL;
}
boot_time = result.tv_sec;
return Py_BuildValue("f", (float)boot_time);
}
/*
* Return process name from kinfo_proc as a Python string.
*/
static PyObject*
get_process_name(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("s", kp.ki_comm);
}
/*
* Return process pathname executable.
* Thanks to Robert N. M. Watson:
* http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
*/
static PyObject*
get_process_exe(PyObject* self, PyObject* args)
{
long pid;
char pathname[PATH_MAX];
int error;
int mib[4];
size_t size;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (pid == 0) {
// ...otherwise we'd get '\x98\xd5\xbf\xbf\xfb\xf3\x10\x08H\x01'
return Py_BuildValue("s", "");
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = pid;
size = sizeof(pathname);
error = sysctl(mib, 4, pathname, &size, NULL, 0);
if (error == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return Py_BuildValue("s", pathname);
}
/*
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject*
get_process_cmdline(PyObject* self, PyObject* args)
{
long pid;
PyObject* arglist = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
// get the commandline, defined in arch/bsd/process_info.c
arglist = get_arg_list(pid);
// get_arg_list() returns NULL only if getcmdargs failed with ESRCH
// (no process with that PID)
if (NULL == arglist) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return Py_BuildValue("N", arglist);
}
/*
* Return process parent pid from kinfo_proc as a Python integer.
*/
static PyObject*
get_process_ppid(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("l", (long)kp.ki_ppid);
}
/*
* Return process status as a Python integer.
*/
static PyObject*
get_process_status(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("i", (int)kp.ki_stat);
}
/*
* Return process real, effective and saved user ids from kinfo_proc
* as a Python tuple.
*/
static PyObject*
get_process_uids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("lll", (long)kp.ki_ruid,
(long)kp.ki_uid,
(long)kp.ki_svuid);
}
/*
* Return process real, effective and saved group ids from kinfo_proc
* as a Python tuple.
*/
static PyObject*
get_process_gids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("lll", (long)kp.ki_rgid,
(long)kp.ki_groups[0],
(long)kp.ki_svuid);
}
/*
* Return process real, effective and saved group ids from kinfo_proc
* as a Python tuple.
*/
static PyObject*
get_process_tty_nr(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("i", kp.ki_tdev);
}
/*
* Return the number of context switches performed by process as a tuple.
*/
static PyObject*
get_process_num_ctx_switches(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("(ll)", kp.ki_rusage.ru_nvcsw,
kp.ki_rusage.ru_nivcsw);
}
/*
* Return number of threads used by process as a Python integer.
*/
static PyObject*
get_process_num_threads(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("l", (long)kp.ki_numthreads);
}
/*
* Retrieves all threads used by process returning a list of tuples
* including thread id, user time and system time.
* Thanks to Robert N. M. Watson:
* http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRENT
*/
static PyObject*
get_process_threads(PyObject* self, PyObject* args)
{
long pid;
int mib[4];
struct kinfo_proc *kip = NULL;
struct kinfo_proc *kipp;
int error;
unsigned int i;
size_t size;
PyObject* retList = PyList_New(0);
PyObject* pyTuple = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
/*
* We need to re-query for thread information, so don't use *kipp.
*/
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
mib[3] = pid;
size = 0;
error = sysctl(mib, 4, NULL, &size, NULL, 0);
if (error == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if (size == 0) {
NoSuchProcess();
goto error;
}
kip = malloc(size);
if (kip == NULL) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
error = sysctl(mib, 4, kip, &size, NULL, 0);
if (error == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if (size == 0) {
NoSuchProcess();
goto error;
}
for (i = 0; i < size / sizeof(*kipp); i++) {
kipp = &kip[i];
pyTuple = Py_BuildValue("Idd", kipp->ki_tid,
TV2DOUBLE(kipp->ki_rusage.ru_utime),
TV2DOUBLE(kipp->ki_rusage.ru_stime)
);
if (pyTuple == NULL)
goto error;
if (PyList_Append(retList, pyTuple))
goto error;
Py_DECREF(pyTuple);
}
free(kip);
return retList;
error:
Py_XDECREF(pyTuple);
Py_DECREF(retList);
if (kip != NULL) {
free(kip);
}
return NULL;
}
/*
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject*
get_process_cpu_times(PyObject* self, PyObject* args)
{
long pid;
double user_t, sys_t;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
// convert from microseconds to seconds
user_t = TV2DOUBLE(kp.ki_rusage.ru_utime);
sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime);
return Py_BuildValue("(dd)", user_t, sys_t);
}
/*
* Return a Python integer indicating the number of CPUs on the system
*/
static PyObject*
get_num_cpus(PyObject* self, PyObject* args)
{
int mib[2];
int ncpu;
size_t len;
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
return NULL;
}
return Py_BuildValue("i", ncpu);
}
/*
* Return a Python float indicating the process create time expressed in
* seconds since the epoch.
*/
static PyObject*
get_process_create_time(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("d", TV2DOUBLE(kp.ki_start));
}
/*
* Return a Python float indicating the process create time expressed in
* seconds since the epoch.
*/
static PyObject*
get_process_io_counters(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
// there's apparently no way to determine bytes count, hence return -1.
return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock,
kp.ki_rusage.ru_oublock,
-1, -1);
}
/*
* Return extended memory info for a process as a Python tuple.
*/
static PyObject*
get_process_memory_info(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("(lllll)", ptoa(kp.ki_rssize), // rss
(long)kp.ki_size, // vms
ptoa(kp.ki_tsize), // text
ptoa(kp.ki_dsize), // data
ptoa(kp.ki_ssize)); // stack
}
/*
* Return virtual memory usage statistics.
*/
static PyObject*
get_virtual_mem(PyObject* self, PyObject* args)
{
unsigned int total, active, inactive, wired, cached, free, buffers;
size_t size = sizeof(total);
struct vmtotal vm;
int mib[] = {CTL_VM, VM_METER};
long pagesize = getpagesize();
if (sysctlbyname("vm.stats.vm.v_page_count", &total, &size, NULL, 0))
goto error;
if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0))
goto error;
if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactive, &size, NULL, 0))
goto error;
if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0))
goto error;
if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0))
goto error;
if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0))
goto error;
if (sysctlbyname("vfs.bufspace", &buffers, &size, NULL, 0))
goto error;
size = sizeof(vm);
if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0)
goto error;
return Py_BuildValue("KKKKKKKK",
(unsigned long long) total * pagesize,
(unsigned long long) free * pagesize,
(unsigned long long) active * pagesize,
(unsigned long long) inactive * pagesize,
(unsigned long long) wired * pagesize,
(unsigned long long) cached * pagesize,
(unsigned long long) buffers,
(unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared
);
error:
PyErr_SetFromErrno(0);
return NULL;
}
/*
* Return swap memory stats (see 'swapinfo' cmdline tool)
*/
static PyObject*
get_swap_mem(PyObject* self, PyObject* args)
{
kvm_t *kd;
struct kvm_swap kvmsw[1];
unsigned int swapin, swapout, nodein, nodeout;
size_t size = sizeof(unsigned int);
if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) {
PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed");
return NULL;
}
if (sysctlbyname("vm.stats.vm.v_swapin", &swapin, &size, NULL, 0) == -1)
goto sbn_error;
if (sysctlbyname("vm.stats.vm.v_swapout", &swapout, &size, NULL, 0) == -1)
goto sbn_error;
if (sysctlbyname("vm.stats.vm.v_vnodein", &nodein, &size, NULL, 0) == -1)
goto sbn_error;
if (sysctlbyname("vm.stats.vm.v_vnodeout", &nodeout, &size, NULL, 0) == -1)
goto sbn_error;
return Py_BuildValue("(iiiII)",
kvmsw[0].ksw_total, // total
kvmsw[0].ksw_used, // used
kvmsw[0].ksw_total - kvmsw[0].ksw_used, // free
swapin + swapout, // swap in
nodein + nodeout); // swap out
sbn_error:
PyErr_SetFromErrno(0);
return NULL;
}
/*
* Return a Python tuple representing user, kernel and idle CPU times
*/
static PyObject*
get_system_cpu_times(PyObject* self, PyObject* args)
{
long cpu_time[CPUSTATES];
size_t size;
size = sizeof(cpu_time);
if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
return NULL;
}
return Py_BuildValue("(ddddd)",
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC
);
}
/*
* XXX
* These functions are available on FreeBSD 8 only.
* In the upper python layer we do various tricks to avoid crashing
* and/or to provide alternatives where possible.
*/
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
/*
* Return files opened by process as a list of (path, fd) tuples
*/
static PyObject*
get_process_open_files(PyObject* self, PyObject* args)
{
long pid;
int i, cnt;
PyObject *retList = PyList_New(0);
PyObject *tuple = NULL;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
struct kinfo_proc kipp;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
if (get_kinfo_proc(pid, &kipp) == -1)
goto error;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
PyErr_SetFromErrno(0);
goto error;
}
for (i = 0; i < cnt; i++) {
kif = &freep[i];
if ((kif->kf_type == KF_TYPE_VNODE) &&
(kif->kf_vnode_type == KF_VTYPE_VREG))
{
tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
if (tuple == NULL)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
}
}
free(freep);
return retList;
error:
Py_XDECREF(tuple);
Py_DECREF(retList);
if (freep != NULL)
free(freep);
return NULL;
}
/*
* Return files opened by process as a list of (path, fd) tuples
*/
static PyObject*
get_process_num_fds(PyObject* self, PyObject* args)
{
long pid;
int cnt;
struct kinfo_file *freep;
struct kinfo_proc kipp;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (get_kinfo_proc(pid, &kipp) == -1)
return NULL;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
PyErr_SetFromErrno(0);
return NULL;
}
free(freep);
return Py_BuildValue("i", cnt);
}
/*
* Return process current working directory.
*/
static PyObject*
get_process_cwd(PyObject* self, PyObject* args)
{
long pid;
PyObject *path = NULL;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
struct kinfo_proc kipp;
int i, cnt;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
if (get_kinfo_proc(pid, &kipp) == -1)
goto error;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
PyErr_SetFromErrno(0);
goto error;
}
for (i = 0; i < cnt; i++) {
kif = &freep[i];
if (kif->kf_fd == KF_FD_TYPE_CWD) {
path = Py_BuildValue("s", kif->kf_path);
if (!path)
goto error;
break;
}
}
/*
* For lower pids it seems we can't retrieve any information
* (lsof can't do that it either). Since this happens even
* as root we return an empty string instead of AccessDenied.
*/
if (path == NULL) {
path = Py_BuildValue("s", "");
}
free(freep);
return path;
error:
Py_XDECREF(path);
if (freep != NULL)
free(freep);
return NULL;
}
/*
* mathes Linux net/tcp_states.h:
* http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
*/
static char *
get_connection_status(int st) {
switch (st) {
case TCPS_CLOSED:
return "CLOSE";
case TCPS_CLOSING:
return "CLOSING";
case TCPS_CLOSE_WAIT:
return "CLOSE_WAIT";
case TCPS_LISTEN:
return "LISTEN";
case TCPS_ESTABLISHED:
return "ESTABLISHED";
case TCPS_SYN_SENT:
return "SYN_SENT";
case TCPS_SYN_RECEIVED:
return "SYN_RECV";
case TCPS_FIN_WAIT_1:
return "FIN_WAIT_1";
case TCPS_FIN_WAIT_2:
return "FIN_WAIT_2";
case TCPS_LAST_ACK:
return "LAST_ACK";
case TCPS_TIME_WAIT:
return "TIME_WAIT";
default:
return "?";
}
}
// a kvm_read that returns true if everything is read
#define KVM_READ(kaddr, paddr, len) \
((len) < SSIZE_MAX && \
kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (ssize_t)(len))
// XXX - copied from sys/file.h to make compiler happy
struct file {
void *f_data; /* file descriptor specific data */
struct fileops *f_ops; /* File operations */
struct ucred *f_cred; /* associated credentials. */
struct vnode *f_vnode; /* NULL or applicable vnode */
short f_type; /* descriptor type */
short f_vnread_flags; /* (f) Sleep lock for f_offset */
volatile u_int f_flag; /* see fcntl.h */
volatile u_int f_count; /* reference count */
int f_seqcount; /* Count of sequential accesses. */
off_t f_nextoff; /* next expected read/write offset. */
struct cdev_privdata *f_cdevpriv; /* (d) Private data for the cdev. */
off_t f_offset;
void *f_label; /* Place-holder for MAC label. */
};
/*
* Return connections opened by process.
* fstat.c source code was used as an example.
*/
static PyObject*
get_process_connections(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc *p;
struct file **ofiles = NULL;
char buf[_POSIX2_LINE_MAX];
char path[PATH_MAX];
int cnt;
int i;
kvm_t *kd = NULL;
struct file file;
struct filedesc filed;
struct nlist nl[] = {{ "" },};
struct socket so;
struct protosw proto;
struct domain dom;
struct inpcb inpcb;
struct tcpcb tcpcb;
struct unpcb unpcb;
PyObject *retList = PyList_New(0);
PyObject *tuple = NULL;
PyObject *laddr = NULL;
PyObject *raddr = NULL;
PyObject *af_filter = NULL;
PyObject *type_filter = NULL;
PyObject* _family = NULL;
PyObject* _type = NULL;
if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
goto error;
}
if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf);
if (kd == NULL) {
AccessDenied();
goto error;
}
if (kvm_nlist(kd, nl) != 0) {
PyErr_SetString(PyExc_RuntimeError, "kvm_nlist() failed");
goto error;
}
p = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
if (p == NULL) {
NoSuchProcess();
goto error;
}
if (cnt != 1) {
NoSuchProcess();
goto error;
}
if (p->ki_fd == NULL) {
PyErr_SetString(PyExc_RuntimeError, "no usable fd found");
goto error;
}
if (!KVM_READ(p->ki_fd, &filed, sizeof(filed))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() failed");
goto error;
}
ofiles = malloc((filed.fd_lastfile+1) * sizeof(struct file *));
if (ofiles == NULL) {
PyErr_SetString(PyExc_RuntimeError, "malloc() failed");
goto error;
}
if (!KVM_READ(filed.fd_ofiles, ofiles,
(filed.fd_lastfile+1) * sizeof(struct file *))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() failed");
goto error;
}
for (i = 0; i <= filed.fd_lastfile; i++) {
int lport, rport;
char lip[200], rip[200];
char *state;
int inseq;
tuple = NULL;
laddr = NULL;
raddr = NULL;
if (ofiles[i] == NULL) {
continue;
}
if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() file failed");
goto error;
}
if (file.f_type == DTYPE_SOCKET) {
// fill in socket
if (!KVM_READ(file.f_data, &so, sizeof(struct socket))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() socket failed");
goto error;
}
// fill in protosw entry
if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() proto failed");
goto error;
}
// fill in domain
if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() domain failed");
goto error;
}
// apply filters
_family = PyLong_FromLong((long)dom.dom_family);
inseq = PySequence_Contains(af_filter, _family);
Py_DECREF(_family);
if (inseq == 0) {
continue;
}
_type = PyLong_FromLong((long)proto.pr_type);
inseq = PySequence_Contains(type_filter, _type);
Py_DECREF(_type);
if (inseq == 0) {
continue;
}
// IPv4 / IPv6 socket
if ((dom.dom_family == AF_INET) || (dom.dom_family == AF_INET6)) {
// fill inpcb
if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
sizeof(struct inpcb)) != sizeof(struct inpcb)) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() addr failed");
goto error;
}
// fill status
if (proto.pr_type == SOCK_STREAM) {
if (kvm_read(kd, (u_long)inpcb.inp_ppcb, (char *)&tcpcb,
sizeof(struct tcpcb)) != sizeof(struct tcpcb)) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() state failed");
goto error;
}
state = get_connection_status((int)tcpcb.t_state);
}
else {
state = "";
}
// build addr and port
if (dom.dom_family == AF_INET) {
inet_ntop(AF_INET, &inpcb.inp_laddr.s_addr, lip, sizeof(lip));
inet_ntop(AF_INET, &inpcb.inp_faddr.s_addr, rip, sizeof(rip));
}
else {
inet_ntop(AF_INET6, &inpcb.in6p_laddr.s6_addr, lip, sizeof(lip));
inet_ntop(AF_INET6, &inpcb.in6p_faddr.s6_addr, rip, sizeof(rip));
}
lport = ntohs(inpcb.inp_lport);
rport = ntohs(inpcb.inp_fport);
// contruct python tuple/list
laddr = Py_BuildValue("(si)", lip, lport);
if (!laddr)
goto error;
if (rport != 0) {
raddr = Py_BuildValue("(si)", rip, rport);
}
else {
raddr = Py_BuildValue("()");
}
if (!raddr)
goto error;
tuple = Py_BuildValue("(iiiNNs)", i,
dom.dom_family,
proto.pr_type,
laddr,
raddr,
state);
if (!tuple)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
}
// UNIX socket
else if (dom.dom_family == AF_UNIX) {
struct sockaddr_un sun;
path[0] = '\0';
if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
sizeof(struct unpcb)) != sizeof(struct unpcb)) {
PyErr_SetString(PyExc_RuntimeError, "kvm_read() unpcb failed");
goto error;
}
if (unpcb.unp_addr) {
if (kvm_read(kd, (u_long)unpcb.unp_addr, (char *)&sun,
sizeof(sun)) != sizeof(sun)) {
PyErr_SetString(PyExc_RuntimeError,
"kvm_read() sockaddr_un failed");
goto error;
}
sprintf(path, "%.*s",
(sun.sun_len - (sizeof(sun) - sizeof(sun.sun_path))),
sun.sun_path);
}
tuple = Py_BuildValue("(iiisOs)", i,
dom.dom_family,
proto.pr_type,
path,
Py_None,
"");
if (!tuple)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
Py_INCREF(Py_None);
}
}
}
free(ofiles);
kvm_close(kd);
return retList;
error:
Py_XDECREF(tuple);
Py_XDECREF(laddr);
Py_XDECREF(raddr);
Py_DECREF(retList);
if (kd != NULL) {
kvm_close(kd);
}
if (ofiles != NULL) {
free(ofiles);
}
return NULL;
}
/*
* Return a Python list of tuple representing per-cpu times
*/
static PyObject*
get_system_per_cpu_times(PyObject* self, PyObject* args)
{
static int maxcpus;
int mib[2];
int ncpu;
size_t len;
size_t size;
int i;
PyObject* py_retlist = PyList_New(0);
PyObject* py_cputime = NULL;
// retrieve maxcpus value
size = sizeof(maxcpus);
if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
Py_DECREF(py_retlist);
PyErr_SetFromErrno(0);
return NULL;
}
long cpu_time[maxcpus][CPUSTATES];
// retrieve the number of cpus
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
goto error;
}
// per-cpu info
size = sizeof(cpu_time);
if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
goto error;
}
for (i = 0; i < ncpu; i++) {
py_cputime = Py_BuildValue("(ddddd)",
(double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC,
(double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC,
(double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC,
(double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC,
(double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC
);
if (!py_cputime)
goto error;
if (PyList_Append(py_retlist, py_cputime))
goto error;
Py_DECREF(py_cputime);
}
return py_retlist;
error:
Py_XDECREF(py_cputime);
Py_DECREF(py_retlist);
return NULL;
}
/*
* Return a list of tuples for every process memory maps.
* 'procstat' cmdline utility has been used as an example.
*/
static PyObject*
get_process_memory_maps(PyObject* self, PyObject* args)
{
long pid;
int ptrwidth;
int i, cnt;
char addr[30];
char perms[10];
const char *path;
struct kinfo_proc kp;
struct kinfo_vmentry *freep = NULL;
struct kinfo_vmentry *kve;
PyObject* pytuple = NULL;
PyObject* retlist = PyList_New(0);
ptrwidth = 2*sizeof(void *);
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
if (get_kinfo_proc(pid, &kp) == -1) {
goto error;
}
freep = kinfo_getvmmap(pid, &cnt);
if (freep == NULL) {
PyErr_SetString(PyExc_RuntimeError, "kinfo_getvmmap() failed");
goto error;
}
for (i = 0; i < cnt; i++) {
pytuple = NULL;
kve = &freep[i];
addr[0] = '\0';
perms[0] = '\0';
sprintf(addr, "%#*jx-%#*jx", ptrwidth, (uintmax_t)kve->kve_start,
ptrwidth, (uintmax_t)kve->kve_end);
strlcat(perms, kve->kve_protection & KVME_PROT_READ ? "r" : "-",
sizeof(perms));
strlcat(perms, kve->kve_protection & KVME_PROT_WRITE ? "w" : "-",
sizeof(perms));
strlcat(perms, kve->kve_protection & KVME_PROT_EXEC ? "x" : "-",
sizeof(perms));
if (strlen(kve->kve_path) == 0) {
switch (kve->kve_type) {
case KVME_TYPE_NONE:
path = "[none]";
break;
case KVME_TYPE_DEFAULT:
path = "[default]";
break;
case KVME_TYPE_VNODE:
path = "[vnode]";
break;
case KVME_TYPE_SWAP:
path = "[swap]";
break;
case KVME_TYPE_DEVICE:
path = "[device]";
break;
case KVME_TYPE_PHYS:
path = "[phys]";
break;
case KVME_TYPE_DEAD:
path = "[dead]";
break;
case KVME_TYPE_SG:
path = "[sg]";
break;
case KVME_TYPE_UNKNOWN:
path = "[unknown]";
break;
default:
path = "[?]";
break;
}
}
else {
path = kve->kve_path;
}
pytuple = Py_BuildValue("sssiiii",
addr, // "start-end" address
perms, // "rwx" permissions
path, // path
kve->kve_resident, // rss
kve->kve_private_resident, // private
kve->kve_ref_count, // ref count
kve->kve_shadow_count // shadow count
);
if (!pytuple)
goto error;
if (PyList_Append(retlist, pytuple))
goto error;
Py_DECREF(pytuple);
}
free(freep);
return retlist;
error:
Py_XDECREF(pytuple);
Py_DECREF(retlist);
if (freep != NULL)
free(freep);
return NULL;
}
#endif
/*
* Return a list of tuples including device, mount point and fs type
* for all partitions mounted on the system.
*/
static PyObject*
get_disk_partitions(PyObject* self, PyObject* args)
{
int num;
int i;
long len;
uint64_t flags;
char opts[200];
struct statfs *fs = NULL;
PyObject* py_retlist = PyList_New(0);
PyObject* py_tuple = NULL;
// get the number of mount points
Py_BEGIN_ALLOW_THREADS
num = getfsstat(NULL, 0, MNT_NOWAIT);
Py_END_ALLOW_THREADS
if (num == -1) {
PyErr_SetFromErrno(0);
goto error;
}
len = sizeof(*fs) * num;
fs = malloc(len);
Py_BEGIN_ALLOW_THREADS
num = getfsstat(fs, len, MNT_NOWAIT);
Py_END_ALLOW_THREADS
if (num == -1) {
PyErr_SetFromErrno(0);
goto error;
}
for (i = 0; i < num; i++) {
py_tuple = NULL;
opts[0] = 0;
flags = fs[i].f_flags;
// see sys/mount.h
if (flags & MNT_RDONLY)
strlcat(opts, "ro", sizeof(opts));
else
strlcat(opts, "rw", sizeof(opts));
if (flags & MNT_SYNCHRONOUS)
strlcat(opts, ",sync", sizeof(opts));
if (flags & MNT_NOEXEC)
strlcat(opts, ",noexec", sizeof(opts));
if (flags & MNT_NOSUID)
strlcat(opts, ",nosuid", sizeof(opts));
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_ASYNC)
strlcat(opts, ",async", sizeof(opts));
if (flags & MNT_SUIDDIR)
strlcat(opts, ",suiddir", sizeof(opts));
if (flags & MNT_SOFTDEP)
strlcat(opts, ",softdep", sizeof(opts));
if (flags & MNT_NOSYMFOLLOW)
strlcat(opts, ",nosymfollow", sizeof(opts));
if (flags & MNT_GJOURNAL)
strlcat(opts, ",gjournal", sizeof(opts));
if (flags & MNT_MULTILABEL)
strlcat(opts, ",multilabel", sizeof(opts));
if (flags & MNT_ACLS)
strlcat(opts, ",acls", sizeof(opts));
if (flags & MNT_NOATIME)
strlcat(opts, ",noatime", sizeof(opts));
if (flags & MNT_NOCLUSTERR)
strlcat(opts, ",noclusterr", sizeof(opts));
if (flags & MNT_NOCLUSTERW)
strlcat(opts, ",noclusterw", sizeof(opts));
if (flags & MNT_NFS4ACLS)
strlcat(opts, ",nfs4acls", sizeof(opts));
py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device
fs[i].f_mntonname, // mount point
fs[i].f_fstypename, // fs type
opts); // options
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
free(fs);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (fs != NULL)
free(fs);
return NULL;
}
/*
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject*
get_network_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_ifc_info = NULL;
char *buf = NULL, *lim, *next;
struct if_msghdr *ifm;
int mib[6];
size_t len;
mib[0] = CTL_NET; // networking subsystem
mib[1] = PF_ROUTE; // type of information
mib[2] = 0; // protocol (IPPROTO_xxx)
mib[3] = 0; // address family
mib[4] = NET_RT_IFLIST; // operation
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(0);
goto error;
}
buf = malloc(len);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(0);
goto error;
}
lim = buf + len;
for (next = buf; next < lim; ) {
py_ifc_info = NULL;
ifm = (struct if_msghdr *)next;
next += ifm->ifm_msglen;
if (ifm->ifm_type == RTM_IFINFO) {
struct if_msghdr *if2m = (struct if_msghdr *)ifm;
struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
char ifc_name[32];
strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
ifc_name[sdl->sdl_nlen] = 0;
py_ifc_info = Py_BuildValue("(kkkkkkki)",
if2m->ifm_data.ifi_obytes,
if2m->ifm_data.ifi_ibytes,
if2m->ifm_data.ifi_opackets,
if2m->ifm_data.ifi_ipackets,
if2m->ifm_data.ifi_ierrors,
if2m->ifm_data.ifi_oerrors,
if2m->ifm_data.ifi_iqdrops,
0); // dropout not supported
if (!py_ifc_info)
goto error;
if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
goto error;
Py_DECREF(py_ifc_info);
}
else {
continue;
}
}
free(buf);
return py_retdict;
error:
Py_XDECREF(py_ifc_info);
Py_DECREF(py_retdict);
if (buf != NULL)
free(buf);
return NULL;
}
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject*
get_disk_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_disk_info = NULL;
int i;
struct statinfo stats;
if (devstat_checkversion(NULL) < 0) {
PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed");
goto error;
}
stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
bzero(stats.dinfo, sizeof(struct devinfo));
if (devstat_getdevs(NULL, &stats) == -1) {
PyErr_Format(PyExc_RuntimeError, "devstat_getdevs() failed");
goto error;
}
for (i = 0; i < stats.dinfo->numdevs; i++) {
py_disk_info = NULL;
struct devstat current;
char disk_name[128];
current = stats.dinfo->devices[i];
snprintf(disk_name, sizeof(disk_name), "%s%d",
current.device_name,
current.unit_number);
py_disk_info = Py_BuildValue("(KKKKLL)",
current.operations[DEVSTAT_READ], // no reads
current.operations[DEVSTAT_WRITE], // no writes
current.bytes[DEVSTAT_READ], // bytes read
current.bytes[DEVSTAT_WRITE], // bytes written
(long long)devstat_compute_etime(
&current.duration[DEVSTAT_READ], NULL), // r time
(long long)devstat_compute_etime(
&current.duration[DEVSTAT_WRITE], NULL) // w time
);
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
goto error;
Py_DECREF(py_disk_info);
}
if (stats.dinfo->mem_ptr) {
free(stats.dinfo->mem_ptr);
}
free(stats.dinfo);
return py_retdict;
error:
Py_XDECREF(py_disk_info);
Py_DECREF(py_retdict);
if (stats.dinfo != NULL)
free(stats.dinfo);
return NULL;
}
/*
* Return currently connected users as a list of tuples.
*/
static PyObject*
get_system_users(PyObject* self, PyObject* args)
{
PyObject *ret_list = PyList_New(0);
PyObject *tuple = NULL;
#if __FreeBSD_version < 900000
struct utmp ut;
FILE *fp;
fp = fopen(_PATH_UTMP, "r");
if (fp == NULL) {
PyErr_SetFromErrno(0);
goto error;
}
while (fread(&ut, sizeof(ut), 1, fp) == 1) {
if (*ut.ut_name == '\0')
continue;
tuple = Py_BuildValue("(sssf)",
ut.ut_name, // username
ut.ut_line, // tty
ut.ut_host, // hostname
(float)ut.ut_time // start time
);
if (!tuple) {
fclose(fp);
goto error;
}
if (PyList_Append(ret_list, tuple)) {
fclose(fp);
goto error;
}
Py_DECREF(tuple);
}
fclose(fp);
#else
struct utmpx *utx;
while ((utx = getutxent()) != NULL) {
if (utx->ut_type != USER_PROCESS)
continue;
tuple = Py_BuildValue("(sssf)",
utx->ut_user, // username
utx->ut_line, // tty
utx->ut_host, // hostname
(float)utx->ut_tv.tv_sec // start time
);
if (!tuple) {
endutxent();
goto error;
}
if (PyList_Append(ret_list, tuple)) {
endutxent();
goto error;
}
Py_DECREF(tuple);
}
endutxent();
#endif
return ret_list;
error:
Py_XDECREF(tuple);
Py_DECREF(ret_list);
return NULL;
}
/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] =
{
// --- per-process functions
{"get_process_name", get_process_name, METH_VARARGS,
"Return process name"},
{"get_process_connections", get_process_connections, METH_VARARGS,
"Return connections opened by process"},
{"get_process_exe", get_process_exe, METH_VARARGS,
"Return process pathname executable"},
{"get_process_cmdline", get_process_cmdline, METH_VARARGS,
"Return process cmdline as a list of cmdline arguments"},
{"get_process_ppid", get_process_ppid, METH_VARARGS,
"Return process ppid as an integer"},
{"get_process_uids", get_process_uids, METH_VARARGS,
"Return process real effective and saved user ids as a Python tuple"},
{"get_process_gids", get_process_gids, METH_VARARGS,
"Return process real effective and saved group ids as a Python tuple"},
{"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
"Return tuple of user/kern time for the given PID"},
{"get_process_create_time", get_process_create_time, METH_VARARGS,
"Return a float indicating the process create time expressed in "
"seconds since the epoch"},
{"get_process_memory_info", get_process_memory_info, METH_VARARGS,
"Return extended memory info for a process as a Python tuple."},
{"get_process_num_threads", get_process_num_threads, METH_VARARGS,
"Return number of threads used by process"},
{"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS,
"Return the number of context switches performed by process"},
{"get_process_threads", get_process_threads, METH_VARARGS,
"Return process threads"},
{"get_process_status", get_process_status, METH_VARARGS,
"Return process status as an integer"},
{"get_process_io_counters", get_process_io_counters, METH_VARARGS,
"Return process IO counters"},
{"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
"Return process tty (terminal) number"},
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
{"get_process_open_files", get_process_open_files, METH_VARARGS,
"Return files opened by process as a list of (path, fd) tuples"},
{"get_process_cwd", get_process_cwd, METH_VARARGS,
"Return process current working directory."},
{"get_process_memory_maps", get_process_memory_maps, METH_VARARGS,
"Return a list of tuples for every process's memory map"},
{"get_process_num_fds", get_process_num_fds, METH_VARARGS,
"Return the number of file descriptors opened by this process"},
#endif
// --- system-related functions
{"get_pid_list", get_pid_list, METH_VARARGS,
"Returns a list of PIDs currently running on the system"},
{"get_num_cpus", get_num_cpus, METH_VARARGS,
"Return number of CPUs on the system"},
{"get_virtual_mem", get_virtual_mem, METH_VARARGS,
"Return system virtual memory usage statistics"},
{"get_swap_mem", get_swap_mem, METH_VARARGS,
"Return swap mem stats"},
{"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
"Return system cpu times as a tuple (user, system, nice, idle, irc)"},
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
{"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
"Return system per-cpu times as a list of tuples"},
#endif
{"get_system_boot_time", get_system_boot_time, METH_VARARGS,
"Return a float indicating the system boot time expressed in "
"seconds since the epoch"},
{"get_disk_partitions", get_disk_partitions, METH_VARARGS,
"Return a list of tuples including device, mount point and "
"fs type for all partitions mounted on the system."},
{"get_network_io_counters", get_network_io_counters, METH_VARARGS,
"Return dict of tuples of networks I/O information."},
{"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
"Return a Python dict of tuples for disk I/O information"},
{"get_system_users", get_system_users, METH_VARARGS,
"Return currently connected users as a list of tuples"},
{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)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_bsd_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef
moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_bsd",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_bsd_traverse,
psutil_bsd_clear,
NULL
};
#define INITERROR return NULL
PyObject *
PyInit__psutil_bsd(void)
#else
#define INITERROR return
void init_psutil_bsd(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
#endif
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
PyModule_AddIntConstant(module, "SLOCK", SLOCK);
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
if (module == NULL) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
/*
* $Id: _psutil_bsd.h 1498 2012-07-24 21:41:28Z g.rodola $
*
* 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.
*
* BSD platform-specific module methods for _psutil_bsd
*/
#include <Python.h>
// --- per-process functions
static PyObject* get_process_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_process_name(PyObject* self, PyObject* args);
static PyObject* get_process_exe(PyObject* self, PyObject* args);
static PyObject* get_process_cmdline(PyObject* self, PyObject* args);
static PyObject* get_process_ppid(PyObject* self, PyObject* args);
static PyObject* get_process_uids(PyObject* self, PyObject* args);
static PyObject* get_process_gids(PyObject* self, PyObject* args);
static PyObject* get_process_connections(PyObject* self, PyObject* args);
static PyObject* get_process_create_time(PyObject* self, PyObject* args);
static PyObject* get_process_memory_info(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
static PyObject* get_process_num_fds(PyObject* self, PyObject* args);
static PyObject* get_process_threads(PyObject* self, PyObject* args);
static PyObject* get_process_status(PyObject* self, PyObject* args);
static PyObject* get_process_io_counters(PyObject* self, PyObject* args);
static PyObject* get_process_tty_nr(PyObject* self, PyObject* args);
static PyObject* get_process_memory_maps(PyObject* self, PyObject* args);
static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args);
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
static PyObject* get_process_open_files(PyObject* self, PyObject* args);
static PyObject* get_process_cwd(PyObject* self, PyObject* args);
#endif
// --- system-related functions
static PyObject* get_pid_list(PyObject* self, PyObject* args);
static PyObject* get_num_cpus(PyObject* self, PyObject* args);
static PyObject* get_virtual_mem(PyObject* self, PyObject* args);
static PyObject* get_swap_mem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args);
#endif
static PyObject* get_system_boot_time(PyObject* self, PyObject* args);
static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
static PyObject* get_network_io_counters(PyObject* self, PyObject* args);
static PyObject* get_disk_io_counters(PyObject* self, PyObject* args);
static PyObject* get_system_users(PyObject* self, PyObject* args);
/*
* $Id: _psutil_common.c 1142 2011-10-05 18:45:49Z g.rodola $
*
* 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.
*
* Routines common to all platforms.
*/
#include <Python.h>
/*
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
*/
PyObject *
NoSuchProcess(void) {
PyObject *exc;
char *msg = strerror(ESRCH);
exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
PyErr_SetObject(PyExc_OSError, exc);
Py_XDECREF(exc);
return NULL;
}
/*
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
*/
PyObject *
AccessDenied(void) {
PyObject *exc;
char *msg = strerror(EACCES);
exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
PyErr_SetObject(PyExc_OSError, exc);
Py_XDECREF(exc);
return NULL;
}
/*
* $Id: _psutil_common.h 1142 2011-10-05 18:45:49Z g.rodola $
*
* 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.
*/
#include <Python.h>
PyObject* NoSuchProcess(void);
PyObject* AccessDenied(void);
/*
* $Id: _psutil_linux.c 1498 2012-07-24 21:41:28Z g.rodola $
*
* 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.
*
* Linux-specific functions.
*/
#include <Python.h>
#include <errno.h>
#include <stdlib.h>
#include <mntent.h>
#include <utmp.h>
#include <sched.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <linux/unistd.h>
#include "_psutil_linux.h"
#define HAS_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set)
#if HAS_IOPRIO
enum {
IOPRIO_WHO_PROCESS = 1,
};
static inline int
ioprio_get(int which, int who)
{
return syscall(__NR_ioprio_get, which, who);
}
static inline int
ioprio_set(int which, int who, int ioprio)
{
return syscall(__NR_ioprio_set, which, who, ioprio);
}
#define IOPRIO_CLASS_SHIFT 13
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
/*
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
*/
static PyObject*
linux_ioprio_get(PyObject* self, PyObject* args)
{
long pid;
int ioprio, ioclass, iodata;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
if (ioprio == -1) {
return PyErr_SetFromErrno(PyExc_OSError);
}
ioclass = IOPRIO_PRIO_CLASS(ioprio);
iodata = IOPRIO_PRIO_DATA(ioprio);
return Py_BuildValue("ii", ioclass, iodata);
}
/*
* A wrapper around ioprio_set(); sets process I/O priority.
* ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
*/
static PyObject*
linux_ioprio_set(PyObject* self, PyObject* args)
{
long pid;
int ioprio, ioclass, iodata;
int retval;
if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) {
return NULL;
}
ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
if (retval == -1) {
return PyErr_SetFromErrno(PyExc_OSError);
}
Py_INCREF(Py_None);
return Py_None;
}
#endif
/*
* Return disk mounted partitions as a list of tuples including device,
* mount point and filesystem type
*/
static PyObject*
get_disk_partitions(PyObject* self, PyObject* args)
{
FILE *file = NULL;
struct mntent *entry;
PyObject* py_retlist = PyList_New(0);
PyObject* py_tuple = NULL;
// MOUNTED constant comes from mntent.h and it's == '/etc/mtab'
Py_BEGIN_ALLOW_THREADS
file = setmntent(MOUNTED, "r");
Py_END_ALLOW_THREADS
if ((file == 0) || (file == NULL)) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
while ((entry = getmntent(file))) {
if (entry == NULL) {
PyErr_Format(PyExc_RuntimeError, "getmntent() failed");
goto error;
}
py_tuple = Py_BuildValue("(ssss)", entry->mnt_fsname, // device
entry->mnt_dir, // mount point
entry->mnt_type, // fs type
entry->mnt_opts); // options
if (! py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
endmntent(file);
return py_retlist;
error:
if (file != NULL)
endmntent(file);
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
return NULL;
}
/*
* A wrapper around sysinfo(), return system memory usage statistics.
*/
static PyObject*
get_sysinfo(PyObject* self, PyObject* args)
{
struct sysinfo info;
if (sysinfo(&info) != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return Py_BuildValue("(KKKKKK)",
(unsigned long long)info.totalram * info.mem_unit, // total
(unsigned long long)info.freeram * info.mem_unit, // free
(unsigned long long)info.bufferram * info.mem_unit, // buffer
(unsigned long long)info.sharedram * info.mem_unit, // shared
(unsigned long long)info.totalswap * info.mem_unit, // swap tot
(unsigned long long)info.freeswap * info.mem_unit); // swap free
// TODO: we can also determine BOOT_TIME here
}
/*
* Return process CPU affinity as a Python long (the bitmask)
*/
static PyObject*
get_process_cpu_affinity(PyObject* self, PyObject* args)
{
unsigned long mask;
unsigned int len = sizeof(mask);
long pid;
if (!PyArg_ParseTuple(args, "i", &pid)) {
return NULL;
}
if (sched_getaffinity(pid, len, (cpu_set_t *)&mask) < 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return Py_BuildValue("l", mask);
}
/*
* Set process CPU affinity; expects a bitmask
*/
static PyObject*
set_process_cpu_affinity(PyObject* self, PyObject* args)
{
unsigned long mask;
unsigned int len = sizeof(mask);
long pid;
if (!PyArg_ParseTuple(args, "ll", &pid, &mask)) {
return NULL;
}
if (sched_setaffinity(pid, len, (cpu_set_t *)&mask)) {
return PyErr_SetFromErrno(PyExc_OSError);
}
Py_INCREF(Py_None);
return Py_None;
}
/*
* Return currently connected users as a list of tuples.
*/
static PyObject*
get_system_users(PyObject* self, PyObject* args)
{
PyObject *ret_list = PyList_New(0);
PyObject *tuple = NULL;
PyObject *user_proc = NULL;
struct utmp *ut;
setutent();
while (NULL != (ut = getutent())) {
tuple = NULL;
user_proc = NULL;
if (ut->ut_type == USER_PROCESS)
user_proc = Py_True;
else
user_proc = Py_False;
tuple = Py_BuildValue("(sssfO)",
ut->ut_user, // username
ut->ut_line, // tty
ut->ut_host, // hostname
(float)ut->ut_tv.tv_sec, // tstamp
user_proc // (bool) user process
);
if (! tuple)
goto error;
if (PyList_Append(ret_list, tuple))
goto error;
Py_DECREF(tuple);
}
endutent();
return ret_list;
error:
Py_XDECREF(tuple);
Py_XDECREF(user_proc);
Py_DECREF(ret_list);
endutent();
return NULL;
}
/*
* Define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] =
{
#if HAS_IOPRIO
{"ioprio_get", linux_ioprio_get, METH_VARARGS,
"Get process I/O priority"},
{"ioprio_set", linux_ioprio_set, METH_VARARGS,
"Set process I/O priority"},
#endif
{"get_disk_partitions", get_disk_partitions, METH_VARARGS,
"Return disk mounted partitions as a list of tuples including "
"device, mount point and filesystem type"},
{"get_sysinfo", get_sysinfo, METH_VARARGS,
"A wrapper around sysinfo(), return system memory usage statistics"},
{"get_process_cpu_affinity", get_process_cpu_affinity, METH_VARARGS,
"Return process CPU affinity as a Python long (the bitmask)."},
{"set_process_cpu_affinity", set_process_cpu_affinity, METH_VARARGS,
"Set process CPU affinity; expects a bitmask."},
{"get_system_users", get_system_users, METH_VARARGS,
"Return currently connected users as a list of tuples"},
{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)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_linux_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef
moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_linux",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_linux_traverse,
psutil_linux_clear,
NULL
};
#define INITERROR return NULL
PyObject *
PyInit__psutil_linux(void)
#else
#define INITERROR return
void init_psutil_linux(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
#endif
if (module == NULL) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
/*
* $Id: _psutil_linux.h 1498 2012-07-24 21:41:28Z g.rodola $
*
* 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.
*
* LINUX specific module methods for _psutil_linux
*/
#include <Python.h>
static PyObject* linux_ioprio_get(PyObject* self, PyObject* args);
static PyObject* linux_ioprio_set(PyObject* self, PyObject* args);
static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
static PyObject* get_sysinfo(PyObject* self, PyObject* args);
static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args);
static PyObject* set_process_cpu_affinity(PyObject* self, PyObject* args);
static PyObject* get_system_users(PyObject* self, PyObject* args);
/*
* $Id: _psutil_mswindows.c 1525 2012-08-16 16:32:03Z g.rodola $
*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Windows platform-specific module methods for _psutil_mswindows
*/
// Fixes clash between winsock2.h and windows.h
#define WIN32_LEAN_AND_MEAN
#include <Python.h>
#include <windows.h>
#include <Psapi.h>
#include <time.h>
#include <lm.h>
#include <WinIoCtl.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <wtsapi32.h>
// Link with Iphlpapi.lib
#pragma comment(lib, "IPHLPAPI.lib")
#include "_psutil_mswindows.h"
#include "_psutil_common.h"
#include "arch/mswindows/security.h"
#include "arch/mswindows/process_info.h"
#include "arch/mswindows/process_handles.h"
#include "arch/mswindows/ntextapi.h"
/*
* Return a Python float representing the system uptime expressed in seconds
* since the epoch.
*/
static PyObject*
get_system_uptime(PyObject* self, PyObject* args)
{
double uptime;
time_t pt;
FILETIME fileTime;
long long ll;
GetSystemTimeAsFileTime(&fileTime);
/*
HUGE thanks to:
http://johnstewien.spaces.live.com/blog/cns!E6885DB5CEBABBC8!831.entry
This function converts the FILETIME structure to the 32 bit
Unix time structure.
The time_t is a 32-bit value for the number of seconds since
January 1, 1970. A FILETIME is a 64-bit for the number of
100-nanosecond periods since January 1, 1601. Convert by
subtracting the number of 100-nanosecond period betwee 01-01-1970
and 01-01-1601, from time_t the divide by 1e+7 to get to the same
base granularity.
*/
ll = (((LONGLONG)(fileTime.dwHighDateTime)) << 32) + fileTime.dwLowDateTime;
pt = (time_t)((ll - 116444736000000000ull) / 10000000ull);
// XXX - By using GetTickCount() time will wrap around to zero if the
// system is run continuously for 49.7 days.
uptime = GetTickCount() / 1000.00f;
return Py_BuildValue("d", (double)pt - uptime);
}
/*
* Return 1 if PID exists in the current process list, else 0.
*/
static PyObject*
pid_exists(PyObject* self, PyObject* args)
{
long pid;
int status;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
status = pid_is_running(pid);
if (-1 == status) {
return NULL; // exception raised in pid_is_running()
}
return PyBool_FromLong(status);
}
/*
* Return a Python list of all the PIDs running on the system.
*/
static PyObject*
get_pid_list(PyObject* self, PyObject* args)
{
DWORD *proclist = NULL;
DWORD numberOfReturnedPIDs;
DWORD i;
PyObject* pid = NULL;
PyObject* retlist = PyList_New(0);
proclist = get_pids(&numberOfReturnedPIDs);
if (NULL == proclist) {
goto error;
}
for (i = 0; i < numberOfReturnedPIDs; i++) {
pid = Py_BuildValue("I", proclist[i]);
if (!pid)
goto error;
if (PyList_Append(retlist, pid))
goto error;
Py_DECREF(pid);
}
// free C array allocated for PIDs
free(proclist);
return retlist;
error:
Py_XDECREF(pid);
Py_DECREF(retlist);
if (proclist != NULL)
free(proclist);
return NULL;
}
/*
* Kill a process given its PID.
*/
static PyObject*
kill_process(PyObject* self, PyObject* args)
{
HANDLE hProcess;
long pid;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (pid == 0) {
return AccessDenied();
}
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProcess == NULL) {
if (GetLastError() == ERROR_INVALID_PARAMETER) {
// see http://code.google.com/p/psutil/issues/detail?id=24
NoSuchProcess();
}
else {
PyErr_SetFromWindowsErr(0);
}
return NULL;
}
// kill the process
if (! TerminateProcess(hProcess, 0)) {
PyErr_SetFromWindowsErr(0);
CloseHandle(hProcess);
return NULL;
}
CloseHandle(hProcess);
Py_INCREF(Py_None);
return Py_None;
}
/*
* Wait for process to terminate and return its exit code.
*/
static PyObject*
process_wait(PyObject* self, PyObject* args)
{
HANDLE hProcess;
DWORD ExitCode;
DWORD retVal;
long pid;
long timeout;
if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) {
return NULL;
}
if (pid == 0) {
return AccessDenied();
}
hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (hProcess == NULL) {
if (GetLastError() == ERROR_INVALID_PARAMETER) {
// no such process; we do not want to raise NSP but
// return None instead.
Py_INCREF(Py_None);
return Py_None;
}
else {
PyErr_SetFromWindowsErr(0);
return NULL;
}
}
// wait until the process has terminated
Py_BEGIN_ALLOW_THREADS
retVal = WaitForSingleObject(hProcess, timeout);
Py_END_ALLOW_THREADS
if (retVal == WAIT_FAILED) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(GetLastError());
}
if (retVal == WAIT_TIMEOUT) {
CloseHandle(hProcess);
return Py_BuildValue("l", WAIT_TIMEOUT);
}
// get the exit code; note: subprocess module (erroneously?) uses
// what returned by WaitForSingleObject
if (GetExitCodeProcess(hProcess, &ExitCode) == 0) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(GetLastError());
}
CloseHandle(hProcess);
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong((long) ExitCode);
#else
return PyInt_FromLong((long) ExitCode);
#endif
}
/*
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject*
get_process_cpu_times(PyObject* self, PyObject* args)
{
long pid;
HANDLE hProcess;
FILETIME ftCreate, ftExit, ftKernel, ftUser;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (hProcess == NULL) {
return NULL;
}
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
// usually means the process has died so we throw a NoSuchProcess
// here
return NoSuchProcess();
}
else {
PyErr_SetFromWindowsErr(0);
return NULL;
}
}
CloseHandle(hProcess);
/*
user and kernel times are represented as a FILETIME structure wich contains
a 64-bit value representing the number of 100-nanosecond intervals since
January 1, 1601 (UTC).
http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
To convert it into a float representing the seconds that the process has
executed in user/kernel mode I borrowed the code below from Python's
Modules/posixmodule.c
*/
return Py_BuildValue(
"(dd)",
(double)(ftUser.dwHighDateTime*429.4967296 + \
ftUser.dwLowDateTime*1e-7),
(double)(ftKernel.dwHighDateTime*429.4967296 + \
ftKernel.dwLowDateTime*1e-7)
);
}
/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject*
get_process_cpu_times_2(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
double user, kernel;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
user = (double)process->UserTime.HighPart * 429.4967296 + \
(double)process->UserTime.LowPart * 1e-7;
kernel = (double)process->KernelTime.HighPart * 429.4967296 + \
(double)process->KernelTime.LowPart * 1e-7;
free(buffer);
return Py_BuildValue("(dd)", user, kernel);
}
/*
* Return a Python float indicating the process create time expressed in
* seconds since the epoch.
*/
static PyObject*
get_process_create_time(PyObject* self, PyObject* args)
{
long pid;
long long unix_time;
DWORD exitCode;
HANDLE hProcess;
BOOL ret;
FILETIME ftCreate, ftExit, ftKernel, ftUser;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
// special case for PIDs 0 and 4, return BOOT_TIME
if (0 == pid || 4 == pid) {
return get_system_uptime(NULL, NULL);
}
hProcess = handle_from_pid(pid);
if (hProcess == NULL) {
return NULL;
}
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
// usually means the process has died so we throw a NoSuchProcess here
return NoSuchProcess();
}
else {
PyErr_SetFromWindowsErr(0);
return NULL;
}
}
// Make sure the process is not gone as OpenProcess alone seems to be
// unreliable in doing so (it seems a previous call to p.wait() makes
// it unreliable).
// This check is important as creation time is used to make sure the
// process is still running.
ret = GetExitCodeProcess(hProcess, &exitCode);
CloseHandle(hProcess);
if (ret != 0) {
if (exitCode != STILL_ACTIVE) {
return NoSuchProcess();
}
}
else {
// Ignore access denied as it means the process is still alive.
// For all other errors, we want an exception.
if (GetLastError() != ERROR_ACCESS_DENIED) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
}
/*
Convert the FILETIME structure to a Unix time.
It's the best I could find by googling and borrowing code here and there.
The time returned has a precision of 1 second.
*/
unix_time = ((LONGLONG)ftCreate.dwHighDateTime) << 32;
unix_time += ftCreate.dwLowDateTime - 116444736000000000LL;
unix_time /= 10000000;
return Py_BuildValue("d", (double)unix_time);
}
/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject*
get_process_create_time_2(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
long long unix_time;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
// special case for PIDs 0 and 4, return BOOT_TIME
if (0 == pid || 4 == pid) {
return get_system_uptime(NULL, NULL);
}
/*
Convert the LARGE_INTEGER union to a Unix time.
It's the best I could find by googling and borrowing code here and there.
The time returned has a precision of 1 second.
*/
unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32;
unix_time += process->CreateTime.LowPart - 116444736000000000LL;
unix_time /= 10000000;
free(buffer);
return Py_BuildValue("d", (double)unix_time);
}
/*
* Return a Python integer indicating the number of CPUs on the system.
*/
static PyObject*
get_num_cpus(PyObject* self, PyObject* args)
{
SYSTEM_INFO system_info;
system_info.dwNumberOfProcessors = 0;
GetSystemInfo(&system_info);
if (system_info.dwNumberOfProcessors == 0){
// GetSystemInfo failed for some reason; return 1 as default
return Py_BuildValue("I", 1);
}
return Py_BuildValue("I", system_info.dwNumberOfProcessors);
}
/*
* Return process name as a Python string.
*/
static PyObject*
get_process_name(PyObject* self, PyObject* args) {
long pid;
int pid_return;
PyObject* name;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (pid == 0) {
return Py_BuildValue("s", "System Idle Process");
}
else if (pid == 4) {
return Py_BuildValue("s", "System");
}
pid_return = pid_is_running(pid);
if (pid_return == 0) {
return NoSuchProcess();
}
if (pid_return == -1) {
return NULL;
}
name = get_name(pid);
if (name == NULL) {
return NULL; // exception set in get_name()
}
return name;
}
/*
* Return process parent pid as a Python integer.
*/
static PyObject*
get_process_ppid(PyObject* self, PyObject* args) {
long pid;
int pid_return;
PyObject* ppid;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if ((pid == 0) || (pid == 4)) {
return Py_BuildValue("l", 0);
}
pid_return = pid_is_running(pid);
if (pid_return == 0) {
return NoSuchProcess();
}
if (pid_return == -1) {
return NULL;
}
ppid = get_ppid(pid);
if (ppid == NULL) {
return NULL; // exception set in get_ppid()
}
return ppid;
}
/*
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject*
get_process_cmdline(PyObject* self, PyObject* args) {
long pid;
int pid_return;
PyObject* arglist;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if ((pid == 0) || (pid == 4)) {
return Py_BuildValue("[]");
}
pid_return = pid_is_running(pid);
if (pid_return == 0) {
return NoSuchProcess();
}
if (pid_return == -1) {
return NULL;
}
// XXX the assumptio below probably needs to go away
// May fail any of several ReadProcessMemory calls etc. and not indicate
// a real problem so we ignore any errors and just live without commandline
arglist = get_arg_list(pid);
if ( NULL == arglist ) {
// carry on anyway, clear any exceptions too
PyErr_Clear();
return Py_BuildValue("[]");
}
return arglist;
}
/*
* Return process executable path.
*/
static PyObject*
get_process_exe(PyObject* self, PyObject* args) {
long pid;
HANDLE hProcess;
wchar_t exe[MAX_PATH];
DWORD nSize = MAX_PATH;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION);
if (NULL == hProcess) {
return NULL;
}
if (GetProcessImageFileName(hProcess, &exe, nSize) == 0) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(hProcess);
return Py_BuildValue("s", exe);
}
/*
* Return process memory information as a Python tuple.
*/
static PyObject*
get_process_memory_info(PyObject* self, PyObject* args)
{
HANDLE hProcess;
DWORD pid;
#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2
PROCESS_MEMORY_COUNTERS_EX cnt;
#else
PROCESS_MEMORY_COUNTERS cnt;
#endif
SIZE_T private = 0;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
return NULL;
}
if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
#if (_WIN32_WINNT >= 0x0501)
private = cnt.PrivateUsage;
#endif
CloseHandle(hProcess);
// py 2.4
#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION <= 4)
return Py_BuildValue("(kIIIIIIIII)",
cnt.PageFaultCount,
(unsigned int)cnt.PeakWorkingSetSize,
(unsigned int)cnt.WorkingSetSize,
(unsigned int)cnt.QuotaPeakPagedPoolUsage,
(unsigned int)cnt.QuotaPagedPoolUsage,
(unsigned int)cnt.QuotaPeakNonPagedPoolUsage,
(unsigned int)cnt.QuotaNonPagedPoolUsage,
(unsigned int)cnt.PagefileUsage,
(unsigned int)cnt.PeakPagefileUsage,
(unsigned int)private);
#else
// py >= 2.5
return Py_BuildValue("(knnnnnnnnn)",
cnt.PageFaultCount,
cnt.PeakWorkingSetSize,
cnt.WorkingSetSize,
cnt.QuotaPeakPagedPoolUsage,
cnt.QuotaPagedPoolUsage,
cnt.QuotaPeakNonPagedPoolUsage,
cnt.QuotaNonPagedPoolUsage,
cnt.PagefileUsage,
cnt.PeakPagefileUsage,
private);
#endif
}
/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject*
get_process_memory_info_2(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
ULONG m0;
SIZE_T m1, m2, m3, m4, m5, m6, m7, m8, m9;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
m0 = process->PageFaultCount;
m1 = process->PeakWorkingSetSize;
m2 = process->WorkingSetSize;
m3 = process->QuotaPeakPagedPoolUsage;
m4 = process->QuotaPagedPoolUsage;
m5 = process->QuotaPeakNonPagedPoolUsage;
m6 = process->QuotaNonPagedPoolUsage;
m7 = process->PagefileUsage;
m8 = process->PeakPagefileUsage;
#if (_WIN32_WINNT >= 0x0501)
m9 = process->PrivatePageCount; // private me
#else
m9 = 0;
#endif
free(buffer);
// py 2.4
#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION <= 4)
return Py_BuildValue("(kIIIIIIIII)",
(unsigned int)m0, (unsigned int)m1, (unsigned int)m2, (unsigned int)m3,
(unsigned int)m4, (unsigned int)m5, (unsigned int)m6, (unsigned int)m7,
(unsigned int)m8, (unsigned int)m9);
#else
return Py_BuildValue("(knnnnnnnnn)",
m0, m1, m2, m3, m4, m5, m6, m7, m8, m9);
#endif
}
/*
* Return a Python integer indicating the total amount of physical memory
* in bytes.
*/
static PyObject*
get_virtual_mem(PyObject* self, PyObject* args)
{
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
if (! GlobalMemoryStatusEx(&memInfo) ) {
return PyErr_SetFromWindowsErr(0);
}
return Py_BuildValue("(LLLLLL)",
memInfo.ullTotalPhys, // total
memInfo.ullAvailPhys, // avail
memInfo.ullTotalPageFile, // total page file
memInfo.ullAvailPageFile, // avail page file
memInfo.ullTotalVirtual, // total virtual
memInfo.ullAvailVirtual // avail virtual
);
}
#define LO_T ((float)1e-7)
#define HI_T (LO_T*4294967296.0)
/*
* Return a Python list of tuples representing user, kernel and idle
* CPU times for every CPU on the system.
*/
static PyObject*
get_system_cpu_times(PyObject* self, PyObject* args)
{
float idle, kernel, user;
typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG);
NTQSI_PROC NtQuerySystemInformation;
HINSTANCE hNtDll;
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
SYSTEM_INFO si;
UINT i;
PyObject *arg = NULL;
PyObject *retlist = PyList_New(0);
// dynamic linking is mandatory to use NtQuerySystemInformation
hNtDll = LoadLibrary(TEXT("ntdll.dll"));
if (hNtDll != NULL) {
// gets NtQuerySystemInformation address
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
hNtDll, "NtQuerySystemInformation");
if (NtQuerySystemInformation != NULL)
{
// retrives number of processors
GetSystemInfo(&si);
// allocates an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
// structures, one per processor
sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
malloc(si.dwNumberOfProcessors * \
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
if (sppi != NULL)
{
// gets cpu time informations
if (0 == NtQuerySystemInformation(
SystemProcessorPerformanceInformation,
sppi,
si.dwNumberOfProcessors * sizeof
(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
NULL)
)
{
// computes system global times summing each processor value
idle = user = kernel = 0;
for (i=0; i<si.dwNumberOfProcessors; i++) {
arg = NULL;
user = (float)((HI_T * sppi[i].UserTime.HighPart) + \
(LO_T * sppi[i].UserTime.LowPart));
idle = (float)((HI_T * sppi[i].IdleTime.HighPart) + \
(LO_T * sppi[i].IdleTime.LowPart));
kernel = (float)((HI_T * sppi[i].KernelTime.HighPart) + \
(LO_T * sppi[i].KernelTime.LowPart));
// kernel time includes idle time on windows
// we return only busy kernel time subtracting
// idle time from kernel time
arg = Py_BuildValue("(ddd)", user,
kernel - idle,
idle);
if (!arg)
goto error;
if (PyList_Append(retlist, arg))
goto error;
Py_DECREF(arg);
}
free(sppi);
FreeLibrary(hNtDll);
return retlist;
} // END NtQuerySystemInformation
} // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
} // END GetProcAddress
} // END LoadLibrary
goto error;
error:
Py_XDECREF(arg);
Py_DECREF(retlist);
if (sppi) {
free(sppi);
}
if (hNtDll) {
FreeLibrary(hNtDll);
}
PyErr_SetFromWindowsErr(0);
return NULL;
}
/*
* Return process current working directory as a Python string.
*/
static PyObject*
get_process_cwd(PyObject* self, PyObject* args)
{
long pid;
HANDLE processHandle = NULL;
PVOID pebAddress;
PVOID rtlUserProcParamsAddress;
UNICODE_STRING currentDirectory;
WCHAR *currentDirectoryContent = NULL;
PyObject *returnPyObj = NULL;
PyObject *cwd_from_wchar = NULL;
PyObject *cwd = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
processHandle = handle_from_pid(pid);
if (processHandle == NULL) {
return NULL;
}
pebAddress = GetPebAddress(processHandle);
// get the address of ProcessParameters
#ifdef _WIN64
if (!ReadProcessMemory(processHandle, (PCHAR)pebAddress + 32,
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
#else
if (!ReadProcessMemory(processHandle, (PCHAR)pebAddress + 0x10,
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
#endif
{
CloseHandle(processHandle);
if (GetLastError() == ERROR_PARTIAL_COPY) {
// this occurs quite often with system processes
return AccessDenied();
}
else {
return PyErr_SetFromWindowsErr(0);
}
}
// Read the currentDirectory UNICODE_STRING structure.
// 0x24 refers to "CurrentDirectoryPath" of RTL_USER_PROCESS_PARAMETERS
// structure, see:
// http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
#ifdef _WIN64
if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 56,
&currentDirectory, sizeof(currentDirectory), NULL))
#else
if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 0x24,
&currentDirectory, sizeof(currentDirectory), NULL))
#endif
{
CloseHandle(processHandle);
if (GetLastError() == ERROR_PARTIAL_COPY) {
// this occurs quite often with system processes
return AccessDenied();
}
else {
return PyErr_SetFromWindowsErr(0);
}
}
// allocate memory to hold cwd
currentDirectoryContent = (WCHAR *)malloc(currentDirectory.Length+1);
// read cwd
if (!ReadProcessMemory(processHandle, currentDirectory.Buffer,
currentDirectoryContent, currentDirectory.Length, NULL))
{
if (GetLastError() == ERROR_PARTIAL_COPY) {
// this occurs quite often with system processes
AccessDenied();
}
else {
PyErr_SetFromWindowsErr(0);
}
goto error;
}
// null-terminate the string to prevent wcslen from returning
// incorrect length the length specifier is in characters, but
// currentDirectory.Length is in bytes
currentDirectoryContent[(currentDirectory.Length/sizeof(WCHAR))] = '\0';
// convert wchar array to a Python unicode string, and then to UTF8
cwd_from_wchar = PyUnicode_FromWideChar(currentDirectoryContent,
wcslen(currentDirectoryContent));
if (cwd_from_wchar == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
cwd = PyUnicode_FromObject(cwd_from_wchar);
#else
cwd = PyUnicode_AsUTF8String(cwd_from_wchar);
#endif
if (cwd == NULL)
goto error;
// decrement the reference count on our temp unicode str to avoid
// mem leak
returnPyObj = Py_BuildValue("N", cwd);
if (!returnPyObj)
goto error;
Py_DECREF(cwd_from_wchar);
CloseHandle(processHandle);
free(currentDirectoryContent);
return returnPyObj;
error:
Py_XDECREF(cwd_from_wchar);
Py_XDECREF(cwd);
Py_XDECREF(returnPyObj);
if (currentDirectoryContent != NULL)
free(currentDirectoryContent);
if (processHandle != NULL)
CloseHandle(processHandle);
return NULL;
}
/*
* Resume or suspends a process
*/
int
suspend_resume_process(DWORD pid, int suspend)
{
// a huge thanks to http://www.codeproject.com/KB/threads/pausep.aspx
HANDLE hThreadSnap = NULL;
THREADENTRY32 te32 = {0};
if (pid == 0) {
AccessDenied();
return FALSE;
}
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
return FALSE;
}
// Fill in the size of the structure before using it
te32.dwSize = sizeof(THREADENTRY32);
if (! Thread32First(hThreadSnap, &te32)) {
PyErr_SetFromWindowsErr(0);
CloseHandle(hThreadSnap);
return FALSE;
}
// Walk the thread snapshot to find all threads of the process.
// If the thread belongs to the process, add its information
// to the display list.
do
{
if (te32.th32OwnerProcessID == pid)
{
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE,
te32.th32ThreadID);
if (hThread == NULL) {
PyErr_SetFromWindowsErr(0);
CloseHandle(hThread);
CloseHandle(hThreadSnap);
return FALSE;
}
if (suspend == 1)
{
if (SuspendThread(hThread) == (DWORD)-1) {
PyErr_SetFromWindowsErr(0);
CloseHandle(hThread);
CloseHandle(hThreadSnap);
return FALSE;
}
}
else
{
if (ResumeThread(hThread) == (DWORD)-1) {
PyErr_SetFromWindowsErr(0);
CloseHandle(hThread);
CloseHandle(hThreadSnap);
return FALSE;
}
}
CloseHandle(hThread);
}
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
return TRUE;
}
static PyObject*
suspend_process(PyObject* self, PyObject* args)
{
long pid;
int suspend = 1;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! suspend_resume_process(pid, suspend)) {
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
resume_process(PyObject* self, PyObject* args)
{
long pid;
int suspend = 0;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! suspend_resume_process(pid, suspend)) {
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
get_process_num_threads(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
int num;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
num = (int)process->NumberOfThreads;
free(buffer);
return Py_BuildValue("i", num);
}
static PyObject*
get_process_threads(PyObject* self, PyObject* args)
{
PyObject* retList = PyList_New(0);
PyObject* pyTuple = NULL;
HANDLE hThreadSnap = NULL;
HANDLE hThread;
THREADENTRY32 te32 = {0};
long pid;
int pid_return;
int rc;
FILETIME ftDummy, ftKernel, ftUser;
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 = pid_is_running(pid);
if (pid_return == 0) {
NoSuchProcess();
goto error;
}
if (pid_return == -1) {
goto error;
}
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// Fill in the size of the structure before using it
te32.dwSize = sizeof(THREADENTRY32);
if (! Thread32First(hThreadSnap, &te32)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// Walk the thread snapshot to find all threads of the process.
// If the thread belongs to the process, increase the counter.
do
{
if (te32.th32OwnerProcessID == pid)
{
pyTuple = NULL;
hThread = NULL;
hThread = OpenThread(THREAD_QUERY_INFORMATION,
FALSE, te32.th32ThreadID);
if (hThread == NULL) {
// thread has disappeared on us
continue;
}
rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser);
if (rc == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
/*
user and kernel times are represented as a FILETIME structure
wich contains a 64-bit value representing the number of
100-nanosecond intervals since January 1, 1601 (UTC).
http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
To convert it into a float representing the seconds that the
process has executed in user/kernel mode I borrowed the code
below from Python's Modules/posixmodule.c
*/
pyTuple = Py_BuildValue("kdd",
te32.th32ThreadID,
(double)(ftUser.dwHighDateTime*429.4967296 + \
ftUser.dwLowDateTime*1e-7),
(double)(ftKernel.dwHighDateTime*429.4967296 + \
ftKernel.dwLowDateTime*1e-7));
if (!pyTuple)
goto error;
if (PyList_Append(retList, pyTuple))
goto error;
Py_DECREF(pyTuple);
CloseHandle(hThread);
}
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
return retList;
error:
Py_XDECREF(pyTuple);
Py_DECREF(retList);
if (hThread != NULL)
CloseHandle(hThread);
if (hThreadSnap != NULL) {
CloseHandle(hThreadSnap);
}
return NULL;
}
static PyObject*
get_process_open_files(PyObject* self, PyObject* args)
{
long pid;
HANDLE processHandle;
DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
PyObject* filesList;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
processHandle = handle_from_pid_waccess(pid, access);
if (processHandle == NULL) {
return NULL;
}
filesList = get_open_files(pid, processHandle);
CloseHandle(processHandle);
if (filesList == NULL) {
return PyErr_SetFromWindowsErr(0);
}
return filesList;
}
/*
Accept a filename's drive in native format like "\Device\HarddiskVolume1\"
and return the corresponding drive letter (e.g. "C:\\").
If no match is found return an empty string.
*/
static PyObject*
win32_QueryDosDevice(PyObject* self, PyObject* args)
{
LPCTSTR lpDevicePath;
TCHAR d = TEXT('A');
TCHAR szBuff[5];
if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) {
return NULL;
}
while(d <= TEXT('Z'))
{
TCHAR szDeviceName[3] = {d,TEXT(':'),TEXT('\0')};
TCHAR szTarget[512] = {0};
if (QueryDosDevice(szDeviceName, szTarget, 511) != 0){
//_tprintf (TEXT("%c:\\ => %s\n"), d, szTarget);
if(_tcscmp(lpDevicePath, szTarget) == 0) {
_stprintf(szBuff, TEXT("%c:"), d);
return Py_BuildValue("s", szBuff);
}
}
d++;
}
return Py_BuildValue("s", "");
}
/*
* Return process username as a "DOMAIN//USERNAME" string.
*/
static PyObject*
get_process_username(PyObject* self, PyObject* args)
{
long pid;
HANDLE processHandle;
HANDLE tokenHandle;
PTOKEN_USER user;
ULONG bufferSize;
PTSTR name;
ULONG nameSize;
PTSTR domainName;
ULONG domainNameSize;
SID_NAME_USE nameUse;
PTSTR fullName;
PyObject* returnObject;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
processHandle = handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION);
if (processHandle == NULL) {
return NULL;
}
if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) {
CloseHandle(processHandle);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(processHandle);
/* Get the user SID. */
bufferSize = 0x100;
user = malloc(bufferSize);
if (!GetTokenInformation(tokenHandle,
TokenUser,
user,
bufferSize,
&bufferSize))
{
free(user);
user = malloc(bufferSize);
if (!GetTokenInformation(tokenHandle,
TokenUser,
user,
bufferSize,
&bufferSize))
{
free(user);
CloseHandle(tokenHandle);
return PyErr_SetFromWindowsErr(0);
}
}
CloseHandle(tokenHandle);
/* Resolve the SID to a name. */
nameSize = 0x100;
domainNameSize = 0x100;
name = malloc(nameSize * sizeof(TCHAR));
domainName = malloc(domainNameSize * sizeof(TCHAR));
if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName,
&domainNameSize, &nameUse))
{
free(name);
free(domainName);
name = malloc(nameSize * sizeof(TCHAR));
domainName = malloc(domainNameSize * sizeof(TCHAR));
if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName,
&domainNameSize, &nameUse))
{
free(name);
free(domainName);
free(user);
return PyErr_SetFromWindowsErr(0);
}
}
nameSize = _tcslen(name);
domainNameSize = _tcslen(domainName);
/* Build the full username string. */
fullName = malloc((domainNameSize + 1 + nameSize + 1) * sizeof(TCHAR));
memcpy(fullName, domainName, domainNameSize);
fullName[domainNameSize] = '\\';
memcpy(&fullName[domainNameSize + 1], name, nameSize);
fullName[domainNameSize + 1 + nameSize] = '\0';
returnObject = Py_BuildValue("s", fullName);
free(fullName);
free(name);
free(domainName);
free(user);
return returnObject;
}
#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff)
#ifndef AF_INET6
#define AF_INET6 23
#endif
static char *state_to_string(ULONG state)
{
switch (state)
{
case MIB_TCP_STATE_CLOSED:
return "CLOSE";
case MIB_TCP_STATE_LISTEN:
return "LISTEN";
case MIB_TCP_STATE_SYN_SENT:
return "SYN_SENT";
case MIB_TCP_STATE_SYN_RCVD:
return "SYN_RECV";
case MIB_TCP_STATE_ESTAB:
return "ESTABLISHED";
case MIB_TCP_STATE_FIN_WAIT1:
return "FIN_WAIT1";
case MIB_TCP_STATE_FIN_WAIT2:
return "FIN_WAIT2";
case MIB_TCP_STATE_CLOSE_WAIT:
return "CLOSE_WAIT";
case MIB_TCP_STATE_CLOSING:
return "CLOSING";
case MIB_TCP_STATE_LAST_ACK:
return "LAST_ACK";
case MIB_TCP_STATE_TIME_WAIT:
return "TIME_WAIT";
case MIB_TCP_STATE_DELETE_TCB:
return "DELETE_TCB";
default:
return "";
}
}
/* mingw support */
#ifndef _IPRTRMIB_H
typedef struct _MIB_TCP6ROW_OWNER_PID
{
UCHAR ucLocalAddr[16];
DWORD dwLocalScopeId;
DWORD dwLocalPort;
UCHAR ucRemoteAddr[16];
DWORD dwRemoteScopeId;
DWORD dwRemotePort;
DWORD dwState;
DWORD dwOwningPid;
} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID;
typedef struct _MIB_TCP6TABLE_OWNER_PID
{
DWORD dwNumEntries;
MIB_TCP6ROW_OWNER_PID table[ANY_SIZE];
} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID;
#endif
#ifndef __IPHLPAPI_H__
typedef struct in6_addr {
union {
UCHAR Byte[16];
USHORT Word[8];
} u;
} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
typedef enum _UDP_TABLE_CLASS {
UDP_TABLE_BASIC,
UDP_TABLE_OWNER_PID,
UDP_TABLE_OWNER_MODULE
} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
typedef struct _MIB_UDPROW_OWNER_PID {
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwOwningPid;
} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
typedef struct _MIB_UDPTABLE_OWNER_PID
{
DWORD dwNumEntries;
MIB_UDPROW_OWNER_PID table[ANY_SIZE];
} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;
#endif
/* end of mingw support */
typedef struct _MIB_UDP6ROW_OWNER_PID {
UCHAR ucLocalAddr[16];
DWORD dwLocalScopeId;
DWORD dwLocalPort;
DWORD dwOwningPid;
} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID;
typedef struct _MIB_UDP6TABLE_OWNER_PID
{
DWORD dwNumEntries;
MIB_UDP6ROW_OWNER_PID table[ANY_SIZE];
} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
#define ConnDecrefPyObjs() Py_DECREF(_AF_INET); \
Py_DECREF(_AF_INET6);\
Py_DECREF(_SOCK_STREAM);\
Py_DECREF(_SOCK_DGRAM);
/*
* Return a list of network connections opened by a process
*/
static PyObject*
get_process_connections(PyObject* self, PyObject* args)
{
static long null_address[4] = { 0, 0, 0, 0 };
unsigned long pid;
PyObject* connectionsList;
PyObject* connectionTuple = NULL;
PyObject *af_filter = NULL;
PyObject *type_filter = NULL;
PyObject *_AF_INET = PyLong_FromLong((long)AF_INET);
PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6);
PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM);
PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM);
typedef PSTR (NTAPI *_RtlIpv4AddressToStringA)(struct in_addr *,
PSTR /* __out_ecount(16) */);
_RtlIpv4AddressToStringA rtlIpv4AddressToStringA;
typedef PSTR (NTAPI *_RtlIpv6AddressToStringA)(struct in6_addr *,
PSTR /* __out_ecount(65) */);
_RtlIpv6AddressToStringA rtlIpv6AddressToStringA;
typedef DWORD (WINAPI *_GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG,
TCP_TABLE_CLASS, ULONG);
_GetExtendedTcpTable getExtendedTcpTable;
typedef DWORD (WINAPI *_GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG,
UDP_TABLE_CLASS, ULONG);
_GetExtendedUdpTable getExtendedUdpTable;
PVOID table = NULL;
DWORD tableSize;
PMIB_TCPTABLE_OWNER_PID tcp4Table;
PMIB_UDPTABLE_OWNER_PID udp4Table;
PMIB_TCP6TABLE_OWNER_PID tcp6Table;
PMIB_UDP6TABLE_OWNER_PID udp6Table;
ULONG i;
CHAR addressBufferLocal[65];
PyObject* addressTupleLocal = NULL;
CHAR addressBufferRemote[65];
PyObject* addressTupleRemote = NULL;
if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
ConnDecrefPyObjs();
return NULL;
}
if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
ConnDecrefPyObjs();
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
return NULL;
}
if (pid_is_running(pid) == 0) {
ConnDecrefPyObjs();
return NoSuchProcess();
}
/* Import some functions. */
{
HMODULE ntdll;
HMODULE iphlpapi;
ntdll = LoadLibrary(TEXT("ntdll.dll"));
rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress(ntdll,
"RtlIpv4AddressToStringA");
rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress(ntdll,
"RtlIpv6AddressToStringA");
/* TODO: Check these two function pointers */
iphlpapi = LoadLibrary(TEXT("iphlpapi.dll"));
getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi,
"GetExtendedTcpTable");
getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi,
"GetExtendedUdpTable");
FreeLibrary(ntdll);
FreeLibrary(iphlpapi);
}
if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) {
PyErr_SetString(PyExc_NotImplementedError,
"feature not supported on this Windows version");
ConnDecrefPyObjs();
return NULL;
}
connectionsList = PyList_New(0);
/* TCP IPv4 */
if ((PySequence_Contains(af_filter, _AF_INET) == 1) &&
(PySequence_Contains(type_filter, _SOCK_STREAM) == 1))
{
table = NULL;
connectionTuple = NULL;
addressTupleLocal = NULL;
addressTupleRemote = NULL;
tableSize = 0;
getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET,
TCP_TABLE_OWNER_PID_ALL, 0);
table = malloc(tableSize);
if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET,
TCP_TABLE_OWNER_PID_ALL, 0) == 0)
{
tcp4Table = table;
for (i = 0; i < tcp4Table->dwNumEntries; i++)
{
if (tcp4Table->table[i].dwOwningPid != pid) {
continue;
}
if (tcp4Table->table[i].dwLocalAddr != 0 ||
tcp4Table->table[i].dwLocalPort != 0)
{
struct in_addr addr;
addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr;
rtlIpv4AddressToStringA(&addr, addressBufferLocal);
addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal,
BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort));
}
else
{
addressTupleLocal = PyTuple_New(0);
}
if (addressTupleLocal == NULL)
goto error;
// On Windows <= XP, remote addr is filled even if socket
// is in LISTEN mode in which case we just ignore it.
if ((tcp4Table->table[i].dwRemoteAddr != 0 ||
tcp4Table->table[i].dwRemotePort != 0) &&
(tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN))
{
struct in_addr addr;
addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr;
rtlIpv4AddressToStringA(&addr, addressBufferRemote);
addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote,
BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort));
}
else
{
addressTupleRemote = PyTuple_New(0);
}
if (addressTupleRemote == NULL)
goto error;
connectionTuple = Py_BuildValue("(iiiNNs)",
-1,
AF_INET,
SOCK_STREAM,
addressTupleLocal,
addressTupleRemote,
state_to_string(tcp4Table->table[i].dwState)
);
if (!connectionTuple)
goto error;
if (PyList_Append(connectionsList, connectionTuple))
goto error;
Py_DECREF(connectionTuple);
}
}
free(table);
}
/* TCP IPv6 */
if ((PySequence_Contains(af_filter, _AF_INET6) == 1) &&
(PySequence_Contains(type_filter, _SOCK_STREAM) == 1))
{
table = NULL;
connectionTuple = NULL;
addressTupleLocal = NULL;
addressTupleRemote = NULL;
tableSize = 0;
getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6,
TCP_TABLE_OWNER_PID_ALL, 0);
table = malloc(tableSize);
if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET6,
TCP_TABLE_OWNER_PID_ALL, 0) == 0)
{
tcp6Table = table;
for (i = 0; i < tcp6Table->dwNumEntries; i++)
{
if (tcp6Table->table[i].dwOwningPid != pid) {
continue;
}
if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) != 0 ||
tcp6Table->table[i].dwLocalPort != 0)
{
struct in6_addr addr;
memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferLocal);
addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal,
BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort));
}
else
{
addressTupleLocal = PyTuple_New(0);
}
if (addressTupleLocal == NULL)
goto error;
// On Windows <= XP, remote addr is filled even if socket
// is in LISTEN mode in which case we just ignore it.
if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) != 0 ||
tcp6Table->table[i].dwRemotePort != 0) &&
(tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN))
{
struct in6_addr addr;
memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferRemote);
addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote,
BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort));
}
else
{
addressTupleRemote = PyTuple_New(0);
}
if (addressTupleRemote == NULL)
goto error;
connectionTuple = Py_BuildValue("(iiiNNs)",
-1,
AF_INET6,
SOCK_STREAM,
addressTupleLocal,
addressTupleRemote,
state_to_string(tcp6Table->table[i].dwState)
);
if (!connectionTuple)
goto error;
if (PyList_Append(connectionsList, connectionTuple))
goto error;
Py_DECREF(connectionTuple);
}
}
free(table);
}
/* UDP IPv4 */
if ((PySequence_Contains(af_filter, _AF_INET) == 1) &&
(PySequence_Contains(type_filter, _SOCK_DGRAM) == 1))
{
table = NULL;
connectionTuple = NULL;
addressTupleLocal = NULL;
addressTupleRemote = NULL;
tableSize = 0;
getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET,
UDP_TABLE_OWNER_PID, 0);
table = malloc(tableSize);
if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET,
UDP_TABLE_OWNER_PID, 0) == 0)
{
udp4Table = table;
for (i = 0; i < udp4Table->dwNumEntries; i++)
{
if (udp4Table->table[i].dwOwningPid != pid) {
continue;
}
if (udp4Table->table[i].dwLocalAddr != 0 ||
udp4Table->table[i].dwLocalPort != 0)
{
struct in_addr addr;
addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr;
rtlIpv4AddressToStringA(&addr, addressBufferLocal);
addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal,
BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort));
}
else
{
addressTupleLocal = PyTuple_New(0);
}
if (addressTupleLocal == NULL)
goto error;
connectionTuple = Py_BuildValue("(iiiNNs)",
-1,
AF_INET,
SOCK_DGRAM,
addressTupleLocal,
PyTuple_New(0),
""
);
if (!connectionTuple)
goto error;
if (PyList_Append(connectionsList, connectionTuple))
goto error;
Py_DECREF(connectionTuple);
}
}
free(table);
}
/* UDP IPv6 */
if ((PySequence_Contains(af_filter, _AF_INET6) == 1) &&
(PySequence_Contains(type_filter, _SOCK_DGRAM) == 1))
{
table = NULL;
connectionTuple = NULL;
addressTupleLocal = NULL;
addressTupleRemote = NULL;
tableSize = 0;
getExtendedUdpTable(NULL, &tableSize, FALSE,
AF_INET6, UDP_TABLE_OWNER_PID, 0);
table = malloc(tableSize);
if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET6,
UDP_TABLE_OWNER_PID, 0) == 0)
{
udp6Table = table;
for (i = 0; i < udp6Table->dwNumEntries; i++)
{
if (udp6Table->table[i].dwOwningPid != pid) {
continue;
}
if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) != 0 ||
udp6Table->table[i].dwLocalPort != 0)
{
struct in6_addr addr;
memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferLocal);
addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal,
BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort));
}
else
{
addressTupleLocal = PyTuple_New(0);
}
if (addressTupleLocal == NULL)
goto error;
connectionTuple = Py_BuildValue("(iiiNNs)",
-1,
AF_INET6,
SOCK_DGRAM,
addressTupleLocal,
PyTuple_New(0),
""
);
if (!connectionTuple)
goto error;
if (PyList_Append(connectionsList, connectionTuple))
goto error;
Py_DECREF(connectionTuple);
}
}
free(table);
}
ConnDecrefPyObjs();
return connectionsList;
error:
ConnDecrefPyObjs();
Py_XDECREF(connectionTuple);
Py_XDECREF(addressTupleLocal);
Py_XDECREF(addressTupleRemote);
Py_DECREF(connectionsList);
if (table != NULL)
free(table);
return NULL;
}
/*
* Get process priority as a Python integer.
*/
static PyObject*
get_process_priority(PyObject* self, PyObject* args)
{
long pid;
DWORD priority;
HANDLE hProcess;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (hProcess == NULL) {
return NULL;
}
priority = GetPriorityClass(hProcess);
CloseHandle(hProcess);
if (priority == 0) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
return Py_BuildValue("i", priority);
}
/*
* Set process priority.
*/
static PyObject*
set_process_priority(PyObject* self, PyObject* args)
{
long pid;
int priority;
int retval;
HANDLE hProcess;
DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
return NULL;
}
hProcess = handle_from_pid_waccess(pid, dwDesiredAccess);
if (hProcess == NULL) {
return NULL;
}
retval = SetPriorityClass(hProcess, priority);
CloseHandle(hProcess);
if (retval == 0) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/*
* Return a Python tuple referencing process I/O counters.
*/
static PyObject*
get_process_io_counters(PyObject* self, PyObject* args)
{
DWORD pid;
HANDLE hProcess;
IO_COUNTERS IoCounters;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
return NULL;
}
if (! GetProcessIoCounters(hProcess, &IoCounters)) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(hProcess);
return Py_BuildValue("(KKKK)", IoCounters.ReadOperationCount,
IoCounters.WriteOperationCount,
IoCounters.ReadTransferCount,
IoCounters.WriteTransferCount);
}
/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject*
get_process_io_counters_2(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
LONGLONG rcount, wcount, rbytes, wbytes;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
rcount = process->ReadOperationCount.QuadPart;
wcount = process->WriteOperationCount.QuadPart;
rbytes = process->ReadTransferCount.QuadPart;
wbytes = process->WriteTransferCount.QuadPart;
free(buffer);
return Py_BuildValue("KKKK", rcount, wcount, rbytes, wbytes);
}
/*
* Return process CPU affinity as a bitmask
*/
static PyObject*
get_process_cpu_affinity(PyObject* self, PyObject* args)
{
DWORD pid;
HANDLE hProcess;
PDWORD_PTR proc_mask;
PDWORD_PTR system_mask;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (hProcess == NULL) {
return NULL;
}
if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(hProcess);
return Py_BuildValue("k", (unsigned long)proc_mask);
}
/*
* Set process CPU affinity
*/
static PyObject*
set_process_cpu_affinity(PyObject* self, PyObject* args)
{
DWORD pid;
HANDLE hProcess;
DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
DWORD_PTR mask;
if (! PyArg_ParseTuple(args, "lk", &pid, &mask)) {
return NULL;
}
hProcess = handle_from_pid_waccess(pid, dwDesiredAccess);
if (hProcess == NULL) {
return NULL;
}
if (SetProcessAffinityMask(hProcess, mask) == 0) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(hProcess);
Py_INCREF(Py_None);
return Py_None;
}
/*
* Return True if one of the process threads is in a waiting or
* suspended status.
*/
static PyObject*
is_process_suspended(PyObject* self, PyObject* args)
{
DWORD pid;
ULONG i;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
for (i = 0; i < process->NumberOfThreads; i++) {
if (process->Threads[i].ThreadState != Waiting ||
process->Threads[i].WaitReason != Suspended)
{
free(buffer);
Py_RETURN_FALSE;
}
}
free(buffer);
Py_RETURN_TRUE;
}
/*
* Return path's disk total and free as a Python tuple.
*/
static PyObject*
get_disk_usage(PyObject* self, PyObject* args)
{
BOOL retval;
ULARGE_INTEGER _, total, free;
LPCTSTR path;
if (! PyArg_ParseTuple(args, "s", &path)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
retval = GetDiskFreeSpaceEx(path, &_, &total, &free);
Py_END_ALLOW_THREADS
if (retval == 0) {
return PyErr_SetFromWindowsErr(0);
}
return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
}
/*
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject*
get_network_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_nic_info = NULL;
PyObject* py_pre_nic_name = NULL;
PyObject* py_nic_name = NULL;
int attempts = 0;
int outBufLen = 15000;
DWORD dwRetVal = 0;
MIB_IFROW *pIfRow = NULL;
ULONG flags = 0;
ULONG family = AF_UNSPEC;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
if (pAddresses == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"memory allocation failed for IP_ADAPTER_ADDRESSES struct.");
goto error;
}
dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses,
&outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
free(pAddresses);
pAddresses = NULL;
}
else {
break;
}
attempts++;
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3));
if (dwRetVal != NO_ERROR) {
PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed.");
goto error;
}
pCurrAddresses = pAddresses;
while (pCurrAddresses) {
py_pre_nic_name = NULL;
py_nic_name = NULL;
py_nic_info = NULL;
pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));
if (pIfRow == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"memory allocation failed for MIB_IFROW struct.");
goto error;
}
pIfRow->dwIndex = pCurrAddresses->IfIndex;
dwRetVal = GetIfEntry(pIfRow);
if (dwRetVal != NO_ERROR) {
PyErr_SetString(PyExc_RuntimeError, "GetIfEntry() failed.");
goto error;
}
py_nic_info = Py_BuildValue("(IIIIIIII)",
pIfRow->dwOutOctets,
pIfRow->dwInOctets,
pIfRow->dwOutUcastPkts,
pIfRow->dwInUcastPkts,
pIfRow->dwInErrors,
pIfRow->dwOutErrors,
pIfRow->dwInDiscards,
pIfRow->dwOutDiscards);
if (!py_nic_info)
goto error;
py_pre_nic_name = PyUnicode_FromWideChar(
pCurrAddresses->FriendlyName,
wcslen(pCurrAddresses->FriendlyName));
if (py_pre_nic_name == NULL)
goto error;
py_nic_name = PyUnicode_FromObject(py_pre_nic_name);
if (py_nic_name == NULL)
goto error;
if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info))
goto error;
Py_XDECREF(py_pre_nic_name);
Py_XDECREF(py_nic_name);
Py_XDECREF(py_nic_info);
free(pIfRow);
pCurrAddresses = pCurrAddresses->Next;
}
free(pAddresses);
return py_retdict;
error:
Py_XDECREF(py_pre_nic_name);
Py_XDECREF(py_nic_name);
Py_XDECREF(py_nic_info);
Py_DECREF(py_retdict);
if (pAddresses != NULL)
free(pAddresses);
if (pIfRow != NULL)
free(pIfRow);
return NULL;
}
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject*
get_disk_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_disk_info = NULL;
DISK_PERFORMANCE diskPerformance;
DWORD dwSize;
HANDLE hDevice = NULL;
char szDevice[MAX_PATH];
char szDeviceDisplay[MAX_PATH];
int devNum;
for (devNum = 0;; devNum++) {
py_disk_info = NULL;
sprintf (szDevice, "\\\\.\\PhysicalDrive%d", devNum);
hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
// what happens if we get an invalid handle on the first disk?
// we might end up with an empty dict incorrectly in some cases
break;
}
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
&diskPerformance, sizeof(DISK_PERFORMANCE),
&dwSize, NULL))
{
sprintf (szDeviceDisplay, "PhysicalDrive%d", devNum);
py_disk_info = Py_BuildValue("(IILLLL)",
diskPerformance.ReadCount,
diskPerformance.WriteCount,
diskPerformance.BytesRead,
diskPerformance.BytesWritten,
(diskPerformance.ReadTime.QuadPart
* 10) / 1000,
(diskPerformance.WriteTime.QuadPart
* 10) / 1000);
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_disk_info))
goto error;
Py_XDECREF(py_disk_info);
}
else {
// XXX we might get here with ERROR_INSUFFICIENT_BUFFER when
// compiling with mingw32; not sure what to do.
//return PyErr_SetFromWindowsErr(0);
;;
}
CloseHandle(hDevice);
}
return py_retdict;
error:
Py_XDECREF(py_disk_info);
Py_DECREF(py_retdict);
if (hDevice != NULL)
CloseHandle(hDevice);
return NULL;
}
static char *get_drive_type(int type)
{
switch (type) {
case DRIVE_FIXED:
return "fixed";
case DRIVE_CDROM:
return "cdrom";
case DRIVE_REMOVABLE:
return "removable";
case DRIVE_UNKNOWN:
return "unknown";
case DRIVE_NO_ROOT_DIR:
return "unmounted";
case DRIVE_REMOTE:
return "remote";
case DRIVE_RAMDISK:
return "ramdisk";
default:
return "?";
}
}
#define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
/*
* Return disk partitions as a list of tuples such as
* (drive_letter, drive_letter, type, "")
*/
static PyObject*
get_disk_partitions(PyObject* self, PyObject* args)
{
DWORD num_bytes;
char drive_strings[255];
char* drive_letter = drive_strings;
int all;
int type;
int ret;
char opts[20];
LPTSTR fs_type[MAX_PATH + 1] = { 0 };
DWORD pflags = 0;
PyObject* py_all;
PyObject* py_retlist = PyList_New(0);
PyObject* py_tuple = NULL;
if (! PyArg_ParseTuple(args, "O", &py_all)) {
goto error;
}
all = PyObject_IsTrue(py_all);
Py_BEGIN_ALLOW_THREADS
num_bytes = GetLogicalDriveStrings(254, drive_letter);
Py_END_ALLOW_THREADS
if (num_bytes == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
while (*drive_letter != 0) {
py_tuple = NULL;
opts[0] = 0;
fs_type[0] = 0;
Py_BEGIN_ALLOW_THREADS
type = GetDriveType(drive_letter);
Py_END_ALLOW_THREADS
// by default we only show hard drives and cd-roms
if (all == 0) {
if ((type == DRIVE_UNKNOWN) ||
(type == DRIVE_NO_ROOT_DIR) ||
(type == DRIVE_REMOTE) ||
(type == DRIVE_RAMDISK)) {
goto next;
}
// floppy disk: skip it by default as it introduces a
// considerable slowdown.
if ((type == DRIVE_REMOVABLE) && (strcmp(drive_letter, "A:\\") == 0)) {
goto next;
}
}
ret = GetVolumeInformation(drive_letter, NULL, _ARRAYSIZE(drive_letter),
NULL, NULL, &pflags, fs_type,
_ARRAYSIZE(fs_type));
if (ret == 0) {
// We might get here in case of a floppy hard drive, in
// which case the error is (21, "device not ready").
// Let's pretend it didn't happen as we already have
// the drive name and type ('removable').
strcat(opts, "");
SetLastError(0);
}
else {
if (pflags & FILE_READ_ONLY_VOLUME) {
strcat(opts, "ro");
}
else {
strcat(opts, "rw");
}
if (pflags & FILE_VOLUME_IS_COMPRESSED) {
strcat(opts, ",compressed");
}
}
if (strlen(opts) > 0) {
strcat(opts, ",");
}
strcat(opts, get_drive_type(type));
py_tuple = Py_BuildValue("(ssss)",
drive_letter,
drive_letter,
fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS
opts);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
goto next;
next:
drive_letter = strchr(drive_letter, 0) + 1;
}
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
return NULL;
}
#ifdef UNICODE
#define WTSOpenServer WTSOpenServerW
#else
#define WTSOpenServer WTSOpenServerA
#endif
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject*
get_system_users(PyObject* self, PyObject* args)
{
PyObject* py_retlist = PyList_New(0);
PyObject* py_tuple = NULL;
PyObject* py_address = NULL;
HANDLE hServer = NULL;
LPTSTR buffer_user = NULL;
LPTSTR buffer_addr = NULL;
PWTS_SESSION_INFO sessions = NULL;
DWORD count;
DWORD i;
DWORD sessionId;
DWORD bytes;
PWTS_CLIENT_ADDRESS address;
char address_str[50];
long long unix_time;
PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW;
WINSTATION_INFO station_info;
HINSTANCE hInstWinSta = NULL;
ULONG returnLen;
hInstWinSta = LoadLibraryA("winsta.dll");
WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW)
GetProcAddress(hInstWinSta, "WinStationQueryInformationW");
hServer = WTSOpenServer('\0');
if (hServer == NULL) {
PyErr_SetFromWindowsErr(0);
goto error;
}
if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
for (i=0; i<count; i++) {
py_address = NULL;
py_tuple = NULL;
sessionId = sessions[i].SessionId;
if (buffer_user != NULL) {
WTSFreeMemory(buffer_user);
}
if (buffer_addr != NULL) {
WTSFreeMemory(buffer_addr);
}
buffer_user = NULL;
buffer_addr = NULL;
// username
bytes = 0;
if (WTSQuerySessionInformation(hServer, sessionId, WTSUserName,
&buffer_user, &bytes) == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
if (bytes == 1) {
continue;
}
// address
bytes = 0;
if (WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress,
&buffer_addr, &bytes) == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
address = (PWTS_CLIENT_ADDRESS)buffer_addr;
if (address->AddressFamily == 0) { // AF_INET
sprintf(address_str, "%u.%u.%u.%u", address->Address[0],
address->Address[1],
address->Address[2],
address->Address[3]);
py_address = Py_BuildValue("s", address_str);
if (!py_address)
goto error;
}
else {
py_address = Py_None;
}
// login time
if (!WinStationQueryInformationW(hServer,
sessionId,
WinStationInformation,
&station_info,
sizeof(station_info),
&returnLen))
{
goto error;
}
unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32;
unix_time += station_info.ConnectTime.dwLowDateTime - 116444736000000000LL;
unix_time /= 10000000;
py_tuple = Py_BuildValue("sOd", buffer_user,
py_address,
(double)unix_time);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_XDECREF(py_address);
Py_XDECREF(py_tuple);
}
WTSCloseServer(hServer);
WTSFreeMemory(sessions);
WTSFreeMemory(buffer_user);
WTSFreeMemory(buffer_addr);
FreeLibrary(hInstWinSta);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_address);
Py_DECREF(py_retlist);
if (hInstWinSta != NULL) {
FreeLibrary(hInstWinSta);
}
if (hServer != NULL) {
WTSCloseServer(hServer);
}
if (sessions != NULL) {
WTSFreeMemory(sessions);
}
if (buffer_user != NULL) {
WTSFreeMemory(buffer_user);
}
if (buffer_addr != NULL) {
WTSFreeMemory(buffer_addr);
}
return NULL;
}
/*
* Return the number of handles opened by process.
*/
static PyObject*
get_process_num_handles(PyObject* self, PyObject* args)
{
DWORD pid;
HANDLE hProcess;
DWORD handleCount;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
return NULL;
}
if (! GetProcessHandleCount(hProcess, &handleCount)) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
CloseHandle(hProcess);
return Py_BuildValue("k", handleCount);
}
/*
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject*
get_process_num_handles_2(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
ULONG count;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
count = process->HandleCount;
free(buffer);
return Py_BuildValue("k", count);
}
/*
* Return the number of context switches executed by process.
*/
static PyObject*
get_process_num_ctx_switches(PyObject* self, PyObject* args)
{
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
ULONG i;
ULONG total = 0;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! get_process_info(pid, &process, &buffer)) {
return NULL;
}
for (i=0; i < process->NumberOfThreads; i++) {
total += process->Threads[i].ContextSwitches;
}
free(buffer);
return Py_BuildValue("ki", total, 0);
}
static char *get_region_protection_string(ULONG protection)
{
switch (protection & 0xff) {
case PAGE_NOACCESS:
return "";
case PAGE_READONLY:
return "r";
case PAGE_READWRITE:
return "rw";
case PAGE_WRITECOPY:
return "wc";
case PAGE_EXECUTE:
return "x";
case PAGE_EXECUTE_READ:
return "xr";
case PAGE_EXECUTE_READWRITE:
return "xrw";
case PAGE_EXECUTE_WRITECOPY:
return "xwc";
default:
return "?";
}
}
/*
* Return a list of process's memory mappings.
*/
static PyObject*
get_process_memory_maps(PyObject* self, PyObject* args)
{
DWORD pid;
HANDLE hProcess = NULL;
MEMORY_BASIC_INFORMATION basicInfo;
PVOID baseAddress;
PVOID previousAllocationBase;
CHAR mappedFileName[MAX_PATH];
SYSTEM_INFO system_info;
LPVOID maxAddr;
PyObject* py_list = PyList_New(0);
PyObject* py_tuple = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
hProcess = handle_from_pid(pid);
if (NULL == hProcess) {
goto error;
}
GetSystemInfo(&system_info);
maxAddr = system_info.lpMaximumApplicationAddress;
baseAddress = NULL;
previousAllocationBase = NULL;
while (VirtualQueryEx(hProcess, baseAddress, &basicInfo,
sizeof(MEMORY_BASIC_INFORMATION)))
{
py_tuple = NULL;
if (baseAddress > maxAddr) {
break;
}
if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName,
sizeof(mappedFileName)))
{
py_tuple = Py_BuildValue("(kssI)",
(unsigned long)baseAddress,
get_region_protection_string(basicInfo.Protect),
mappedFileName,
basicInfo.RegionSize
);
if (!py_tuple)
goto error;
if (PyList_Append(py_list, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
previousAllocationBase = basicInfo.AllocationBase;
baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize;
}
CloseHandle(hProcess);
return py_list;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_list);
if (hProcess != NULL)
CloseHandle(hProcess);
return NULL;
}
// ------------------------ Python init ---------------------------
static PyMethodDef
PsutilMethods[] =
{
// --- per-process functions
{"get_process_name", get_process_name, METH_VARARGS,
"Return process name"},
{"get_process_cmdline", get_process_cmdline, METH_VARARGS,
"Return process cmdline as a list of cmdline arguments"},
{"get_process_exe", get_process_exe, METH_VARARGS,
"Return path of the process executable"},
{"get_process_ppid", get_process_ppid, METH_VARARGS,
"Return process ppid as an integer"},
{"kill_process", kill_process, METH_VARARGS,
"Kill the process identified by the given PID"},
{"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
"Return tuple of user/kern time for the given PID"},
{"get_process_create_time", get_process_create_time, METH_VARARGS,
"Return a float indicating the process create time expressed in "
"seconds since the epoch"},
{"get_process_memory_info", get_process_memory_info, METH_VARARGS,
"Return a tuple of process memory information"},
{"get_process_cwd", get_process_cwd, METH_VARARGS,
"Return process current working directory"},
{"suspend_process", suspend_process, METH_VARARGS,
"Suspend a process"},
{"resume_process", resume_process, METH_VARARGS,
"Resume a process"},
{"get_process_open_files", get_process_open_files, METH_VARARGS,
"Return files opened by process"},
{"get_process_username", get_process_username, METH_VARARGS,
"Return the username of a process"},
{"get_process_connections", get_process_connections, METH_VARARGS,
"Return the network connections of a process"},
{"get_process_num_threads", get_process_num_threads, METH_VARARGS,
"Return the network connections of a process"},
{"get_process_threads", get_process_threads, METH_VARARGS,
"Return process threads information as a list of tuple"},
{"process_wait", process_wait, METH_VARARGS,
"Wait for process to terminate and return its exit code."},
{"get_process_priority", get_process_priority, METH_VARARGS,
"Return process priority."},
{"set_process_priority", set_process_priority, METH_VARARGS,
"Set process priority."},
{"get_process_cpu_affinity", get_process_cpu_affinity, METH_VARARGS,
"Return process CPU affinity as a bitmask."},
{"set_process_cpu_affinity", set_process_cpu_affinity, METH_VARARGS,
"Set process CPU affinity."},
{"get_process_io_counters", get_process_io_counters, METH_VARARGS,
"Get process I/O counters."},
{"is_process_suspended", is_process_suspended, METH_VARARGS,
"Return True if one of the process threads is in a suspended state"},
{"get_process_num_handles", get_process_num_handles, METH_VARARGS,
"Return the number of handles opened by process."},
{"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS,
"Return the number of context switches performed by process."},
{"get_process_memory_maps", get_process_memory_maps, METH_VARARGS,
"Return a list of process's memory mappings"},
// --- alternative pinfo interface
{"get_process_cpu_times_2", get_process_cpu_times_2, METH_VARARGS,
"Alternative implementation"},
{"get_process_create_time_2", get_process_create_time_2, METH_VARARGS,
"Alternative implementation"},
{"get_process_num_handles_2", get_process_num_handles_2, METH_VARARGS,
"Alternative implementation"},
{"get_process_io_counters_2", get_process_io_counters_2, METH_VARARGS,
"Alternative implementation"},
{"get_process_memory_info_2", get_process_memory_info_2, METH_VARARGS,
"Alternative implementation"},
// --- system-related functions
{"get_pid_list", get_pid_list, METH_VARARGS,
"Returns a list of PIDs currently running on the system"},
{"pid_exists", pid_exists, METH_VARARGS,
"Determine if the process exists in the current process list."},
{"get_num_cpus", get_num_cpus, METH_VARARGS,
"Returns the number of CPUs on the system"},
{"get_system_uptime", get_system_uptime, METH_VARARGS,
"Return system uptime"},
{"get_virtual_mem", get_virtual_mem, METH_VARARGS,
"Return the total amount of physical memory, in bytes"},
{"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
"Return system per-cpu times as a list of tuples"},
{"get_disk_usage", get_disk_usage, METH_VARARGS,
"Return path's disk total and free as a Python tuple."},
{"get_network_io_counters", get_network_io_counters, METH_VARARGS,
"Return dict of tuples of networks I/O information."},
{"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
"Return dict of tuples of disks I/O information."},
{"get_system_users", get_system_users, METH_VARARGS,
"Return a list of currently connected users."},
{"get_disk_partitions", get_disk_partitions, METH_VARARGS,
"Return disk partitions."},
// --- windows API bindings
{"win32_QueryDosDevice", win32_QueryDosDevice, METH_VARARGS,
"QueryDosDevice binding"},
{NULL, NULL, 0, NULL}
};
struct module_state {
PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif
#if PY_MAJOR_VERSION >= 3
static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int psutil_mswindows_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_mswindows",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_mswindows_traverse,
psutil_mswindows_clear,
NULL
};
#define INITERROR return NULL
PyObject* PyInit__psutil_mswindows(void)
#else
#define INITERROR return
void init_psutil_mswindows(void)
#endif
{
struct module_state *st = NULL;
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods);
#endif
if (module == NULL) {
INITERROR;
}
st = GETSTATE(module);
st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL);
if (st->error == NULL) {
Py_DECREF(module);
INITERROR;
}
// Public constants
// http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx
PyModule_AddIntConstant(module, "ABOVE_NORMAL_PRIORITY_CLASS",
ABOVE_NORMAL_PRIORITY_CLASS);
PyModule_AddIntConstant(module, "BELOW_NORMAL_PRIORITY_CLASS",
BELOW_NORMAL_PRIORITY_CLASS);
PyModule_AddIntConstant(module, "HIGH_PRIORITY_CLASS",
HIGH_PRIORITY_CLASS);
PyModule_AddIntConstant(module, "IDLE_PRIORITY_CLASS",
IDLE_PRIORITY_CLASS);
PyModule_AddIntConstant(module, "NORMAL_PRIORITY_CLASS",
NORMAL_PRIORITY_CLASS);
PyModule_AddIntConstant(module, "REALTIME_PRIORITY_CLASS",
REALTIME_PRIORITY_CLASS);
// private constants
PyModule_AddIntConstant(module, "INFINITE", INFINITE);
PyModule_AddIntConstant(module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED);
SetSeDebug();
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
/*
* $Id: _psutil_mswindows.h 1498 2012-07-24 21:41:28Z g.rodola $
*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Windows platform-specific module methods for _psutil_mswindows
*/
#include <Python.h>
#include <windows.h>
// --- per-process functions
static PyObject* get_process_name(PyObject* self, PyObject* args);
static PyObject* get_process_cmdline(PyObject* self, PyObject* args);
static PyObject* get_process_exe(PyObject* self, PyObject* args);
static PyObject* get_process_ppid(PyObject* self, PyObject* args);
static PyObject* get_process_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_process_create_time(PyObject* self, PyObject* args);
static PyObject* get_process_memory_info(PyObject* self, PyObject* args);
static PyObject* get_process_cwd(PyObject* self, PyObject* args);
static PyObject* get_process_open_files(PyObject* self, PyObject* args);
static PyObject* get_process_username(PyObject* self, PyObject* args);
static PyObject* get_process_connections(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
static PyObject* get_process_threads(PyObject* self, PyObject* args);
static PyObject* get_process_priority(PyObject* self, PyObject* args);
static PyObject* set_process_priority(PyObject* self, PyObject* args);
static PyObject* get_process_io_counters(PyObject* self, PyObject* args);
static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args);
static PyObject* set_process_cpu_affinity(PyObject* self, PyObject* args);
static PyObject* get_process_num_handles(PyObject* self, PyObject* args);
static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args);
static PyObject* get_process_memory_maps(PyObject* self, PyObject* args);
static PyObject* get_process_cpu_times_2(PyObject* self, PyObject* args);
static PyObject* get_process_create_time_2(PyObject* self, PyObject* args);
static PyObject* get_process_num_handles_2(PyObject* self, PyObject* args);
static PyObject* get_process_io_counters_2(PyObject* self, PyObject* args);
static PyObject* get_process_memory_info_2(PyObject* self, PyObject* args);
static PyObject* suspend_process(PyObject* self, PyObject* args);
static PyObject* resume_process(PyObject* self, PyObject* args);
static PyObject* is_process_suspended(PyObject* self, PyObject* args);
static PyObject* process_wait(PyObject* self, PyObject* args);
static PyObject* kill_process(PyObject* self, PyObject* args);
// --- system-related functions
static PyObject* get_pid_list(PyObject* self, PyObject* args);
static PyObject* get_num_cpus(PyObject* self, PyObject* args);
static PyObject* get_system_uptime(PyObject* self, PyObject* args);
static PyObject* get_virtual_mem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
static PyObject* pid_exists(PyObject* self, PyObject* args);
static PyObject* get_disk_usage(PyObject* self, PyObject* args);
static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
static PyObject* get_network_io_counters(PyObject* self, PyObject* args);
static PyObject* get_disk_io_counters(PyObject* self, PyObject* args);
static PyObject* get_system_users(PyObject* self, PyObject* args);
// --- windows API bindings
static PyObject* win32_QueryDosDevice(PyObject* self, PyObject* args);
// --- internal
int suspend_resume_process(DWORD pid, int suspend);
/*
* $Id: _psutil_osx.c 1501 2012-07-25 12:57:34Z g.rodola@gmail.com $
*
* 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.
*
* OS X platform-specific module methods for _psutil_osx
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <utmpx.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <libproc.h>
#include <sys/proc_info.h>
#include <netinet/tcp_fsm.h>
#include <arpa/inet.h>
#include <net/if_dl.h>
#include <pwd.h>
#include <mach/mach.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/host_info.h>
#include <mach/mach_host.h>
#include <mach/mach_traps.h>
#include <mach/mach_vm.h>
#include <mach/shared_memory_server.h>
#include <mach-o/loader.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/IOBSD.h>
#include "_psutil_osx.h"
#include "_psutil_common.h"
#include "arch/osx/process_info.h"
/*
* A wrapper around host_statistics() invoked with HOST_VM_INFO.
*/
int
psutil_sys_vminfo(vm_statistics_data_t *vmstat)
{
kern_return_t ret;
mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
mach_port_t mport = mach_host_self();
ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)vmstat, &count);
if (ret != KERN_SUCCESS) {
PyErr_Format(PyExc_RuntimeError,
"host_statistics() failed: %s", mach_error_string(ret));
return 0;
}
return 1;
}
/*
* Return a Python list of all the PIDs running on the system.
*/
static PyObject*
get_pid_list(PyObject* self, PyObject* args)
{
kinfo_proc *proclist = NULL;
kinfo_proc *orig_address = NULL;
size_t num_processes;
size_t idx;
PyObject *pid = NULL;
PyObject *retlist = PyList_New(0);
if (get_proc_list(&proclist, &num_processes) != 0) {
PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list.");
goto error;
}
if (num_processes > 0) {
// save the address of proclist so we can free it later
orig_address = proclist;
for (idx=0; idx < num_processes; idx++) {
pid = Py_BuildValue("i", proclist->kp_proc.p_pid);
if (!pid)
goto error;
if (PyList_Append(retlist, pid))
goto error;
Py_DECREF(pid);
proclist++;
}
free(orig_address);
}
return retlist;
error:
Py_XDECREF(pid);
Py_DECREF(retlist);
if (orig_address != NULL)
free(orig_address);
return NULL;
}
/*
* Return process name from kinfo_proc as a Python string.
*/
static PyObject*
get_process_name(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("s", kp.kp_proc.p_comm);
}
/*
* Return process current working directory.
*/
static PyObject*
get_process_cwd(PyObject* self, PyObject* args)
{
long pid;
struct proc_vnodepathinfo pathinfo;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo,
sizeof(pathinfo)))
{
return NULL;
}
return Py_BuildValue("s", pathinfo.pvi_cdir.vip_path);
}
/*
* Return path of the process executable.
*/
static PyObject*
get_process_exe(PyObject* self, PyObject* args)
{
long pid;
char buf[PATH_MAX];
int ret;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
ret = proc_pidpath(pid, &buf, sizeof(buf));
if (ret == 0) {
if (! pid_exists(pid)) {
return NoSuchProcess();
}
else {
return AccessDenied();
}
}
return Py_BuildValue("s", buf);
}
/*
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject*
get_process_cmdline(PyObject* self, PyObject* args)
{
long pid;
PyObject* arglist = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
// get the commandline, defined in arch/osx/process_info.c
arglist = get_arg_list(pid);
return arglist;
}
/*
* Return process parent pid from kinfo_proc as a Python integer.
*/
static PyObject*
get_process_ppid(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid);
}
/*
* Return process real uid from kinfo_proc as a Python integer.
*/
static PyObject*
get_process_uids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_ruid,
(long)kp.kp_eproc.e_ucred.cr_uid,
(long)kp.kp_eproc.e_pcred.p_svuid);
}
/*
* Return process real group id from ki_comm as a Python integer.
*/
static PyObject*
get_process_gids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_rgid,
(long)kp.kp_eproc.e_ucred.cr_groups[0],
(long)kp.kp_eproc.e_pcred.p_svgid);
}
/*
* Return process controlling terminal number as an integer.
*/
static PyObject*
get_process_tty_nr(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("i", kp.kp_eproc.e_tdev);
}
/*
* Return a list of tuples for every process memory maps.
* 'procstat' cmdline utility has been used as an example.
*/
static PyObject*
get_process_memory_maps(PyObject* self, PyObject* args)
{
char buf[PATH_MAX];
char addr_str[34];
char perms[8];
int pagesize = getpagesize();
long pid;
kern_return_t err = KERN_SUCCESS;
mach_port_t task;
uint32_t depth = 1;
vm_address_t address = 0;
vm_size_t size = 0;
PyObject* py_tuple = NULL;
PyObject* py_list = PyList_New(0);
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
if (! pid_exists(pid)) {
NoSuchProcess();
}
else {
// pid exists, so return AccessDenied error since task_for_pid()
// failed
AccessDenied();
}
goto error;
}
while (1) {
py_tuple = NULL;
struct vm_region_submap_info_64 info;
mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
err = vm_region_recurse_64(task, &address, &size, &depth,
(vm_region_info_64_t)&info, &count);
if (err == KERN_INVALID_ADDRESS) {
break;
}
if (info.is_submap) {
depth++;
}
else {
// Free/Reset the char[]s to avoid weird paths
memset(buf, 0, sizeof(buf));
memset(addr_str, 0, sizeof(addr_str));
memset(perms, 0, sizeof(perms));
sprintf(addr_str, "%016x-%016x", address, address + size);
sprintf(perms, "%c%c%c/%c%c%c",
(info.protection & VM_PROT_READ) ? 'r' : '-',
(info.protection & VM_PROT_WRITE) ? 'w' : '-',
(info.protection & VM_PROT_EXECUTE) ? 'x' : '-',
(info.max_protection & VM_PROT_READ) ? 'r' : '-',
(info.max_protection & VM_PROT_WRITE) ? 'w' : '-',
(info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-');
address += size;
err = proc_regionfilename(pid, address, buf, sizeof(buf));
if (info.share_mode == SM_COW && info.ref_count == 1) {
// Treat single reference SM_COW as SM_PRIVATE
info.share_mode = SM_PRIVATE;
}
if (strlen(buf) == 0) {
switch(info.share_mode) {
/*
case SM_LARGE_PAGE:
// Treat SM_LARGE_PAGE the same as SM_PRIVATE
// since they are not shareable and are wired.
*/
case SM_COW:
strcpy(buf, "[cow]");
break;
case SM_PRIVATE:
strcpy(buf, "[prv]");
break;
case SM_EMPTY:
strcpy(buf, "[nul]");
break;
case SM_SHARED:
case SM_TRUESHARED:
strcpy(buf, "[shm]");
break;
case SM_PRIVATE_ALIASED:
strcpy(buf, "[ali]");
break;
case SM_SHARED_ALIASED:
strcpy(buf, "[s/a]");
break;
default:
strcpy(buf, "[???]");
}
}
py_tuple = Py_BuildValue("sssIIIIIH",
addr_str, // "start-end" address
perms, // "rwx" permissions
buf, // path
info.pages_resident * pagesize, // rss
info.pages_shared_now_private * pagesize, // private
info.pages_swapped_out * pagesize, // swapped
info.pages_dirtied * pagesize, // dirtied
info.ref_count, // ref count
info.shadow_depth // shadow depth
);
if (!py_tuple)
goto error;
if (PyList_Append(py_list, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
}
return py_list;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_list);
return NULL;
}
/*
* Return a Python integer indicating the number of CPUs on the system.
*/
static PyObject*
get_num_cpus(PyObject* self, PyObject* args)
{
int mib[2];
int ncpu;
size_t len;
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
return NULL;
}
return Py_BuildValue("i", ncpu);
}
#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
/*
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject*
get_process_cpu_times(PyObject* self, PyObject* args)
{
long pid;
struct proc_taskinfo pti;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
return NULL;
}
return Py_BuildValue("(dd)",
(float)pti.pti_total_user / 1000000000.0,
(float)pti.pti_total_system / 1000000000.0);
}
/*
* Return a Python float indicating the process create time expressed in
* seconds since the epoch.
*/
static PyObject*
get_process_create_time(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("d", TV2DOUBLE(kp.kp_proc.p_starttime));
}
/*
* Return extended memory info about a process.
*/
static PyObject*
get_process_memory_info(PyObject* self, PyObject* args)
{
long pid;
struct proc_taskinfo pti;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
return NULL;
}
// Note: determining other memory stats on OSX is a mess:
// http://www.opensource.apple.com/source/top/top-67/libtop.c?txt
// I just give up...
//struct proc_regioninfo pri;
//psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, &pri, sizeof(pri))
return Py_BuildValue("(KKkk)",
pti.pti_resident_size, // resident memory size (rss)
pti.pti_virtual_size, // virtual memory size (vms)
pti.pti_faults, // number of page faults (pages)
pti.pti_pageins // number of actual pageins (pages)
);
}
/*
* Return number of threads used by process as a Python integer.
*/
static PyObject*
get_process_num_threads(PyObject* self, PyObject* args)
{
long pid;
struct proc_taskinfo pti;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
return NULL;
}
return Py_BuildValue("k", pti.pti_threadnum);
}
/*
* Return the number of context switches performed by process.
*/
static PyObject*
get_process_num_ctx_switches(PyObject* self, PyObject* args)
{
long pid;
struct proc_taskinfo pti;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
return NULL;
}
// unvoluntary value seems not to be available;
// pti.pti_csw probably refers to the sum of the two (getrusage()
// numbers seems to confirm this theory).
return Py_BuildValue("ki", pti.pti_csw, 0);
}
/*
* Return system virtual memory stats
*/
static PyObject*
get_virtual_mem(PyObject* self, PyObject* args)
{
int mib[2];
uint64_t total;
size_t len = sizeof(total);
vm_statistics_data_t vm;
int pagesize = getpagesize();
// physical mem
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
if (sysctl(mib, 2, &total, &len, NULL, 0)) {
if (errno != 0)
PyErr_SetFromErrno(0);
else
PyErr_Format(PyExc_RuntimeError, "sysctl(HW_MEMSIZE) failed");
return NULL;
}
// vm
if (!psutil_sys_vminfo(&vm)) {
return NULL;
}
return Py_BuildValue("KKKKK",
total,
(unsigned long long) vm.active_count * pagesize,
(unsigned long long) vm.inactive_count * pagesize,
(unsigned long long) vm.wire_count * pagesize,
(unsigned long long) vm.free_count * pagesize
);
}
/*
* Return stats about swap memory.
*/
static PyObject*
get_swap_mem(PyObject* self, PyObject* args)
{
int mib[2];
size_t size;
struct xsw_usage totals;
vm_statistics_data_t vmstat;
int pagesize = getpagesize();
mib[0] = CTL_VM;
mib[1] = VM_SWAPUSAGE;
size = sizeof(totals);
if (sysctl(mib, 2, &totals, &size, NULL, 0) == -1) {
if (errno != 0)
PyErr_SetFromErrno(0);
else
PyErr_Format(PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) failed");
return NULL;
}
if (!psutil_sys_vminfo(&vmstat)) {
return NULL;
}
return Py_BuildValue("LLLKK",
totals.xsu_total,
totals.xsu_used,
totals.xsu_avail,
(unsigned long long)vmstat.pageins * pagesize,
(unsigned long long)vmstat.pageouts * pagesize);
}
/*
* Return a Python tuple representing user, kernel and idle CPU times
*/
static PyObject*
get_system_cpu_times(PyObject* self, PyObject* args)
{
mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
kern_return_t error;
host_cpu_load_info_data_t r_load;
error = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&r_load, &count);
if (error != KERN_SUCCESS) {
return PyErr_Format(PyExc_RuntimeError,
"Error in host_statistics(): %s", mach_error_string(error));
}
return Py_BuildValue("(dddd)",
(double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK,
(double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
(double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
(double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
);
}
/*
* Return a Python list of tuple representing per-cpu times
*/
static PyObject*
get_system_per_cpu_times(PyObject* self, PyObject* args)
{
natural_t cpu_count;
processor_info_array_t info_array;
mach_msg_type_number_t info_count;
kern_return_t error;
processor_cpu_load_info_data_t* cpu_load_info = NULL;
PyObject* py_retlist = PyList_New(0);
PyObject* py_cputime = NULL;
int i, ret;
error = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO,
&cpu_count, &info_array, &info_count);
if (error != KERN_SUCCESS) {
PyErr_Format(PyExc_RuntimeError, "Error in host_processor_info(): %s",
mach_error_string(error));
goto error;
}
cpu_load_info = (processor_cpu_load_info_data_t*) info_array;
for (i = 0; i < cpu_count; i++) {
py_cputime = Py_BuildValue("(dddd)",
(double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK,
(double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
(double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
(double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
);
if (!py_cputime)
goto error;
if (PyList_Append(py_retlist, py_cputime))
goto error;
Py_DECREF(py_cputime);
}
ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
info_count * sizeof(int));
if (ret != KERN_SUCCESS) {
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
}
return py_retlist;
error:
Py_XDECREF(py_cputime);
Py_DECREF(py_retlist);
if (cpu_load_info != NULL) {
ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
info_count * sizeof(int));
if (ret != KERN_SUCCESS) {
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
}
}
return NULL;
}
/*
* Return a Python float indicating the system boot time expressed in
* seconds since the epoch.
*/
static PyObject*
get_system_boot_time(PyObject* self, PyObject* args)
{
/* fetch sysctl "kern.boottime" */
static int request[2] = { CTL_KERN, KERN_BOOTTIME };
struct timeval result;
size_t result_len = sizeof result;
time_t boot_time = 0;
if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) {
PyErr_SetFromErrno(0);
return NULL;
}
boot_time = result.tv_sec;
return Py_BuildValue("f", (float)boot_time);
}
/*
* Return a list of tuples including device, mount point and fs type
* for all partitions mounted on the system.
*/
static PyObject*
get_disk_partitions(PyObject* self, PyObject* args)
{
int num;
int i;
long len;
uint64_t flags;
char opts[400];
struct statfs *fs = NULL;
PyObject* py_retlist = PyList_New(0);
PyObject* py_tuple = NULL;
// get the number of mount points
Py_BEGIN_ALLOW_THREADS
num = getfsstat(NULL, 0, MNT_NOWAIT);
Py_END_ALLOW_THREADS
if (num == -1) {
PyErr_SetFromErrno(0);
goto error;
}
len = sizeof(*fs) * num;
fs = malloc(len);
Py_BEGIN_ALLOW_THREADS
num = getfsstat(fs, len, MNT_NOWAIT);
Py_END_ALLOW_THREADS
if (num == -1) {
PyErr_SetFromErrno(0);
goto error;
}
for (i = 0; i < num; i++) {
opts[0] = 0;
flags = fs[i].f_flags;
// see sys/mount.h
if (flags & MNT_RDONLY)
strlcat(opts, "ro", sizeof(opts));
else
strlcat(opts, "rw", sizeof(opts));
if (flags & MNT_SYNCHRONOUS)
strlcat(opts, ",sync", sizeof(opts));
if (flags & MNT_NOEXEC)
strlcat(opts, ",noexec", sizeof(opts));
if (flags & MNT_NOSUID)
strlcat(opts, ",nosuid", sizeof(opts));
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_ASYNC)
strlcat(opts, ",async", sizeof(opts));
if (flags & MNT_EXPORTED)
strlcat(opts, ",exported", sizeof(opts));
if (flags & MNT_QUARANTINE)
strlcat(opts, ",quarantine", sizeof(opts));
if (flags & MNT_LOCAL)
strlcat(opts, ",local", sizeof(opts));
if (flags & MNT_QUOTA)
strlcat(opts, ",quota", sizeof(opts));
if (flags & MNT_ROOTFS)
strlcat(opts, ",rootfs", sizeof(opts));
if (flags & MNT_DOVOLFS)
strlcat(opts, ",dovolfs", sizeof(opts));
if (flags & MNT_DONTBROWSE)
strlcat(opts, ",dontbrowse", sizeof(opts));
if (flags & MNT_IGNORE_OWNERSHIP)
strlcat(opts, ",ignore-ownership", sizeof(opts));
if (flags & MNT_AUTOMOUNTED)
strlcat(opts, ",automounted", sizeof(opts));
if (flags & MNT_JOURNALED)
strlcat(opts, ",journaled", sizeof(opts));
if (flags & MNT_NOUSERXATTR)
strlcat(opts, ",nouserxattr", sizeof(opts));
if (flags & MNT_DEFWRITE)
strlcat(opts, ",defwrite", sizeof(opts));
if (flags & MNT_MULTILABEL)
strlcat(opts, ",multilabel", sizeof(opts));
if (flags & MNT_NOATIME)
strlcat(opts, ",noatime", sizeof(opts));
if (flags & MNT_UPDATE)
strlcat(opts, ",update", sizeof(opts));
if (flags & MNT_RELOAD)
strlcat(opts, ",reload", sizeof(opts));
if (flags & MNT_FORCE)
strlcat(opts, ",force", sizeof(opts));
if (flags & MNT_CMDFLAGS)
strlcat(opts, ",cmdflags", sizeof(opts));
py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device
fs[i].f_mntonname, // mount point
fs[i].f_fstypename, // fs type
opts); // options
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
free(fs);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (fs != NULL)
free(fs);
return NULL;
}
/*
* Return process status as a Python integer.
*/
static PyObject*
get_process_status(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
return Py_BuildValue("i", (int)kp.kp_proc.p_stat);
}
/*
* Return process threads
*/
static PyObject*
get_process_threads(PyObject* self, PyObject* args)
{
long pid;
int err, j, ret;
kern_return_t kr;
unsigned int info_count = TASK_BASIC_INFO_COUNT;
mach_port_t task;
struct task_basic_info tasks_info;
thread_act_port_array_t thread_list = NULL;
thread_info_data_t thinfo;
thread_basic_info_t basic_info_th;
mach_msg_type_number_t thread_count, thread_info_count;
PyObject* retList = PyList_New(0);
PyObject* pyTuple = NULL;
// the argument passed should be a process id
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
// task_for_pid() requires special privileges
err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
if (! pid_exists(pid)) {
NoSuchProcess();
}
else {
AccessDenied();
}
goto error;
}
info_count = TASK_BASIC_INFO_COUNT;
err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count);
if (err != KERN_SUCCESS) {
// errcode 4 is "invalid argument" (access denied)
if (err == 4) {
AccessDenied();
}
else {
// otherwise throw a runtime error with appropriate error code
PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed");
}
goto error;
}
err = task_threads(task, &thread_list, &thread_count);
if (err != KERN_SUCCESS) {
PyErr_Format(PyExc_RuntimeError, "task_threads() failed");
goto error;
}
for (j = 0; j < thread_count; j++) {
pyTuple = NULL;
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
(thread_info_t)thinfo, &thread_info_count);
if (kr != KERN_SUCCESS) {
PyErr_Format(PyExc_RuntimeError, "thread_info() failed");
goto error;
}
basic_info_th = (thread_basic_info_t)thinfo;
// XXX - thread_info structure does not provide any process id;
// the best we can do is assigning an incremental bogus value
pyTuple = Py_BuildValue("Iff", j + 1,
(float)basic_info_th->user_time.microseconds / 1000000.0,
(float)basic_info_th->system_time.microseconds / 1000000.0
);
if (!pyTuple)
goto error;
if (PyList_Append(retList, pyTuple))
goto error;
Py_DECREF(pyTuple);
}
ret = vm_deallocate(task, (vm_address_t)thread_list,
thread_count * sizeof(int));
if (ret != KERN_SUCCESS) {
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
}
return retList;
error:
Py_XDECREF(pyTuple);
Py_DECREF(retList);
if (thread_list != NULL) {
ret = vm_deallocate(task, (vm_address_t)thread_list,
thread_count * sizeof(int));
if (ret != KERN_SUCCESS) {
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
}
}
return NULL;
}
/*
* Return process open files as a Python tuple.
* References:
* - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd
* - /usr/include/sys/proc_info.h
*/
static PyObject*
get_process_open_files(PyObject* self, PyObject* args)
{
long pid;
int pidinfo_result;
int iterations;
int i;
int nb;
struct proc_fdinfo *fds_pointer = NULL;
struct proc_fdinfo *fdp_pointer;
struct vnode_fdinfowithpath vi;
PyObject *retList = PyList_New(0);
PyObject *tuple = NULL;
if (! PyArg_ParseTuple(args, "l", &pid)) {
goto error;
}
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0) {
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed");
goto error;
}
fds_pointer = malloc(pidinfo_result);
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
if (pidinfo_result <= 0) {
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed");
goto error;
}
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
tuple = NULL;
fdp_pointer = &fds_pointer[i];
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE)
{
nb = proc_pidfdinfo(pid,
fdp_pointer->proc_fd,
PROC_PIDFDVNODEPATHINFO,
&vi,
sizeof(vi));
// --- errors checking
if (nb <= 0) {
if ((errno == ENOENT) || (errno == EBADF)) {
// no such file or directory or bad file descriptor;
// let's assume the file has been closed or removed
continue;
}
// may be be ignored later if errno != 0
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
goto error;
}
if (nb < sizeof(vi)) {
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)");
goto error;
}
// --- /errors checking
// --- construct python list
tuple = Py_BuildValue("(si)", vi.pvip.vip_path,
(int)fdp_pointer->proc_fd);
if (!tuple)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
// --- /construct python list
}
}
free(fds_pointer);
return retList;
error:
Py_XDECREF(tuple);
Py_DECREF(retList);
if (fds_pointer != NULL) {
free(fds_pointer);
}
if (errno != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
else if (! pid_exists(pid)) {
return NoSuchProcess();
}
else {
// exception has already been set earlier
return NULL;
}
}
/*
* mathes Linux net/tcp_states.h:
* http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
*/
static char *
get_connection_status(int st) {
switch (st) {
case TCPS_CLOSED:
return "CLOSE";
case TCPS_CLOSING:
return "CLOSING";
case TCPS_CLOSE_WAIT:
return "CLOSE_WAIT";
case TCPS_LISTEN:
return "LISTEN";
case TCPS_ESTABLISHED:
return "ESTABLISHED";
case TCPS_SYN_SENT:
return "SYN_SENT";
case TCPS_SYN_RECEIVED:
return "SYN_RECV";
case TCPS_FIN_WAIT_1:
return "FIN_WAIT_1";
case TCPS_FIN_WAIT_2:
return "FIN_WAIT_2";
case TCPS_LAST_ACK:
return "LAST_ACK";
case TCPS_TIME_WAIT:
return "TIME_WAIT";
default:
return "";
}
}
/*
* Return process TCP and UDP connections as a list of tuples.
* References:
* - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0
* - /usr/include/sys/proc_info.h
*/
static PyObject*
get_process_connections(PyObject* self, PyObject* args)
{
long pid;
int pidinfo_result;
int iterations;
int i;
int nb;
struct proc_fdinfo *fds_pointer = NULL;
struct proc_fdinfo *fdp_pointer;
struct socket_fdinfo si;
PyObject *retList = PyList_New(0);
PyObject *tuple = NULL;
PyObject *laddr = NULL;
PyObject *raddr = NULL;
PyObject *af_filter = NULL;
PyObject *type_filter = NULL;
if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
goto error;
}
if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
if (pid == 0) {
return retList;
}
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0) {
goto error;
}
fds_pointer = malloc(pidinfo_result);
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
if (pidinfo_result <= 0) {
goto error;
}
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
tuple = NULL;
laddr = NULL;
raddr = NULL;
errno = 0;
fdp_pointer = &fds_pointer[i];
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET)
{
nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO,
&si, sizeof(si));
// --- errors checking
if (nb <= 0) {
if (errno == EBADF) {
// let's assume socket has been closed
continue;
}
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
}
else {
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
}
goto error;
}
if (nb < sizeof(si)) {
PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)");
goto error;
}
// --- /errors checking
//
int fd, family, type, lport, rport;
char lip[200], rip[200];
char *state;
int inseq;
PyObject* _family;
PyObject* _type;
fd = (int)fdp_pointer->proc_fd;
family = si.psi.soi_family;
type = si.psi.soi_type;
// apply filters
_family = PyLong_FromLong((long)family);
inseq = PySequence_Contains(af_filter, _family);
Py_DECREF(_family);
if (inseq == 0) {
continue;
}
_type = PyLong_FromLong((long)type);
inseq = PySequence_Contains(type_filter, _type);
Py_DECREF(_type);
if (inseq == 0) {
continue;
}
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if ((family == AF_INET) || (family == AF_INET6)) {
if (family == AF_INET) {
inet_ntop(AF_INET,
&si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4,
lip,
sizeof(lip));
inet_ntop(AF_INET,
&si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4,
rip,
sizeof(rip));
}
else {
inet_ntop(AF_INET6,
&si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6,
lip, sizeof(lip));
inet_ntop(AF_INET6,
&si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6,
rip, sizeof(rip));
}
// check for inet_ntop failures
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
if (type == SOCK_STREAM) {
state = get_connection_status((int)si.psi.soi_proto.pri_tcp.tcpsi_state);
}
else {
state = "";
}
laddr = Py_BuildValue("(si)", lip, lport);
if (!laddr)
goto error;
if (rport != 0) {
raddr = Py_BuildValue("(si)", rip, rport);
}
else {
raddr = Py_BuildValue("()");
}
if (!raddr)
goto error;
// construct the python list
tuple = Py_BuildValue("(iiiNNs)", fd, family, type, laddr, raddr,
state);
if (!tuple)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
}
else if (family == AF_UNIX) {
// construct the python list
tuple = Py_BuildValue("(iiisss)",
fd, family, type,
si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path,
si.psi.soi_proto.pri_un.unsi_caddr.ua_sun.sun_path,
"");
if (!tuple)
goto error;
if (PyList_Append(retList, tuple))
goto error;
Py_DECREF(tuple);
}
}
}
free(fds_pointer);
return retList;
error:
Py_XDECREF(tuple);
Py_XDECREF(laddr);
Py_XDECREF(raddr);
Py_DECREF(retList);
if (fds_pointer != NULL) {
free(fds_pointer);
}
if (errno != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
else if (! pid_exists(pid) ) {
return NoSuchProcess();
}
else {
return PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDLISTFDS) failed");
}
}
/*
* Return number of file descriptors opened by process.
*/
static PyObject*
get_process_num_fds(PyObject* self, PyObject* args)
{
long pid;
int pidinfo_result;
int num;
struct proc_fdinfo *fds_pointer;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
fds_pointer = malloc(pidinfo_result);
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
if (pidinfo_result <= 0) {
free(fds_pointer);
return PyErr_SetFromErrno(PyExc_OSError);
}
num = (pidinfo_result / PROC_PIDLISTFD_SIZE);
free(fds_pointer);
return Py_BuildValue("i", num);
}
/*
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject*
get_network_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_ifc_info = NULL;
char *buf = NULL, *lim, *next;
struct if_msghdr *ifm;
int mib[6];
size_t len;
mib[0] = CTL_NET; // networking subsystem
mib[1] = PF_ROUTE; // type of information
mib[2] = 0; // protocol (IPPROTO_xxx)
mib[3] = 0; // address family
mib[4] = NET_RT_IFLIST2; // operation
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(0);
goto error;
}
buf = malloc(len);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(0);
goto error;
}
lim = buf + len;
for (next = buf; next < lim; ) {
ifm = (struct if_msghdr *)next;
next += ifm->ifm_msglen;
if (ifm->ifm_type == RTM_IFINFO2) {
py_ifc_info = NULL;
struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
char ifc_name[32];
strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
ifc_name[sdl->sdl_nlen] = 0;
py_ifc_info = Py_BuildValue("(KKKKKKKi)",
if2m->ifm_data.ifi_obytes,
if2m->ifm_data.ifi_ibytes,
if2m->ifm_data.ifi_opackets,
if2m->ifm_data.ifi_ipackets,
if2m->ifm_data.ifi_ierrors,
if2m->ifm_data.ifi_oerrors,
if2m->ifm_data.ifi_iqdrops,
0); // dropout not supported
if (!py_ifc_info)
goto error;
if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
goto error;
Py_DECREF(py_ifc_info);
}
else {
continue;
}
}
free(buf);
return py_retdict;
error:
Py_XDECREF(py_ifc_info);
Py_DECREF(py_retdict);
if (buf != NULL)
free(buf);
return NULL;
}
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject*
get_disk_io_counters(PyObject* self, PyObject* args)
{
PyObject* py_retdict = PyDict_New();
PyObject* py_disk_info = NULL;
CFDictionaryRef parent_dict;
CFDictionaryRef props_dict;
CFDictionaryRef stats_dict;
io_registry_entry_t parent;
io_registry_entry_t disk;
io_iterator_t disk_list;
/* Get list of disks */
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(kIOMediaClass),
&disk_list) != kIOReturnSuccess) {
PyErr_SetString(PyExc_RuntimeError, "Unable to get the list of disks.");
goto error;
}
/* Iterate over disks */
while ((disk = IOIteratorNext(disk_list)) != 0) {
py_disk_info = NULL;
parent_dict = NULL;
props_dict = NULL;
stats_dict = NULL;
if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) != kIOReturnSuccess) {
PyErr_SetString(PyExc_RuntimeError, "Unable to get the disk's parent.");
IOObjectRelease(disk);
goto error;
}
if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
if(IORegistryEntryCreateCFProperties(
disk,
(CFMutableDictionaryRef *) &parent_dict,
kCFAllocatorDefault,
kNilOptions) != kIOReturnSuccess)
{
PyErr_SetString(PyExc_RuntimeError,
"Unable to get the parent's properties.");
IOObjectRelease(disk);
IOObjectRelease(parent);
goto error;
}
if (IORegistryEntryCreateCFProperties(parent,
(CFMutableDictionaryRef *) &props_dict,
kCFAllocatorDefault,
kNilOptions) != kIOReturnSuccess)
{
PyErr_SetString(PyExc_RuntimeError,
"Unable to get the disk properties.");
CFRelease(props_dict);
IOObjectRelease(disk);
IOObjectRelease(parent);
goto error;
}
const int kMaxDiskNameSize = 64;
CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue(
parent_dict,
CFSTR(kIOBSDNameKey));
char disk_name[kMaxDiskNameSize];
CFStringGetCString(disk_name_ref,
disk_name,
kMaxDiskNameSize,
CFStringGetSystemEncoding());
stats_dict = (CFDictionaryRef)CFDictionaryGetValue(
props_dict,
CFSTR(kIOBlockStorageDriverStatisticsKey));
if (stats_dict == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Unable to get disk stats.");
goto error;
}
CFNumberRef number;
int64_t reads, writes, read_bytes, write_bytes, read_time, write_time = 0;
/* Get disk reads/writes */
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsReadsKey))))
{
CFNumberGetValue(number, kCFNumberSInt64Type, &reads);
}
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsWritesKey))))
{
CFNumberGetValue(number, kCFNumberSInt64Type, &writes);
}
/* Get disk bytes read/written */
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey))))
{
CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes);
}
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey))))
{
CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes);
}
/* Get disk time spent reading/writing (nanoseconds) */
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey))))
{
CFNumberGetValue(number, kCFNumberSInt64Type, &read_time);
}
if ((number = (CFNumberRef)CFDictionaryGetValue(
stats_dict,
CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
CFNumberGetValue(number, kCFNumberSInt64Type, &write_time);
}
// Read/Write time on OS X comes back in nanoseconds and in psutil
// we've standardized on milliseconds so do the conversion.
py_disk_info = Py_BuildValue("(KKKKKK)",
reads, writes,
read_bytes, write_bytes,
read_time / 1000, write_time / 1000);
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
goto error;
Py_DECREF(py_disk_info);
CFRelease(parent_dict);
IOObjectRelease(parent);
CFRelease(props_dict);
IOObjectRelease(disk);
}
}
IOObjectRelease (disk_list);
return py_retdict;
error:
Py_XDECREF(py_disk_info);
Py_DECREF(py_retdict);
return NULL;
}
/*
* Return currently connected users as a list of tuples.
*/
static PyObject*
get_system_users(PyObject* self, PyObject* args)
{
PyObject *ret_list = PyList_New(0);
PyObject *tuple = NULL;
struct utmpx ut;
FILE *fp = NULL;
fp = fopen(_PATH_UTMPX, "r");
if (fp == NULL) {
// man fopen says errno is set but it seems it's not (OSX 10.6)
PyErr_SetFromErrnoWithFilename(PyExc_OSError, _PATH_UTMPX);
goto error;
}
while (fread(&ut, sizeof(ut), 1, fp) == 1) {
if (*ut.ut_user == '\0') {
continue;
}
#ifdef UTMPX_USER_PROCESS
if (ut.ut_type != UTMPX_USER_PROCESS) {
continue;
}
#endif
tuple = Py_BuildValue("(sssf)",
ut.ut_user, // username
ut.ut_line, // tty
ut.ut_host, // hostname
(float)ut.ut_tv.tv_sec // login time
);
if (!tuple)
goto error;
if (PyList_Append(ret_list, tuple))
goto error;
Py_DECREF(tuple);
}
fclose(fp);
return ret_list;
error:
Py_XDECREF(tuple);
Py_DECREF(ret_list);
if (fp != NULL)
fclose(fp);
return NULL;
}
/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] =
{
// --- per-process functions
{"get_process_name", get_process_name, METH_VARARGS,
"Return process name"},
{"get_process_cmdline", get_process_cmdline, METH_VARARGS,
"Return process cmdline as a list of cmdline arguments"},
{"get_process_exe", get_process_exe, METH_VARARGS,
"Return path of the process executable"},
{"get_process_cwd", get_process_cwd, METH_VARARGS,
"Return process current working directory."},
{"get_process_ppid", get_process_ppid, METH_VARARGS,
"Return process ppid as an integer"},
{"get_process_uids", get_process_uids, METH_VARARGS,
"Return process real user id as an integer"},
{"get_process_gids", get_process_gids, METH_VARARGS,
"Return process real group id as an integer"},
{"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
"Return tuple of user/kern time for the given PID"},
{"get_process_create_time", get_process_create_time, METH_VARARGS,
"Return a float indicating the process create time expressed in "
"seconds since the epoch"},
{"get_process_memory_info", get_process_memory_info, METH_VARARGS,
"Return memory information about a process"},
{"get_process_num_threads", get_process_num_threads, METH_VARARGS,
"Return number of threads used by process"},
{"get_process_status", get_process_status, METH_VARARGS,
"Return process status as an integer"},
{"get_process_threads", get_process_threads, METH_VARARGS,
"Return process threads as a list of tuples"},
{"get_process_open_files", get_process_open_files, METH_VARARGS,
"Return files opened by process as a list of tuples"},
{"get_process_num_fds", get_process_num_fds, METH_VARARGS,
"Return the number of fds opened by process."},
{"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS,
"Return the number of context switches performed by process"},
{"get_process_connections", get_process_connections, METH_VARARGS,
"Get process TCP and UDP connections as a list of tuples"},
{"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
"Return process tty number as an integer"},
{"get_process_memory_maps", get_process_memory_maps, METH_VARARGS,
"Return a list of tuples for every process's memory map"},
// --- system-related functions
{"get_pid_list", get_pid_list, METH_VARARGS,
"Returns a list of PIDs currently running on the system"},
{"get_num_cpus", get_num_cpus, METH_VARARGS,
"Return number of CPUs on the system"},
{"get_virtual_mem", get_virtual_mem, METH_VARARGS,
"Return system virtual memory stats"},
{"get_swap_mem", get_swap_mem, METH_VARARGS,
"Return stats about swap memory, in bytes"},
{"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
"Return system cpu times as a tuple (user, system, nice, idle, irc)"},
{"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
"Return system per-cpu times as a list of tuples"},
{"get_system_boot_time", get_system_boot_time, METH_VARARGS,
"Return a float indicating the system boot time expressed in "
"seconds since the epoch"},
{"get_disk_partitions", get_disk_partitions, METH_VARARGS,
"Return a list of tuples including device, mount point and "
"fs type for all partitions mounted on the system."},
{"get_network_io_counters", get_network_io_counters, METH_VARARGS,
"Return dict of tuples of networks I/O information."},
{"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
"Return dict of tuples of disks I/O information."},
{"get_system_users", get_system_users, METH_VARARGS,
"Return currently connected users as a list of tuples"},
{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)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_osx_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef
moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_osx",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_osx_traverse,
psutil_osx_clear,
NULL
};
#define INITERROR return NULL
PyObject *
PyInit__psutil_osx(void)
#else
#define INITERROR return
void
init_psutil_osx(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
#endif
// process status constants, defined in:
// http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
if (module == NULL) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
/*
* $Id: _psutil_osx.h 1498 2012-07-24 21:41:28Z g.rodola $
*
* 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.
*
* OS X platform-specific module methods for _psutil_osx
*/
#include <Python.h>
// --- per-process functions
static PyObject* get_process_name(PyObject* self, PyObject* args);
static PyObject* get_process_cmdline(PyObject* self, PyObject* args);
static PyObject* get_process_cwd(PyObject* self, PyObject* args);
static PyObject* get_process_exe(PyObject* self, PyObject* args);
static PyObject* get_process_ppid(PyObject* self, PyObject* args);
static PyObject* get_process_uids(PyObject* self, PyObject* args);
static PyObject* get_process_gids(PyObject* self, PyObject* args);
static PyObject* get_process_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_process_create_time(PyObject* self, PyObject* args);
static PyObject* get_process_memory_info(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
static PyObject* get_process_status(PyObject* self, PyObject* args);
static PyObject* get_process_threads(PyObject* self, PyObject* args);
static PyObject* get_process_open_files(PyObject* self, PyObject* args);
static PyObject* get_process_connections(PyObject* self, PyObject* args);
static PyObject* get_process_num_fds(PyObject* self, PyObject* args);
static PyObject* get_process_tty_nr(PyObject* self, PyObject* args);
static PyObject* get_process_memory_maps(PyObject* self, PyObject* args);
// --- system-related functions
static PyObject* get_pid_list(PyObject* self, PyObject* args);
static PyObject* get_num_cpus(PyObject* self, PyObject* args);
static PyObject* get_virtual_mem(PyObject* self, PyObject* args);
static PyObject* get_swap_mem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_system_boot_time(PyObject* self, PyObject* args);
static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
static PyObject* get_network_io_counters(PyObject* self, PyObject* args);
static PyObject* get_disk_io_counters(PyObject* self, PyObject* args);
static PyObject* get_system_users(PyObject* self, PyObject* args);
/*
* $Id: _psutil_posix.c 1223 2011-11-09 23:47:55Z g.rodola $
*
* 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.
*
* Functions specific to all POSIX compliant platforms.
*/
#include <Python.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/resource.h>
#include "_psutil_posix.h"
/*
* Given a PID return process priority as a Python integer.
*/
static PyObject*
posix_getpriority(PyObject* self, PyObject* args)
{
long pid;
int priority;
errno = 0;
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
priority = getpriority(PRIO_PROCESS, pid);
if (errno != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return Py_BuildValue("i", priority);
}
/*
* Given a PID and a value change process priority.
*/
static PyObject*
posix_setpriority(PyObject* self, PyObject* args)
{
long pid;
int priority;
int retval;
if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
return NULL;
}
retval = setpriority(PRIO_PROCESS, pid, priority);
if (retval == -1) {
return PyErr_SetFromErrno(PyExc_OSError);
}
Py_INCREF(Py_None);
return Py_None;
}
/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] =
{
{"getpriority", posix_getpriority, METH_VARARGS,
"Return process priority"},
{"setpriority", posix_setpriority, METH_VARARGS,
"Set process priority"},
{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)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_posix_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef
moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_posix",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_posix_traverse,
psutil_posix_clear,
NULL
};
#define INITERROR return NULL
PyObject *
PyInit__psutil_posix(void)
#else
#define INITERROR return
void init_psutil_posix(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
#endif
if (module == NULL) {
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
/*
* $Id: _psutil_posix.h 1223 2011-11-09 23:47:55Z g.rodola $
*
* 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.
*
* POSIX specific module methods for _psutil_posix
*/
#include <Python.h>
static PyObject* posix_getpriority(PyObject* self, PyObject* args);
static PyObject* posix_setpriority(PyObject* self, PyObject* args);
/*
* $Id: process_info.c 1462 2012-07-18 03:12:08Z g.rodola $
*
* 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.
*
* Helper functions related to fetching process information. Used by _psutil_bsd
* module methods.
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <signal.h>
#include "process_info.h"
/*
* Returns a list of all BSD processes on the system. This routine
* allocates the list and puts it in *procList and a count of the
* number of entries in *procCount. You are responsible for freeing
* this list (use "free" from System framework).
* On success, the function returns 0.
* On error, the function returns a BSD errno value.
*/
int
get_proc_list(struct kinfo_proc **procList, size_t *procCount)
{
int err;
struct kinfo_proc * result;
int done;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
// Declaring name as const requires us to cast it when passing it to
// sysctl because the prototype doesn't include the const modifier.
size_t length;
assert( procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
*procCount = 0;
/*
* We start by calling sysctl with result == NULL and length == 0.
* That will succeed, and set length to the appropriate length.
* We then allocate a buffer of that size and call sysctl again
* with that buffer. If that succeeds, we're done. If that fails
* with ENOMEM, we have to throw away our buffer and loop. Note
* that the loop causes use to call sysctl with NULL again; this
* is necessary because the ENOMEM failure case sets length to
* the amount of data returned, not the amount of data that
* could have been returned.
*/
result = NULL;
done = 0;
do {
assert(result == NULL);
// Call sysctl with a NULL buffer.
length = 0;
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1,
NULL, &length, NULL, 0);
if (err == -1)
err = errno;
// Allocate an appropriately sized buffer based on the results
// from the previous call.
if (err == 0) {
result = malloc(length);
if (result == NULL)
err = ENOMEM;
}
// Call sysctl again with the new buffer. If we get an ENOMEM
// error, toss away our buffer and start again.
if (err == 0) {
err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
result, &length, NULL, 0);
if (err == -1)
err = errno;
if (err == 0) {
done = 1;
}
else if (err == ENOMEM) {
assert(result != NULL);
free(result);
result = NULL;
err = 0;
}
}
} while (err == 0 && ! done);
// Clean up and establish post conditions.
if (err != 0 && result != NULL) {
free(result);
result = NULL;
}
*procList = result;
*procCount = length / sizeof(struct kinfo_proc);
assert((err == 0) == (*procList != NULL));
return err;
}
char
*getcmdpath(long pid, size_t *pathsize)
{
int mib[4];
char *path;
size_t size = 0;
/*
* Make a sysctl() call to get the raw argument space of the process.
*/
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = pid;
// call with a null buffer first to determine if we need a buffer
if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) {
return NULL;
}
path = malloc(size);
if (path == NULL) {
PyErr_SetString(PyExc_MemoryError, "couldn't allocate memory");
return NULL;
}
*pathsize = size;
if (sysctl(mib, 4, path, &size, NULL, 0) == -1) {
free(path);
return NULL; /* Insufficient privileges */
}
return path;
}
/*
* Borrowed from psi Python System Information project
*
* Get command arguments and environment variables.
*
* Based on code from ps.
*
* Returns:
* 0 for success;
* -1 for failure (Exception raised);
* 1 for insufficient privileges.
*/
char
*getcmdargs(long pid, size_t *argsize)
{
int mib[4];
size_t size, argmax;
char *procargs = NULL;
/* Get the maximum process arguments size. */
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
return NULL;
/* Allocate space for the arguments. */
procargs = (char *)malloc(argmax);
if (procargs == NULL) {
PyErr_SetString(PyExc_MemoryError, "couldn't allocate memory");
return NULL;
}
/*
* Make a sysctl() call to get the raw argument space of the process.
*/
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_ARGS;
mib[3] = pid;
size = argmax;
if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) {
free(procargs);
return NULL; /* Insufficient privileges */
}
// return string and set the length of arguments
*argsize = size;
return procargs;
}
/* returns the command line as a python list object */
PyObject*
get_arg_list(long pid)
{
char *argstr = NULL;
int pos = 0;
size_t argsize = 0;
PyObject *retlist = Py_BuildValue("[]");
PyObject *item = NULL;
if (pid < 0) {
return retlist;
}
argstr = getcmdargs(pid, &argsize);
if (argstr == NULL) {
goto error;
}
// args are returned as a flattened string with \0 separators between
// arguments add each string to the list then step forward to the next
// separator
if (argsize > 0) {
while(pos < argsize) {
item = Py_BuildValue("s", &argstr[pos]);
if (!item)
goto error;
if (PyList_Append(retlist, item))
goto error;
Py_DECREF(item);
pos = pos + strlen(&argstr[pos]) + 1;
}
}
free(argstr);
return retlist;
error:
Py_XDECREF(item);
Py_DECREF(retlist);
if (argstr != NULL)
free(argstr);
return NULL;
}
/*
* Return 1 if PID exists in the current process list, else 0.
*/
int
pid_exists(long pid)
{
int kill_ret;
if (pid < 0) {
return 0;
}
// if kill returns success of permission denied we know it's a valid PID
kill_ret = kill(pid , 0);
if ((0 == kill_ret) || (EPERM == errno)) {
return 1;
}
// otherwise return 0 for PID not found
return 0;
}
/*
* $Id: process_info.h 1142 2011-10-05 18:45:49Z g.rodola $
*
* 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.
*
* Helper functions related to fetching process information. Used by _psutil_bsd
* module methods.
*/
#include <Python.h>
typedef struct kinfo_proc kinfo_proc;
int get_proc_list(struct kinfo_proc **procList, size_t *procCount);
char *getcmdargs(long pid, size_t *argsize);
char *getcmdpath(long pid, size_t *pathsize);
PyObject* get_arg_list(long pid);
int pid_exists(long pid);
/*
* $Id: ntextapi.h 1452 2012-07-13 19:02:07Z g.rodola $
*
* 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.
*
*/
typedef enum _KTHREAD_STATE
{
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition,
DeferredReady,
GateWait,
MaximumThreadState
} KTHREAD_STATE, *PKTHREAD_STATE;
typedef enum _KWAIT_REASON
{
Executive = 0,
FreePage = 1,
PageIn = 2,
PoolAllocation = 3,
DelayExecution = 4,
Suspended = 5,
UserRequest = 6,
WrExecutive = 7,
WrFreePage = 8,
WrPageIn = 9,
WrPoolAllocation = 10,
WrDelayExecution = 11,
WrSuspended = 12,
WrUserRequest = 13,
WrEventPair = 14,
WrQueue = 15,
WrLpcReceive = 16,
WrLpcReply = 17,
WrVirtualMemory = 18,
WrPageOut = 19,
WrRendezvous = 20,
Spare2 = 21,
Spare3 = 22,
Spare4 = 23,
Spare5 = 24,
WrCalloutStack = 25,
WrKernel = 26,
WrResource = 27,
WrPushLock = 28,
WrMutex = 29,
WrQuantumEnd = 30,
WrDispatchInt = 31,
WrPreempted = 32,
WrYieldExecution = 33,
WrFastMutex = 34,
WrGuardedMutex = 35,
WrRundown = 36,
MaximumWaitReason = 37
} KWAIT_REASON, *PKWAIT_REASON;
typedef struct _CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _SYSTEM_TIMEOFDAY_INFORMATION
{
LARGE_INTEGER BootTime;
LARGE_INTEGER CurrentTime;
LARGE_INTEGER TimeZoneBias;
ULONG TimeZoneId;
ULONG Reserved;
ULONGLONG BootTimeBias;
ULONGLONG SleepTimeBias;
} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION;
typedef struct _SYSTEM_THREAD_INFORMATION
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
LONG Priority;
LONG BasePriority;
ULONG ContextSwitches;
ULONG ThreadState;
KWAIT_REASON WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef struct _TEB *PTEB;
// private
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION
{
SYSTEM_THREAD_INFORMATION ThreadInfo;
PVOID StackBase;
PVOID StackLimit;
PVOID Win32StartAddress;
PTEB TebBase;
ULONG_PTR Reserved2;
ULONG_PTR Reserved3;
ULONG_PTR Reserved4;
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
typedef struct _SYSTEM_PROCESS_INFORMATION
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
LARGE_INTEGER SpareLi2;
LARGE_INTEGER SpareLi3;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
LONG BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
DWORD PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
SYSTEM_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
// structures and enums from winternl.h (not available under mingw)
typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation = 0,
SystemPerformanceInformation = 2,
SystemTimeOfDayInformation = 3,
SystemProcessInformation = 5,
SystemProcessorPerformanceInformation = 8,
SystemInterruptInformation = 23,
SystemExceptionInformation = 33,
SystemRegistryQuotaInformation = 37,
SystemLookasideInformation = 45
} SYSTEM_INFORMATION_CLASS;
// ================================================
// get_system_users support ()
// ================================================
typedef struct _WINSTATION_INFO {
BYTE Reserved1[72];
ULONG SessionId;
BYTE Reserved2[4];
FILETIME ConnectTime;
FILETIME DisconnectTime;
FILETIME LastInputTime;
FILETIME LoginTime;
BYTE Reserved3[1096];
FILETIME CurrentTime;
} WINSTATION_INFO, *PWINSTATION_INFO;
typedef enum _WINSTATIONINFOCLASS {
WinStationInformation = 8
} WINSTATIONINFOCLASS;
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
typedef struct _WINSTATIONINFORMATIONW {
BYTE Reserved2[70];
ULONG LogonId;
BYTE Reserved3[1140];
} WINSTATIONINFORMATIONW, *PWINSTATIONINFORMATIONW;
// start mingw support:
// http://www.koders.com/c/fid7C02CAE627C526914CDEB427405B51DF393A5EFA.aspx
#ifndef _INC_WTSAPI
typedef struct _WTS_CLIENT_ADDRESS {
DWORD AddressFamily; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC
BYTE Address[20]; // client network address
} WTS_CLIENT_ADDRESS, * PWTS_CLIENT_ADDRESS;
HANDLE
WINAPI
WTSOpenServerA(
IN LPSTR pServerName
);
VOID
WINAPI
WTSCloseServer(
IN HANDLE hServer
);
#endif
/*
* $Id: process_handles.c 1463 2012-07-18 13:06:49Z g.rodola $
*
* 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.
*
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <Python.h>
#include <windows.h>
#include <stdio.h>
#include "process_handles.h"
#ifndef NT_SUCCESS
#define NT_SUCCESS(x) ((x) >= 0)
#endif
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
#define SystemHandleInformation 16
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2
typedef LONG NTSTATUS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef NTSTATUS (NTAPI *_NtDuplicateObject)(
HANDLE SourceProcessHandle,
HANDLE SourceHandle,
HANDLE TargetProcessHandle,
PHANDLE TargetHandle,
ACCESS_MASK DesiredAccess,
ULONG Attributes,
ULONG Options
);
typedef NTSTATUS (NTAPI *_NtQueryObject)(
HANDLE ObjectHandle,
ULONG ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_HANDLE
{
ULONG ProcessId;
BYTE ObjectTypeNumber;
BYTE Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG HandleCount;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef enum _POOL_TYPE
{
NonPagedPool,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS
} POOL_TYPE, *PPOOL_TYPE;
typedef struct _OBJECT_TYPE_INFORMATION
{
UNICODE_STRING Name;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
USHORT MaintainTypeList;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
{
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
}
PyObject*
get_open_files(long pid, HANDLE processHandle)
{
_NtQuerySystemInformation NtQuerySystemInformation =
GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation");
_NtDuplicateObject NtDuplicateObject =
GetLibraryProcAddress("ntdll.dll", "NtDuplicateObject");
_NtQueryObject NtQueryObject =
GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION handleInfo;
ULONG handleInfoSize = 0x10000;
ULONG i;
ULONG fileNameLength;
PyObject *filesList = Py_BuildValue("[]");
PyObject *arg = NULL;
PyObject *fileFromWchar = NULL;
handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);
/* NtQuerySystemInformation won't give us the correct buffer size,
so we guess by doubling the buffer size. */
while ((status = NtQuerySystemInformation(
SystemHandleInformation,
handleInfo,
handleInfoSize,
NULL
)) == STATUS_INFO_LENGTH_MISMATCH)
{
handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);
}
/* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */
if (!NT_SUCCESS(status)) {
//printf("NtQuerySystemInformation failed!\n");
Py_DECREF(filesList);
free(handleInfo);
return NULL;
}
for (i = 0; i < handleInfo->HandleCount; i++)
{
SYSTEM_HANDLE handle = handleInfo->Handles[i];
HANDLE dupHandle = NULL;
POBJECT_TYPE_INFORMATION objectTypeInfo = NULL;
PVOID objectNameInfo;
UNICODE_STRING objectName;
ULONG returnLength;
fileFromWchar = NULL;
arg = NULL;
/* Check if this handle belongs to the PID the user specified. */
if (handle.ProcessId != pid)
continue;
/* Skip handles with the following access codes as the next call
to NtDuplicateObject() or NtQueryObject() might hang forever. */
if((handle.GrantedAccess == 0x0012019f)
|| (handle.GrantedAccess == 0x001a019f)
|| (handle.GrantedAccess == 0x00120189)
|| (handle.GrantedAccess == 0x00100000)) {
continue;
}
/* Duplicate the handle so we can query it. */
if (!NT_SUCCESS(NtDuplicateObject(
processHandle,
handle.Handle,
GetCurrentProcess(),
&dupHandle,
0,
0,
0
)))
{
//printf("[%#x] Error!\n", handle.Handle);
continue;
}
/* Query the object type. */
objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
if (!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectTypeInformation,
objectTypeInfo,
0x1000,
NULL
)))
{
//printf("[%#x] Error!\n", handle.Handle);
free(objectTypeInfo);
CloseHandle(dupHandle);
continue;
}
objectNameInfo = malloc(0x1000);
if (!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectNameInformation,
objectNameInfo,
0x1000,
&returnLength
)))
{
/* Reallocate the buffer and try again. */
objectNameInfo = realloc(objectNameInfo, returnLength);
if (!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectNameInformation,
objectNameInfo,
returnLength,
NULL
)))
{
/* We have the type name, so just display that.*/
/*
printf(
"[%#x] %.*S: (could not get name)\n",
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
*/
free(objectTypeInfo);
free(objectNameInfo);
CloseHandle(dupHandle);
continue;
}
}
/* Cast our buffer into an UNICODE_STRING. */
objectName = *(PUNICODE_STRING)objectNameInfo;
/* Print the information! */
if (objectName.Length)
{
/* The object has a name. Make sure it is a file otherwise
ignore it */
fileNameLength = objectName.Length / 2;
if (wcscmp(objectTypeInfo->Name.Buffer, L"File") == 0) {
//printf("%.*S\n", objectName.Length / 2, objectName.Buffer);
fileFromWchar = PyUnicode_FromWideChar(objectName.Buffer,
fileNameLength);
if (fileFromWchar == NULL)
goto error_py_fun;
#if PY_MAJOR_VERSION >= 3
arg = Py_BuildValue("N", PyUnicode_AsUTF8String(fileFromWchar));
#else
arg = Py_BuildValue("N", PyUnicode_FromObject(fileFromWchar));
#endif
if (!arg)
goto error_py_fun;
Py_XDECREF(fileFromWchar);
fileFromWchar = NULL;
if (PyList_Append(filesList, arg))
goto error_py_fun;
Py_XDECREF(arg);
}
/*
printf(
"[%#x] %.*S: %.*S\n",
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer,
objectName.Length / 2,
objectName.Buffer
);
*/
}
else
{
/* Print something else. */
/*
printf(
"[%#x] %.*S: (unnamed)\n",
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
*/
;;
}
free(objectTypeInfo);
free(objectNameInfo);
CloseHandle(dupHandle);
}
free(handleInfo);
CloseHandle(processHandle);
return filesList;
error_py_fun:
Py_XDECREF(arg);
Py_XDECREF(fileFromWchar);
Py_DECREF(filesList);
return NULL;
}
/*
* $Id: process_info.h 1060 2011-07-02 18:05:26Z g.rodola $
*
* 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.
*/
#include <Python.h>
#include <windows.h>
PyObject* get_open_files(long pid, HANDLE processHandle);
/*
* $Id: process_info.c 1463 2012-07-18 13:06:49Z g.rodola $
*
* 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.
*
* Helper functions related to fetching process information. Used by
* _psutil_mswindows module methods.
*/
#include <Python.h>
#include <windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include "security.h"
#include "process_info.h"
#include "ntextapi.h"
/*
* NtQueryInformationProcess code taken from
* http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
* typedefs needed to compile against ntdll functions not exposted in the API
*/
typedef LONG NTSTATUS;
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength,
PDWORD ReturnLength
);
typedef struct _PROCESS_BASIC_INFORMATION
{
PVOID Reserved1;
PVOID PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
/*
* A wrapper around OpenProcess setting NSP exception if process
* no longer exists.
* "pid" is the process pid, "dwDesiredAccess" is the first argument
* exptected by OpenProcess.
* Return a process handle or NULL.
*/
HANDLE
handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess)
{
HANDLE hProcess;
DWORD processExitCode = 0;
if (pid == 0) {
// otherwise we'd get NoSuchProcess
return AccessDenied();
}
hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
if (hProcess == NULL) {
if (GetLastError() == ERROR_INVALID_PARAMETER) {
NoSuchProcess();
}
else {
PyErr_SetFromWindowsErr(0);
}
return NULL;
}
/* make sure the process is running */
GetExitCodeProcess(hProcess, &processExitCode);
if (processExitCode == 0) {
NoSuchProcess();
CloseHandle(hProcess);
return NULL;
}
return hProcess;
}
/*
* Same as handle_from_pid_waccess but implicitly uses
* PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as dwDesiredAccess
* parameter for OpenProcess.
*/
HANDLE
handle_from_pid(DWORD pid) {
DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
return handle_from_pid_waccess(pid, dwDesiredAccess);
}
// fetch the PEB base address from NtQueryInformationProcess()
PVOID
GetPebAddress(HANDLE ProcessHandle)
{
_NtQueryInformationProcess NtQueryInformationProcess =
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION pbi;
NtQueryInformationProcess(ProcessHandle, 0, &pbi, sizeof(pbi), NULL);
return pbi.PebBaseAddress;
}
DWORD*
get_pids(DWORD *numberOfReturnedPIDs) {
/* Win32 SDK says the only way to know if our process array
* wasn't large enough is to check the returned size and make
* sure that it doesn't match the size of the array.
* If it does we allocate a larger array and try again */
// Stores the actual array
DWORD *procArray = NULL;
DWORD procArrayByteSz;
int procArraySz = 0;
// Stores the byte size of the returned array from enumprocesses
DWORD enumReturnSz = 0;
do {
procArraySz += 1024;
free(procArray);
procArrayByteSz = procArraySz * sizeof(DWORD);
procArray = malloc(procArrayByteSz);
if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) {
free(procArray);
PyErr_SetFromWindowsErr(0);
return NULL;
}
} while(enumReturnSz == procArraySz * sizeof(DWORD));
// The number of elements is the returned size / size of each element
*numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD);
return procArray;
}
int
pid_is_running(DWORD pid)
{
HANDLE hProcess;
DWORD exitCode;
// Special case for PID 0 System Idle Process
if (pid == 0) {
return 1;
}
if (pid < 0) {
return 0;
}
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
if (NULL == hProcess) {
// invalid parameter is no such process
if (GetLastError() == ERROR_INVALID_PARAMETER) {
CloseHandle(hProcess);
return 0;
}
// access denied obviously means there's a process to deny access to...
if (GetLastError() == ERROR_ACCESS_DENIED) {
CloseHandle(hProcess);
return 1;
}
CloseHandle(hProcess);
PyErr_SetFromWindowsErr(0);
return -1;
}
if (GetExitCodeProcess(hProcess, &exitCode)) {
CloseHandle(hProcess);
return (exitCode == STILL_ACTIVE);
}
// access denied means there's a process there so we'll assume it's running
if (GetLastError() == ERROR_ACCESS_DENIED) {
CloseHandle(hProcess);
return 1;
}
PyErr_SetFromWindowsErr(0);
CloseHandle(hProcess);
return -1;
}
int
pid_in_proclist(DWORD pid)
{
DWORD *proclist = NULL;
DWORD numberOfReturnedPIDs;
DWORD i;
proclist = get_pids(&numberOfReturnedPIDs);
if (NULL == proclist) {
return -1;
}
for (i = 0; i < numberOfReturnedPIDs; i++) {
if (pid == proclist[i]) {
free(proclist);
return 1;
}
}
free(proclist);
return 0;
}
// Check exit code from a process handle. Return FALSE on an error also
BOOL is_running(HANDLE hProcess)
{
DWORD dwCode;
if (NULL == hProcess) {
return FALSE;
}
if (GetExitCodeProcess(hProcess, &dwCode)) {
return (dwCode == STILL_ACTIVE);
}
return FALSE;
}
// Return None to represent NoSuchProcess, else return NULL for
// other exception or the name as a Python string
PyObject*
get_name(long pid)
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
if( Process32First(h, &pe)) {
do {
if (pe.th32ProcessID == pid) {
CloseHandle(h);
return Py_BuildValue("s", pe.szExeFile);
}
} while(Process32Next(h, &pe));
// the process was never found, set NoSuchProcess exception
NoSuchProcess();
CloseHandle(h);
return NULL;
}
CloseHandle(h);
return PyErr_SetFromWindowsErr(0);
}
/* returns parent pid (as a Python int) for given pid or None on failure */
PyObject*
get_ppid(long pid)
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
if( Process32First(h, &pe)) {
do {
if (pe.th32ProcessID == pid) {
CloseHandle(h);
return Py_BuildValue("I", pe.th32ParentProcessID);
}
} while(Process32Next(h, &pe));
// the process was never found, set NoSuchProcess exception
NoSuchProcess();
CloseHandle(h);
return NULL;
}
CloseHandle(h);
return PyErr_SetFromWindowsErr(0);
}
/*
* returns a Python list representing the arguments for the process
* with given pid or NULL on error.
*/
PyObject*
get_arg_list(long pid)
{
int nArgs, i;
LPWSTR *szArglist = NULL;
HANDLE hProcess = NULL;
PVOID pebAddress;
PVOID rtlUserProcParamsAddress;
UNICODE_STRING commandLine;
WCHAR *commandLineContents = NULL;
PyObject *arg = NULL;
PyObject *arg_from_wchar = NULL;
PyObject *argList = NULL;
hProcess = handle_from_pid(pid);
if(hProcess == NULL) {
return NULL;
}
pebAddress = GetPebAddress(hProcess);
/* get the address of ProcessParameters */
#ifdef _WIN64
if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 32,
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
#else
if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 0x10,
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
#endif
{
////printf("Could not read the address of ProcessParameters!\n");
PyErr_SetFromWindowsErr(0);
goto error;
}
/* read the CommandLine UNICODE_STRING structure */
#ifdef _WIN64
if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 112,
&commandLine, sizeof(commandLine), NULL))
#else
if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x40,
&commandLine, sizeof(commandLine), NULL))
#endif
{
////printf("Could not read CommandLine!\n");
PyErr_SetFromWindowsErr(0);
goto error;
}
/* allocate memory to hold the command line */
commandLineContents = (WCHAR *)malloc(commandLine.Length+1);
/* read the command line */
if (!ReadProcessMemory(hProcess, commandLine.Buffer,
commandLineContents, commandLine.Length, NULL))
{
////printf("Could not read the command line string!\n");
PyErr_SetFromWindowsErr(0);
goto error;
}
/* print the commandline */
////printf("%.*S\n", commandLine.Length / 2, commandLineContents);
// null-terminate the string to prevent wcslen from returning incorrect length
// the length specifier is in characters, but commandLine.Length is in bytes
commandLineContents[(commandLine.Length/sizeof(WCHAR))] = '\0';
// attemempt tp parse the command line using Win32 API, fall back on string
// cmdline version otherwise
szArglist = CommandLineToArgvW(commandLineContents, &nArgs);
if (NULL == szArglist) {
// failed to parse arglist
// encode as a UTF8 Python string object from WCHAR string
arg_from_wchar = PyUnicode_FromWideChar(commandLineContents,
commandLine.Length / 2);
if (arg_from_wchar == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
argList = Py_BuildValue("N", PyUnicode_AsUTF8String(arg_from_wchar));
#else
argList = Py_BuildValue("N", PyUnicode_FromObject(arg_from_wchar));
#endif
if (!argList)
goto error;
}
else {
// arglist parsed as array of UNICODE_STRING, so convert each to Python
// string object and add to arg list
argList = Py_BuildValue("[]");
if (!argList)
goto error;
for(i=0; i<nArgs; i++) {
arg_from_wchar = NULL;
arg = NULL;
////printf("%d: %.*S (%d characters)\n", i, wcslen(szArglist[i]),
// szArglist[i], wcslen(szArglist[i]));
arg_from_wchar = PyUnicode_FromWideChar(szArglist[i],
wcslen(szArglist[i])
);
if (arg_from_wchar == NULL)
goto error;
#if PY_MAJOR_VERSION >= 3
arg = PyUnicode_FromObject(arg_from_wchar);
#else
arg = PyUnicode_AsUTF8String(arg_from_wchar);
#endif
if (arg == NULL)
goto error;
Py_XDECREF(arg_from_wchar);
if (PyList_Append(argList, arg))
goto error;
Py_XDECREF(arg);
}
}
if (szArglist != NULL)
LocalFree(szArglist);
free(commandLineContents);
CloseHandle(hProcess);
return argList;
error:
Py_XDECREF(arg);
Py_XDECREF(arg_from_wchar);
Py_XDECREF(argList);
if (hProcess != NULL)
CloseHandle(hProcess);
if (commandLineContents != NULL)
free(commandLineContents);
if (szArglist != NULL)
LocalFree(szArglist);
return NULL;
}
#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))
#define PH_NEXT_PROCESS(Process) ( \
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \
NULL \
)
const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
const STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
/*
* Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
* fills the structure with process information.
* On success return 1, else 0 with Python exception already set.
*/
int
get_process_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer)
{
static ULONG initialBufferSize = 0x4000;
NTSTATUS status;
PVOID buffer;
ULONG bufferSize;
PSYSTEM_PROCESS_INFORMATION process;
// get NtQuerySystemInformation
typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG);
NTQSI_PROC NtQuerySystemInformation;
HINSTANCE hNtDll;
hNtDll = LoadLibrary(TEXT("ntdll.dll"));
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
hNtDll, "NtQuerySystemInformation");
bufferSize = initialBufferSize;
buffer = malloc(bufferSize);
while (TRUE) {
status = NtQuerySystemInformation(SystemProcessInformation, buffer,
bufferSize, &bufferSize);
if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
{
free(buffer);
buffer = malloc(bufferSize);
}
else {
break;
}
}
if (status != 0) {
PyErr_Format(PyExc_RuntimeError, "NtQuerySystemInformation() failed");
FreeLibrary(hNtDll);
free(buffer);
return 0;
}
if (bufferSize <= 0x20000) {
initialBufferSize = bufferSize;
}
process = PH_FIRST_PROCESS(buffer);
do {
if (process->UniqueProcessId == (HANDLE)pid) {
*retProcess = process;
*retBuffer = buffer;
return 1;
}
} while ( (process = PH_NEXT_PROCESS(process)) );
NoSuchProcess();
FreeLibrary(hNtDll);
free(buffer);
return 0;
}
/*
* $Id: process_info.h 1142 2011-10-05 18:45:49Z g.rodola $
*
* 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.
*
* Helper functions related to fetching process information. Used by _psutil_mswindows
* module methods.
*/
#include <Python.h>
#include <windows.h>
HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
HANDLE handle_from_pid(DWORD pid);
PVOID GetPebAddress(HANDLE ProcessHandle);
HANDLE handle_from_pid(DWORD pid);
BOOL is_running(HANDLE hProcess);
int pid_in_proclist(DWORD pid);
int pid_is_running(DWORD pid);
PyObject* get_arg_list(long pid);
PyObject* get_ppid(long pid);
PyObject* get_name(long pid);
DWORD* get_pids(DWORD *numberOfReturnedPIDs);
/*
* $Id: security.c 1296 2012-04-25 01:29:43Z david.daeschler@gmail.com $
*
* 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.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
*/
#include <windows.h>
#include <Python.h>
/*
* Convert a process handle to a process token handle.
*/
HANDLE
token_from_handle(HANDLE hProcess) {
HANDLE hToken = NULL;
if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken) ) {
return PyErr_SetFromWindowsErr(0);
}
return hToken;
}
/*
* http://www.ddj.com/windows/184405986
*
* There's a way to determine whether we're running under the Local System
* account. However (you guessed it), we have to call more Win32 functions to
* determine this. Backing up through the code listing, we need to make another
* call to GetTokenInformation, but instead of passing through the TOKEN_USER
* constant, we pass through the TOKEN_PRIVILEGES constant. This value returns
* an array of privileges that the account has in the environment. Iterating
* through the array, we call the function LookupPrivilegeName looking for the
* string SeTcbPrivilege. If the function returns this string, then this
* account has Local System privileges
*/
int HasSystemPrivilege(HANDLE hProcess) {
DWORD i;
DWORD dwSize = 0;
DWORD dwRetval = 0;
TCHAR privName[256];
DWORD dwNameSize = 256;
//PTOKEN_PRIVILEGES tp = NULL;
BYTE *pBuffer = NULL;
TOKEN_PRIVILEGES* tp = NULL;
HANDLE hToken = token_from_handle(hProcess);
if (NULL == hToken) {
return -1;
}
// call GetTokenInformation first to get the buffer size
if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) {
dwRetval = GetLastError();
// if it failed for a reason other than the buffer, bail out
if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) {
PyErr_SetFromWindowsErr(dwRetval);
return 0;
}
}
// allocate buffer and call GetTokenInformation again
//tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize);
pBuffer = (BYTE *) malloc(dwSize);
if (pBuffer == NULL) {
PyErr_SetFromWindowsErr(0);
free(pBuffer);
return -1;
}
if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer, dwSize, &dwSize) ) {
PyErr_SetFromWindowsErr(0);
free(pBuffer);
return -1;
}
// convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer
tp = (TOKEN_PRIVILEGES*)pBuffer;
// check all the privileges looking for SeTcbPrivilege
for(i=0; i < tp->PrivilegeCount; i++) {
// reset the buffer contents and the buffer size
strcpy(privName, "");
dwNameSize = sizeof(privName) / sizeof(TCHAR);
if (! LookupPrivilegeName(NULL,
&tp->Privileges[i].Luid,
(LPTSTR)privName,
&dwNameSize)) {
PyErr_SetFromWindowsErr(0);
free(pBuffer);
return -1;
}
// if we find the SeTcbPrivilege then it's a LocalSystem process
if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) {
free(pBuffer);
return 1;
}
} //for
free(pBuffer);
return 0;
}
BOOL SetPrivilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
// first pass. get current privilege setting
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
// second pass. set privilege based on previous setting
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege) {
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
}
else {
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
}
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
return TRUE;
}
int SetSeDebug()
{
HANDLE hToken;
if(! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
){
if (GetLastError() == ERROR_NO_TOKEN){
if (!ImpersonateSelf(SecurityImpersonation)){
CloseHandle(hToken);
return 0;
}
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
){
RevertToSelf();
CloseHandle(hToken);
return 0;
}
}
}
// enable SeDebugPrivilege (open any process)
if (! SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)){
RevertToSelf();
CloseHandle(hToken);
return 0;
}
RevertToSelf();
CloseHandle(hToken);
return 1;
}
int UnsetSeDebug()
{
HANDLE hToken;
if(! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
){
if(GetLastError() == ERROR_NO_TOKEN){
if(! ImpersonateSelf(SecurityImpersonation)){
//Log2File("Error setting impersonation! [UnsetSeDebug()]", L_DEBUG);
return 0;
}
if(!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
){
//Log2File("Error Opening Thread Token! [UnsetSeDebug()]", L_DEBUG);
return 0;
}
}
}
//now disable SeDebug
if(!SetPrivilege(hToken, SE_DEBUG_NAME, FALSE)){
//Log2File("Error unsetting SeDebug Privilege [SetPrivilege()]", L_WARN);
return 0;
}
CloseHandle(hToken);
return 1;
}
/*
* $Id: security.h 1142 2011-10-05 18:45:49Z g.rodola $
*
* 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.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
*/
#include <windows.h>
BOOL SetPrivilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege);
int SetSeDebug();
int UnsetSeDebug();
HANDLE token_from_handle(HANDLE hProcess);
int HasSystemPrivilege(HANDLE hProcess);
/*
* $Id: process_info.c 1460 2012-07-18 02:49:24Z g.rodola@gmail.com $
*
* 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.
*
* Helper functions related to fetching process information. Used by _psutil_osx
* module methods.
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <limits.h> /* for INT_MAX */
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/sysctl.h>
#include <libproc.h>
#include "process_info.h"
#include "../../_psutil_common.h"
/*
* Return 1 if PID exists in the current process list, else 0.
*/
int
pid_exists(long pid)
{
int kill_ret;
// save some time if it's an invalid PID
if (pid < 0) {
return 0;
}
// if kill returns success of permission denied we know it's a valid PID
kill_ret = kill(pid , 0);
if ( (0 == kill_ret) || (EPERM == errno) ) {
return 1;
}
// otherwise return 0 for PID not found
return 0;
}
/*
* Returns a list of all BSD processes on the system. This routine
* allocates the list and puts it in *procList and a count of the
* number of entries in *procCount. You are responsible for freeing
* this list (use "free" from System framework).
* On success, the function returns 0.
* On error, the function returns a BSD errno value.
*/
int
get_proc_list(kinfo_proc **procList, size_t *procCount)
{
/* Declaring mib as const requires use of a cast since the
* sysctl prototype doesn't include the const modifier. */
static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t size, size2;
void *ptr;
int err, lim = 8; /* some limit */
assert( procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
*procCount = 0;
/* We start by calling sysctl with ptr == NULL and size == 0.
* That will succeed, and set size to the appropriate length.
* We then allocate a buffer of at least that size and call
* sysctl with that buffer. If that succeeds, we're done.
* If that call fails with ENOMEM, we throw the buffer away
* and try again.
* Note that the loop calls sysctl with NULL again. This is
* is necessary because the ENOMEM failure case sets size to
* the amount of data returned, not the amount of data that
* could have been returned.
*/
while (lim-- > 0) {
size = 0;
if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) {
return errno;
}
size2 = size + (size >> 3); /* add some */
if (size2 > size) {
ptr = malloc(size2);
if (ptr == NULL) {
ptr = malloc(size);
} else {
size = size2;
}
}
else {
ptr = malloc(size);
}
if (ptr == NULL) {
return ENOMEM;
}
if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) {
err = errno;
free(ptr);
if (err != ENOMEM) {
return err;
}
} else {
*procList = (kinfo_proc *)ptr;
*procCount = size / sizeof(kinfo_proc);
return 0;
}
}
return ENOMEM;
}
/* Read the maximum argument size for processes */
int
get_argmax()
{
int argmax;
int mib[] = { CTL_KERN, KERN_ARGMAX };
size_t size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) {
return argmax;
}
return 0;
}
/* return process args as a python list */
PyObject*
get_arg_list(long pid)
{
int mib[3];
int nargs;
int len;
char *procargs = NULL;
char *arg_ptr;
char *arg_end;
char *curr_arg;
size_t argmax;
PyObject *arg = NULL;
PyObject *arglist = NULL;
//special case for PID 0 (kernel_task) where cmdline cannot be fetched
if (pid == 0) {
return Py_BuildValue("[]");
}
/* read argmax and allocate memory for argument space. */
argmax = get_argmax();
if (! argmax) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
procargs = (char *)malloc(argmax);
if (NULL == procargs) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
/* read argument space */
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
if (EINVAL == errno) { // invalid == access denied OR nonexistent PID
if ( pid_exists(pid) ) {
AccessDenied();
} else {
NoSuchProcess();
}
}
goto error;
}
arg_end = &procargs[argmax];
/* copy the number of arguments to nargs */
memcpy(&nargs, procargs, sizeof(nargs));
arg_ptr = procargs + sizeof(nargs);
len = strlen(arg_ptr);
arg_ptr += len + 1;
if (arg_ptr == arg_end) {
free(procargs);
return Py_BuildValue("[]");
}
// skip ahead to the first argument
for (; arg_ptr < arg_end; arg_ptr++) {
if (*arg_ptr != '\0') {
break;
}
}
/* iterate through arguments */
curr_arg = arg_ptr;
arglist = Py_BuildValue("[]");
if (!arglist)
goto error;
while (arg_ptr < arg_end && nargs > 0) {
if (*arg_ptr++ == '\0') {
arg = Py_BuildValue("s", curr_arg);
if (!arg)
goto error;
if (PyList_Append(arglist, arg))
goto error;
Py_DECREF(arg);
// iterate to next arg and decrement # of args
curr_arg = arg_ptr;
nargs--;
}
}
free(procargs);
return arglist;
error:
Py_XDECREF(arg);
Py_XDECREF(arglist);
if (procargs != NULL)
free(procargs);
return NULL;
}
int
get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
{
int mib[4];
size_t len;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = pid;
// fetch the info with sysctl()
len = sizeof(struct kinfo_proc);
// now read the data from sysctl
if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) {
// raise an exception and throw errno as the error
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
/*
* sysctl succeeds but len is zero, happens when process has gone away
*/
if (len == 0) {
NoSuchProcess();
return -1;
}
return 0;
}
/*
* A thin wrapper around proc_pidinfo()
*/
int
psutil_proc_pidinfo(long pid, int flavor, void *pti, int size)
{
int ret = proc_pidinfo((int)pid, flavor, 0, pti, size);
if (ret == 0) {
if (! pid_exists(pid)) {
NoSuchProcess();
return 0;
}
else {
AccessDenied();
return 0;
}
}
else if (ret != size) {
AccessDenied();
return 0;
}
else {
return 1;
}
}
/*
* $Id: process_info.h 1407 2012-06-30 17:14:54Z g.rodola@gmail.com $
*
* 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.
*
* Helper functions related to fetching process information. Used by _psutil_osx
* module methods.
*/
#include <Python.h>
typedef struct kinfo_proc kinfo_proc;
int get_proc_list(kinfo_proc **procList, size_t *procCount);
int get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
int get_argmax(void);
int pid_exists(long pid);
int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size);
PyObject* get_arg_list(long pid);
#!/usr/bin/env python
#
# $Id: error.py 1142 2011-10-05 18:45:49Z g.rodola $
#
# 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.
"""psutil exception classes; do not import this directly"""
class Error(Exception):
"""Base exception class. All other psutil exceptions inherit
from this one.
"""
class NoSuchProcess(Error):
"""Exception raised when a process with a certain PID doesn't
or no longer exists (zombie).
"""
def __init__(self, pid, name=None, msg=None):
self.pid = pid
self.name = name
self.msg = msg
if msg is None:
if name:
details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
else:
details = "(pid=%s)" % self.pid
self.msg = "process no longer exists " + details
def __str__(self):
return self.msg
class AccessDenied(Error):
"""Exception raised when permission to perform an action is denied."""
def __init__(self, pid=None, name=None, msg=None):
self.pid = pid
self.name = name
self.msg = msg
if msg is None:
if (pid is not None) and (name is not None):
self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
elif (pid is not None):
self.msg = "(pid=%s)" % self.pid
else:
self.msg = ""
def __str__(self):
return self.msg
class TimeoutExpired(Error):
"""Raised on Process.wait(timeout) if timeout expires and process
is still alive.
"""
def __init__(self, pid=None, name=None):
self.pid = pid
self.name = name
if (pid is not None) and (name is not None):
self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
elif (pid is not None):
self.msg = "(pid=%s)" % self.pid
else:
self.msg = ""
def __str__(self):
return self.msg
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
#!/usr/bin/env python
#
# $Id: setup.py 1469 2012-07-18 16:00:39Z g.rodola $
#
# 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.
import sys
import os
try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
def get_version():
INIT = os.path.abspath(os.path.join(os.path.dirname(__file__),
'psutil', '__init__.py'))
f = open(INIT, 'r')
try:
for line in f:
if line.startswith('__version__'):
ret = eval(line.strip().split(' = ')[1])
assert ret.count('.') == 2, ret
for num in ret.split('.'):
assert num.isdigit(), ret
return ret
else:
raise ValueError("couldn't find version string")
finally:
f.close()
def get_description():
README = os.path.abspath(os.path.join(os.path.dirname(__file__), 'README'))
f = open(README, 'r')
try:
return f.read()
finally:
f.close()
VERSION = get_version()
# POSIX
if os.name == 'posix':
posix_extension = Extension('_psutil_posix',
sources = ['psutil/_psutil_posix.c'])
# Windows
if sys.platform.startswith("win32"):
def get_winver():
maj, min = sys.getwindowsversion()[0:2]
return '0x0%s' % ((maj * 100) + min)
extensions = [Extension('_psutil_mswindows',
sources=['psutil/_psutil_mswindows.c',
'psutil/_psutil_common.c',
'psutil/arch/mswindows/process_info.c',
'psutil/arch/mswindows/process_handles.c',
'psutil/arch/mswindows/security.c'],
define_macros=[('_WIN32_WINNT', get_winver()),
('_AVAIL_WINVER_', get_winver())],
libraries=["psapi", "kernel32", "advapi32",
"shell32", "netapi32", "iphlpapi",
"wtsapi32"],
#extra_compile_args=["/Z7"],
#extra_link_args=["/DEBUG"]
)]
# OS X
elif sys.platform.startswith("darwin"):
extensions = [Extension('_psutil_osx',
sources = ['psutil/_psutil_osx.c',
'psutil/_psutil_common.c',
'psutil/arch/osx/process_info.c'],
extra_link_args=['-framework', 'CoreFoundation',
'-framework', 'IOKit']
),
posix_extension]
# FreeBSD
elif sys.platform.startswith("freebsd"):
extensions = [Extension('_psutil_bsd',
sources = ['psutil/_psutil_bsd.c',
'psutil/_psutil_common.c',
'psutil/arch/bsd/process_info.c'],
libraries=["devstat"],
),
posix_extension]
# Linux
elif sys.platform.startswith("linux"):
extensions = [Extension('_psutil_linux',
sources=['psutil/_psutil_linux.c'],
),
posix_extension]
else:
sys.exit('platform %s is not supported' % sys.platform)
def main():
setup_args = dict(
name='psutil',
version=VERSION,
download_url="http://psutil.googlecode.com/files/psutil-%s.tar.gz" \
% VERSION,
description='A process and system utilities module for Python',
long_description=get_description(),
keywords=['ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice',
'tty', 'ionice', 'uptime', 'taskmgr', 'process', 'df',
'iotop', 'iostat', 'ifconfig', 'taskset', 'who', 'pidof',
'pmap', 'smem', 'monitoring',],
author='Giampaolo Rodola, Jay Loden',
author_email='psutil@googlegroups.com',
maintainer='Giampaolo Rodola',
maintainer_email='g.rodola <at> gmail <dot> com',
url='http://code.google.com/p/psutil/',
platforms='Platform Independent',
license='License :: OSI Approved :: BSD License',
packages=['psutil'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft',
'Operating System :: Microsoft :: Windows :: Windows NT/2000',
'Operating System :: POSIX',
'Operating System :: POSIX :: Linux',
'Operating System :: POSIX :: BSD :: FreeBSD',
'Operating System :: OS Independent',
'Programming Language :: C',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.4',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.0',
'Programming Language :: Python :: 3.1',
'Programming Language :: Python :: 3.2',
'Topic :: System :: Monitoring',
'Topic :: System :: Networking',
'Topic :: System :: Networking :: Monitoring',
'Topic :: System :: Benchmark',
'Topic :: System :: Hardware',
'Topic :: System :: Systems Administration',
'Topic :: Utilities',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: BSD License',
],
)
if extensions is not None:
setup_args["ext_modules"] = extensions
setup(**setup_args)
if __name__ == '__main__':
main()
#!/usr/bin/env python
#
# $Id: _bsd.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""BSD specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
import time
import re
import sys
import os
import psutil
from psutil._compat import PY3
from test_psutil import DEVNULL
from test_psutil import (reap_children, get_test_subprocess, sh, which,
skipUnless)
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
TOLERANCE = 200 * 1024 # 200 KB
MUSE_AVAILABLE = which('muse')
def sysctl(cmdline):
"""Expects a sysctl command with an argument and parse the result
returning only the value of interest.
"""
result = sh("sysctl " + cmdline)
result = result[result.find(": ") + 2:]
try:
return int(result)
except ValueError:
return result
def muse(field):
"""Thin wrapper around 'muse' cmdline utility."""
out = sh('muse', stderr=DEVNULL)
for line in out.split('\n'):
if line.startswith(field):
break
else:
raise ValueError("line not found")
return int(line.split()[1])
class BSDSpecificTestCase(unittest.TestCase):
def setUp(self):
self.pid = get_test_subprocess().pid
def tearDown(self):
reap_children()
def assert_eq_w_tol(self, first, second, tolerance):
difference = abs(first - second)
if difference <= tolerance:
return
msg = '%r != %r within %r delta (%r difference)' \
% (first, second, tolerance, difference)
raise AssertionError(msg)
def test_BOOT_TIME(self):
s = sysctl('sysctl kern.boottime')
s = s[s.find(" sec = ") + 7:]
s = s[:s.find(',')]
btime = int(s)
self.assertEqual(btime, psutil.BOOT_TIME)
def test_process_create_time(self):
cmdline = "ps -o lstart -p %s" %self.pid
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
output = p.communicate()[0]
if PY3:
output = str(output, sys.stdout.encoding)
start_ps = output.replace('STARTED', '').strip()
start_psutil = psutil.Process(self.pid).create_time
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
time.localtime(start_psutil))
self.assertEqual(start_ps, start_psutil)
def test_disks(self):
# test psutil.disk_usage() and psutil.disk_partitions()
# against "df -a"
def df(path):
out = sh('df -k "%s"' % path).strip()
lines = out.split('\n')
lines.pop(0)
line = lines.pop(0)
dev, total, used, free = line.split()[:4]
if dev == 'none':
dev = ''
total = int(total) * 1024
used = int(used) * 1024
free = int(free) * 1024
return dev, total, used, free
for part in psutil.disk_partitions(all=False):
usage = psutil.disk_usage(part.mountpoint)
dev, total, used, free = df(part.mountpoint)
self.assertEqual(part.device, dev)
self.assertEqual(usage.total, total)
# 10 MB tollerance
if abs(usage.free - free) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % (usage.free, free))
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % (usage.used, used))
def test_memory_maps(self):
out = sh('procstat -v %s' % self.pid)
maps = psutil.Process(self.pid).get_memory_maps(grouped=False)
lines = out.split('\n')[1:]
while lines:
line = lines.pop()
fields = line.split()
_, start, stop, perms, res = fields[:5]
map = maps.pop()
self.assertEqual("%s-%s" % (start, stop), map.addr)
self.assertEqual(int(res), map.rss)
if not map.path.startswith('['):
self.assertEqual(fields[10], map.path)
# --- virtual_memory(); tests against sysctl
def test_vmem_total(self):
syst = sysctl("sysctl vm.stats.vm.v_page_count") * PAGESIZE
self.assertEqual(psutil.virtual_memory().total, syst)
def test_vmem_active(self):
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
self.assert_eq_w_tol(psutil.virtual_memory().active, syst, TOLERANCE)
def test_vmem_inactive(self):
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
self.assert_eq_w_tol(psutil.virtual_memory().inactive, syst, TOLERANCE)
def test_vmem_wired(self):
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
self.assert_eq_w_tol(psutil.virtual_memory().wired, syst, TOLERANCE)
def test_vmem_cached(self):
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
self.assert_eq_w_tol(psutil.virtual_memory().cached, syst, TOLERANCE)
def test_vmem_free(self):
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
self.assert_eq_w_tol(psutil.virtual_memory().free, syst, TOLERANCE)
def test_vmem_buffers(self):
syst = sysctl("vfs.bufspace")
self.assert_eq_w_tol(psutil.virtual_memory().buffers, syst, TOLERANCE)
# --- virtual_memory(); tests against muse
@skipUnless(MUSE_AVAILABLE)
def test_total(self):
num = muse('Total')
self.assertEqual(psutil.virtual_memory().total, num)
@skipUnless(MUSE_AVAILABLE)
def test_active(self):
num = muse('Active')
self.assert_eq_w_tol(psutil.virtual_memory().active, num, TOLERANCE)
@skipUnless(MUSE_AVAILABLE)
def test_inactive(self):
num = muse('Inactive')
self.assert_eq_w_tol(psutil.virtual_memory().inactive, num, TOLERANCE)
@skipUnless(MUSE_AVAILABLE)
def test_wired(self):
num = muse('Wired')
self.assert_eq_w_tol(psutil.virtual_memory().wired, num, TOLERANCE)
@skipUnless(MUSE_AVAILABLE)
def test_cached(self):
num = muse('Cache')
self.assert_eq_w_tol(psutil.virtual_memory().cached, num, TOLERANCE)
@skipUnless(MUSE_AVAILABLE)
def test_free(self):
num = muse('Free')
self.assert_eq_w_tol(psutil.virtual_memory().free, num, TOLERANCE)
@skipUnless(MUSE_AVAILABLE)
def test_buffers(self):
num = muse('Buffer')
self.assert_eq_w_tol(psutil.virtual_memory().buffers, num, TOLERANCE)
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
#!/usr/bin/env python
#
# $Id: _linux.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""Linux specific tests. These are implicitly run by test_psutil.py."""
from __future__ import division
import unittest
import subprocess
import sys
import time
import os
from test_psutil import sh, get_test_subprocess
from psutil._compat import PY3
import psutil
TOLERANCE = 200 * 1024 # 200 KB
class LinuxSpecificTestCase(unittest.TestCase):
def assert_eq_w_tol(self, first, second, tolerance):
difference = abs(first - second)
if difference <= tolerance:
return
msg = '%r != %r within %r delta (%r difference)' \
% (first, second, tolerance, difference)
raise AssertionError(msg)
def test_disks(self):
# test psutil.disk_usage() and psutil.disk_partitions()
# against "df -a"
def df(path):
out = sh('df -P -B 1 "%s"' % path).strip()
lines = out.split('\n')
lines.pop(0)
line = lines.pop(0)
dev, total, used, free = line.split()[:4]
if dev == 'none':
dev = ''
total, used, free = int(total), int(used), int(free)
return dev, total, used, free
for part in psutil.disk_partitions(all=False):
usage = psutil.disk_usage(part.mountpoint)
dev, total, used, free = df(part.mountpoint)
self.assertEqual(part.device, dev)
self.assertEqual(usage.total, total)
# 10 MB tollerance
if abs(usage.free - free) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % (usage.free, free))
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % (usage.used, used))
def test_memory_maps(self):
sproc = get_test_subprocess()
time.sleep(1)
p = psutil.Process(sproc.pid)
maps = p.get_memory_maps(grouped=False)
pmap = sh('pmap -x %s' % p.pid).split('\n')
del pmap[0]; del pmap[0] # get rid of header
while maps and pmap:
this = maps.pop(0)
other = pmap.pop(0)
addr, _, rss, dirty, mode, path = other.split(None, 5)
if not path.startswith('[') and not path.endswith(']'):
self.assertEqual(path, os.path.basename(this.path))
self.assertEqual(int(rss) * 1024, this.rss)
# test only rwx chars, ignore 's' and 'p'
self.assertEqual(mode[:3], this.perms[:3])
def test_vmem_total(self):
lines = sh('free').split('\n')[1:]
total = int(lines[0].split()[1]) * 1024
self.assertEqual(total, psutil.virtual_memory().total)
def test_vmem_used(self):
lines = sh('free').split('\n')[1:]
used = int(lines[0].split()[2]) * 1024
self.assert_eq_w_tol(used, psutil.virtual_memory().used, TOLERANCE)
def test_vmem_free(self):
lines = sh('free').split('\n')[1:]
free = int(lines[0].split()[3]) * 1024
self.assert_eq_w_tol(free, psutil.virtual_memory().free, TOLERANCE)
def test_vmem_buffers(self):
lines = sh('free').split('\n')[1:]
buffers = int(lines[0].split()[5]) * 1024
self.assert_eq_w_tol(buffers, psutil.virtual_memory().buffers, TOLERANCE)
def test_vmem_cached(self):
lines = sh('free').split('\n')[1:]
cached = int(lines[0].split()[6]) * 1024
self.assert_eq_w_tol(cached, psutil.virtual_memory().cached, TOLERANCE)
def test_swapmem_total(self):
lines = sh('free').split('\n')[1:]
total = int(lines[2].split()[1]) * 1024
self.assertEqual(total, psutil.swap_memory().total)
def test_swapmem_used(self):
lines = sh('free').split('\n')[1:]
used = int(lines[2].split()[2]) * 1024
self.assert_eq_w_tol(used, psutil.swap_memory().used, TOLERANCE)
def test_swapmem_free(self):
lines = sh('free').split('\n')[1:]
free = int(lines[2].split()[3]) * 1024
self.assert_eq_w_tol(free, psutil.swap_memory().free, TOLERANCE)
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
#!/usr/bin/env python
#
# $Id: _osx.py 1498 2012-07-24 21:41:28Z g.rodola $
#
# 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.
"""OSX specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
import time
import sys
import os
import re
import psutil
from psutil._compat import PY3
from test_psutil import reap_children, get_test_subprocess, sh
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
TOLERANCE = 200 * 1024 # 200 KB
def sysctl(cmdline):
"""Expects a sysctl command with an argument and parse the result
returning only the value of interest.
"""
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
result = p.communicate()[0].strip().split()[1]
if PY3:
result = str(result, sys.stdout.encoding)
try:
return int(result)
except ValueError:
return result
def vm_stat(field):
"""Wrapper around 'vm_stat' cmdline utility."""
out = sh('vm_stat')
for line in out.split('\n'):
if field in line:
break
else:
raise ValueError("line not found")
return int(re.search('\d+', line).group(0)) * PAGESIZE
class OSXSpecificTestCase(unittest.TestCase):
def setUp(self):
self.pid = get_test_subprocess().pid
def tearDown(self):
reap_children()
def assert_eq_w_tol(self, first, second, tolerance):
difference = abs(first - second)
if difference <= tolerance:
return
msg = '%r != %r within %r delta (%r difference)' \
% (first, second, tolerance, difference)
raise AssertionError(msg)
def test_process_create_time(self):
cmdline = "ps -o lstart -p %s" %self.pid
p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
output = p.communicate()[0]
if PY3:
output = str(output, sys.stdout.encoding)
start_ps = output.replace('STARTED', '').strip()
start_psutil = psutil.Process(self.pid).create_time
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
time.localtime(start_psutil))
self.assertEqual(start_ps, start_psutil)
def test_disks(self):
# test psutil.disk_usage() and psutil.disk_partitions()
# against "df -a"
def df(path):
out = sh('df -k "%s"' % path).strip()
lines = out.split('\n')
lines.pop(0)
line = lines.pop(0)
dev, total, used, free = line.split()[:4]
if dev == 'none':
dev = ''
total = int(total) * 1024
used = int(used) * 1024
free = int(free) * 1024
return dev, total, used, free
for part in psutil.disk_partitions(all=False):
usage = psutil.disk_usage(part.mountpoint)
dev, total, used, free = df(part.mountpoint)
self.assertEqual(part.device, dev)
self.assertEqual(usage.total, total)
# 10 MB tollerance
if abs(usage.free - free) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % usage.free, free)
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % usage.used, used)
# --- virtual mem
def test_vmem_total(self):
sysctl_hwphymem = sysctl('sysctl hw.memsize')
self.assertEqual(sysctl_hwphymem, psutil.TOTAL_PHYMEM)
def test_vmem_free(self):
num = vm_stat("free")
self.assert_eq_w_tol(psutil.virtual_memory().free, num, TOLERANCE)
def test_vmem_active(self):
num = vm_stat("active")
self.assert_eq_w_tol(psutil.virtual_memory().active, num, TOLERANCE)
def test_vmem_inactive(self):
num = vm_stat("inactive")
self.assert_eq_w_tol(psutil.virtual_memory().inactive, num, TOLERANCE)
def test_vmem_wired(self):
num = vm_stat("wired")
self.assert_eq_w_tol(psutil.virtual_memory().wired, num, TOLERANCE)
# --- swap mem
def test_swapmem_sin(self):
num = vm_stat("Pageins")
self.assertEqual(psutil.swap_memory().sin, num)
def test_swapmem_sout(self):
num = vm_stat("Pageouts")
self.assertEqual(psutil.swap_memory().sout, num)
def test_swapmem_total(self):
tot1 = psutil.swap_memory().total
tot2 = 0
# OSX uses multiple cache files:
# http://en.wikipedia.org/wiki/Paging#OS_X
for name in os.listdir("/var/vm/"):
file = os.path.join("/var/vm", name)
if os.path.isfile(file):
tot2 += os.path.getsize(file)
self.assertEqual(tot1, tot2)
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
#!/usr/bin/env python
#
# $Id: _posix.py 1386 2012-06-27 15:44:36Z g.rodola $
#
# 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.
"""POSIX specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
import time
import sys
import os
import datetime
import psutil
from psutil._compat import PY3
from test_psutil import (get_test_subprocess, reap_children, PYTHON, LINUX, OSX,
BSD, ignore_access_denied, sh, skipIf)
def ps(cmd):
"""Expects a ps command with a -o argument and parse the result
returning only the value of interest.
"""
if not LINUX:
cmd = cmd.replace(" --no-headers ", " ")
p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE)
output = p.communicate()[0].strip()
if PY3:
output = str(output, sys.stdout.encoding)
if not LINUX:
output = output.split('\n')[1]
try:
return int(output)
except ValueError:
return output
class PosixSpecificTestCase(unittest.TestCase):
"""Compare psutil results against 'ps' command line utility."""
# for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps
def setUp(self):
self.pid = get_test_subprocess([PYTHON, "-E", "-O"],
stdin=subprocess.PIPE).pid
def tearDown(self):
reap_children()
def test_process_parent_pid(self):
ppid_ps = ps("ps --no-headers -o ppid -p %s" %self.pid)
ppid_psutil = psutil.Process(self.pid).ppid
self.assertEqual(ppid_ps, ppid_psutil)
def test_process_uid(self):
uid_ps = ps("ps --no-headers -o uid -p %s" %self.pid)
uid_psutil = psutil.Process(self.pid).uids.real
self.assertEqual(uid_ps, uid_psutil)
def test_process_gid(self):
gid_ps = ps("ps --no-headers -o rgid -p %s" %self.pid)
gid_psutil = psutil.Process(self.pid).gids.real
self.assertEqual(gid_ps, gid_psutil)
def test_process_username(self):
username_ps = ps("ps --no-headers -o user -p %s" %self.pid)
username_psutil = psutil.Process(self.pid).username
self.assertEqual(username_ps, username_psutil)
@ignore_access_denied
def test_process_rss_memory(self):
# give python interpreter some time to properly initialize
# so that the results are the same
time.sleep(0.1)
rss_ps = ps("ps --no-headers -o rss -p %s" %self.pid)
rss_psutil = psutil.Process(self.pid).get_memory_info()[0] / 1024
self.assertEqual(rss_ps, rss_psutil)
@ignore_access_denied
def test_process_vsz_memory(self):
# give python interpreter some time to properly initialize
# so that the results are the same
time.sleep(0.1)
vsz_ps = ps("ps --no-headers -o vsz -p %s" %self.pid)
vsz_psutil = psutil.Process(self.pid).get_memory_info()[1] / 1024
self.assertEqual(vsz_ps, vsz_psutil)
def test_process_name(self):
# use command + arg since "comm" keyword not supported on all platforms
name_ps = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
# remove path if there is any, from the command
name_ps = os.path.basename(name_ps).lower()
name_psutil = psutil.Process(self.pid).name.lower()
self.assertEqual(name_ps, name_psutil)
@skipIf(OSX or BSD)
def test_process_create_time(self):
time_ps = ps("ps --no-headers -o start -p %s" %self.pid).split(' ')[0]
time_psutil = psutil.Process(self.pid).create_time
time_psutil = datetime.datetime.fromtimestamp(
time_psutil).strftime("%H:%M:%S")
self.assertEqual(time_ps, time_psutil)
def test_process_exe(self):
ps_pathname = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
psutil_pathname = psutil.Process(self.pid).exe
try:
self.assertEqual(ps_pathname, psutil_pathname)
except AssertionError:
# certain platforms such as BSD are more accurate returning:
# "/usr/local/bin/python2.7"
# ...instead of:
# "/usr/local/bin/python"
# We do not want to consider this difference in accuracy
# an error.
adjusted_ps_pathname = ps_pathname[:len(ps_pathname)]
self.assertEqual(ps_pathname, adjusted_ps_pathname)
def test_process_cmdline(self):
ps_cmdline = ps("ps --no-headers -o command -p %s" %self.pid)
psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline)
self.assertEqual(ps_cmdline, psutil_cmdline)
def test_get_pids(self):
# Note: this test might fail if the OS is starting/killing
# other processes in the meantime
p = get_test_subprocess(["ps", "ax", "-o", "pid"], stdout=subprocess.PIPE)
output = p.communicate()[0].strip()
if PY3:
output = str(output, sys.stdout.encoding)
output = output.replace('PID', '')
p.wait()
pids_ps = []
for pid in output.split('\n'):
if pid:
pids_ps.append(int(pid.strip()))
# remove ps subprocess pid which is supposed to be dead in meantime
pids_ps.remove(p.pid)
pids_psutil = psutil.get_pid_list()
pids_ps.sort()
pids_psutil.sort()
# on OSX ps doesn't show pid 0
if OSX and 0 not in pids_ps:
pids_ps.insert(0, 0)
if pids_ps != pids_psutil:
difference = [x for x in pids_psutil if x not in pids_ps] + \
[x for x in pids_ps if x not in pids_psutil]
self.fail("difference: " + str(difference))
def test_nic_names(self):
p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE)
output = p.communicate()[0].strip()
if PY3:
output = str(output, sys.stdout.encoding)
for nic in psutil.network_io_counters(pernic=True).keys():
for line in output.split():
if line.startswith(nic):
break
else:
self.fail("couldn't find %s nic in 'ifconfig -a' output" % nic)
def test_get_users(self):
out = sh("who")
lines = out.split('\n')
users = [x.split()[0] for x in lines]
self.assertEqual(len(users), len(psutil.get_users()))
terminals = [x.split()[1] for x in lines]
for u in psutil.get_users():
self.assertTrue(u.name in users, u.name)
self.assertTrue(u.terminal in terminals, u.terminal)
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
#!/usr/bin/env python
#
# $Id: _windows.py 1453 2012-07-13 19:55:11Z g.rodola $
#
# 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 specific tests. These are implicitly run by test_psutil.py."""
import os
import unittest
import platform
import signal
import time
import warnings
import atexit
import sys
import subprocess
import errno
import traceback
import psutil
import _psutil_mswindows
from psutil._compat import PY3, callable, long
from test_psutil import reap_children, get_test_subprocess, wait_for_pid, warn
try:
import wmi
except ImportError:
err = sys.exc_info()[1]
atexit.register(warn, "Couldn't run wmi tests: %s" % str(err))
wmi = None
try:
import win32api
import win32con
except ImportError:
err = sys.exc_info()[1]
atexit.register(warn, "Couldn't run pywin32 tests: %s" % str(err))
win32api = None
class WindowsSpecificTestCase(unittest.TestCase):
def setUp(self):
sproc = get_test_subprocess()
wait_for_pid(sproc.pid)
self.pid = sproc.pid
def tearDown(self):
reap_children()
def test_issue_24(self):
p = psutil.Process(0)
self.assertRaises(psutil.AccessDenied, p.kill)
def test_special_pid(self):
p = psutil.Process(4)
self.assertEqual(p.name, 'System')
# use __str__ to access all common Process properties to check
# that nothing strange happens
str(p)
p.username
self.assertTrue(p.create_time >= 0.0)
try:
rss, vms = p.get_memory_info()
except psutil.AccessDenied:
# expected on Windows Vista and Windows 7
if not platform.uname()[1] in ('vista', 'win-7', 'win7'):
raise
else:
self.assertTrue(rss > 0)
def test_signal(self):
p = psutil.Process(self.pid)
self.assertRaises(ValueError, p.send_signal, signal.SIGINT)
def test_nic_names(self):
p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE)
out = p.communicate()[0]
if PY3:
out = str(out, sys.stdout.encoding)
nics = psutil.network_io_counters(pernic=True).keys()
for nic in nics:
if "pseudo-interface" in nic.replace(' ', '-').lower():
continue
if nic not in out:
self.fail("%r nic wasn't found in 'ipconfig /all' output" % nic)
def test_exe(self):
for p in psutil.process_iter():
try:
self.assertEqual(os.path.basename(p.exe), p.name)
except psutil.Error:
pass
if wmi is not None:
# --- Process class tests
def test_process_name(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
self.assertEqual(p.name, w.Caption)
def test_process_exe(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
self.assertEqual(p.exe, w.ExecutablePath)
def test_process_cmdline(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
self.assertEqual(' '.join(p.cmdline), w.CommandLine.replace('"', ''))
def test_process_username(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
domain, _, username = w.GetOwner()
username = "%s\\%s" %(domain, username)
self.assertEqual(p.username, username)
def test_process_rss_memory(self):
time.sleep(0.1)
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
rss = p.get_memory_info().rss
self.assertEqual(rss, int(w.WorkingSetSize))
def test_process_vms_memory(self):
time.sleep(0.1)
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
vms = p.get_memory_info().vms
# http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx
# ...claims that PageFileUsage is represented in Kilo
# bytes but funnily enough on certain platforms bytes are
# returned instead.
wmi_usage = int(w.PageFileUsage)
if (vms != wmi_usage) and (vms != wmi_usage * 1024):
self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
def test_process_create_time(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
wmic_create = str(w.CreationDate.split('.')[0])
psutil_create = time.strftime("%Y%m%d%H%M%S",
time.localtime(p.create_time))
self.assertEqual(wmic_create, psutil_create)
# --- psutil namespace functions and constants tests
def test_NUM_CPUS(self):
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
self.assertEqual(num_cpus, psutil.NUM_CPUS)
def test_TOTAL_PHYMEM(self):
w = wmi.WMI().Win32_ComputerSystem()[0]
self.assertEqual(int(w.TotalPhysicalMemory), psutil.TOTAL_PHYMEM)
def test__UPTIME(self):
# _UPTIME constant is not public but it is used internally
# as value to return for pid 0 creation time.
# WMI behaves the same.
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(0)
wmic_create = str(w.CreationDate.split('.')[0])
psutil_create = time.strftime("%Y%m%d%H%M%S",
time.localtime(p.create_time))
# XXX - ? no actual test here
def test_get_pids(self):
# Note: this test might fail if the OS is starting/killing
# other processes in the meantime
w = wmi.WMI().Win32_Process()
wmi_pids = [x.ProcessId for x in w]
wmi_pids.sort()
psutil_pids = psutil.get_pid_list()
psutil_pids.sort()
if wmi_pids != psutil_pids:
difference = filter(lambda x:x not in wmi_pids, psutil_pids) + \
filter(lambda x:x not in psutil_pids, wmi_pids)
self.fail("difference: " + str(difference))
def test_disks(self):
ps_parts = psutil.disk_partitions(all=True)
wmi_parts = wmi.WMI().Win32_LogicalDisk()
for ps_part in ps_parts:
for wmi_part in wmi_parts:
if ps_part.device.replace('\\', '') == wmi_part.DeviceID:
if not ps_part.mountpoint:
# this is usually a CD-ROM with no disk inserted
break
try:
usage = psutil.disk_usage(ps_part.mountpoint)
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.ENOENT:
# usually this is the floppy
break
else:
raise
self.assertEqual(usage.total, int(wmi_part.Size))
wmi_free = int(wmi_part.FreeSpace)
self.assertEqual(usage.free, wmi_free)
# 10 MB tollerance
if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
self.fail("psutil=%s, wmi=%s" % usage.free, wmi_free)
break
else:
self.fail("can't find partition %s" % repr(ps_part))
if win32api is not None:
def test_get_num_handles(self):
p = psutil.Process(os.getpid())
before = p.get_num_handles()
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
win32con.FALSE, os.getpid())
after = p.get_num_handles()
self.assertEqual(after, before+1)
win32api.CloseHandle(handle)
self.assertEqual(p.get_num_handles(), before)
def test_get_num_handles_2(self):
# Note: this fails from time to time; I'm keen on thinking
# it doesn't mean something is broken
def call(p, attr):
attr = getattr(p, name, None)
if attr is not None and callable(attr):
ret = attr()
else:
ret = attr
p = psutil.Process(self.pid)
attrs = []
failures = []
for name in dir(psutil.Process):
if name.startswith('_') \
or name.startswith('set_') \
or name in ('terminate', 'kill', 'suspend', 'resume', 'nice',
'send_signal', 'wait', 'get_children', 'as_dict'):
continue
else:
try:
call(p, name)
num1 = p.get_num_handles()
call(p, name)
num2 = p.get_num_handles()
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
else:
if num2 > num1:
fail = "failure while processing Process.%s method " \
"(before=%s, after=%s)" % (name, num1, num2)
failures.append(fail)
if failures:
self.fail('\n' + '\n'.join(failures))
import _psutil_mswindows
from psutil._psmswindows import ACCESS_DENIED_SET
def wrap_exceptions(callable):
def wrapper(self, *args, **kwargs):
try:
return callable(self, *args, **kwargs)
except OSError:
err = sys.exc_info()[1]
if err.errno in ACCESS_DENIED_SET:
raise psutil.AccessDenied(None, None)
if err.errno == errno.ESRCH:
raise psutil.NoSuchProcess(None, None)
raise
return wrapper
class TestDualProcessImplementation(unittest.TestCase):
fun_names = [
# function name tolerance
('get_process_cpu_times', 0.2),
('get_process_create_time', 0.5),
('get_process_num_handles', 1), # 1 because impl #1 opens a handle
('get_process_io_counters', 0),
('get_process_memory_info', 1024), # KB
]
def test_compare_values(self):
# Certain APIs on Windows have 2 internal implementations, one
# based on documented Windows APIs, another one based
# NtQuerySystemInformation() which gets called as fallback in
# case the first fails because of limited permission error.
# Here we test that the two methods return the exact same value,
# see:
# http://code.google.com/p/psutil/issues/detail?id=304
def assert_ge_0(obj):
if isinstance(obj, tuple):
for value in obj:
assert value >= 0, value
elif isinstance(obj, (int, long, float)):
assert obj >= 0, obj
else:
assert 0 # case not handled which needs to be fixed
def compare_with_tolerance(ret1, ret2, tolerance):
if ret1 == ret2:
return
else:
if isinstance(ret2, (int, long, float)):
diff = abs(ret1 - ret2)
assert diff <= tolerance, diff
elif isinstance(ret2, tuple):
for a, b in zip(ret1, ret2):
diff = abs(a - b)
assert diff <= tolerance, diff
failures = []
for name, tolerance in self.fun_names:
meth1 = wrap_exceptions(getattr(_psutil_mswindows, name))
meth2 = wrap_exceptions(getattr(_psutil_mswindows, name + '_2'))
for p in psutil.process_iter():
#
try:
ret1 = meth1(p.pid)
except psutil.NoSuchProcess:
continue
except psutil.AccessDenied:
ret1 = None
#
try:
ret2 = meth2(p.pid)
except psutil.NoSuchProcess:
# this is supposed to fail only in case of zombie process
# never for permission error
continue
# compare values
try:
if ret1 is None:
assert_ge_0(ret2)
else:
compare_with_tolerance(ret1, ret2, tolerance)
assert_ge_0(ret1)
assert_ge_0(ret2)
except AssertionError:
err = sys.exc_info()[1]
trace = traceback.format_exc()
msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' \
% (trace, p.pid, name, ret1, ret2)
failures.append(msg)
break
if failures:
self.fail('\n\n'.join(failures))
def test_zombies(self):
# test that NPS is raised by the 2nd implementation in case a
# process no longer exists
ZOMBIE_PID = max(psutil.get_pid_list()) + 5000
for name, _ in self.fun_names:
meth = wrap_exceptions(getattr(_psutil_mswindows, name))
self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID)
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase))
test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation))
unittest.TextTestRunner(verbosity=2).run(test_suite)
#!/usr/bin/env python
#
# $Id: test_memory_leaks.py 1499 2012-07-25 12:42:31Z g.rodola $
#
# 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.
"""
A test script which attempts to detect memory leaks by calling C
functions many times and compare process memory usage before and
after the calls. It might produce false positives.
"""
import os
import gc
import unittest
import time
import socket
import threading
import types
import psutil
import psutil._common
from psutil._compat import PY3, callable, xrange
from test_psutil import POSIX, LINUX, WINDOWS, OSX, BSD, TESTFN
from test_psutil import (reap_children, skipUnless, skipIf, supports_ipv6,
safe_remove, get_test_subprocess)
# disable cache for Process class properties
psutil._common.cached_property.enabled = False
LOOPS = 1000
TOLERANCE = 4096
class Base(unittest.TestCase):
proc = psutil.Process(os.getpid())
def execute(self, function, *args, **kwargs):
def call_many_times():
for x in xrange(LOOPS - 1):
self.call(function, *args, **kwargs)
del x
gc.collect()
return self.get_mem()
self.call(function, *args, **kwargs)
self.assertEqual(gc.garbage, [])
self.assertEqual(threading.active_count(), 1)
# RSS comparison
# step 1
rss1 = call_many_times()
# step 2
rss2 = call_many_times()
difference = rss2 - rss1
if difference > TOLERANCE:
# This doesn't necessarily mean we have a leak yet.
# At this point we assume that after having called the
# function so many times the memory usage is stabilized
# and if there are no leaks it should not increase any
# more.
# Let's keep calling fun for 3 more seconds and fail if
# we notice any difference.
stop_at = time.time() + 3
while 1:
self.call(function, *args, **kwargs)
if time.time() >= stop_at:
break
del stop_at
gc.collect()
rss3 = self.get_mem()
difference = rss3 - rss2
if rss3 > rss2:
self.fail("rss2=%s, rss3=%s, difference=%s" \
% (rss2, rss3, difference))
def get_mem(self):
return psutil.Process(os.getpid()).get_memory_info()[0]
def call(self, *args, **kwargs):
raise NotImplementedError("must be implemented in subclass")
class TestProcessObjectLeaks(Base):
"""Test leaks of Process class methods and properties"""
def __init__(self, *args, **kwargs):
Base.__init__(self, *args, **kwargs)
# skip tests which are not supported by Process API
supported_attrs = dir(psutil.Process)
for attr in [x for x in dir(self) if x.startswith('test')]:
if attr[5:] not in supported_attrs:
meth = getattr(self, attr)
@skipIf(True)
def test_(self):
pass
setattr(self, attr, types.MethodType(test_, self))
def setUp(self):
gc.collect()
def tearDown(self):
reap_children()
def call(self, function, *args, **kwargs):
try:
obj = getattr(self.proc, function)
if callable(obj):
obj(*args, **kwargs)
except psutil.Error:
pass
def test_name(self):
self.execute('name')
def test_cmdline(self):
self.execute('cmdline')
def test_exe(self):
self.execute('exe')
def test_ppid(self):
self.execute('ppid')
def test_uids(self):
self.execute('uids')
def test_gids(self):
self.execute('gids')
def test_status(self):
self.execute('status')
def test_get_nice(self):
self.execute('get_nice')
def test_set_nice(self):
niceness = psutil.Process(os.getpid()).get_nice()
self.execute('set_nice', niceness)
def test_get_io_counters(self):
self.execute('get_io_counters')
def test_get_ionice(self):
self.execute('get_ionice')
def test_set_ionice(self):
self.execute('set_ionice', psutil.IOPRIO_CLASS_NONE)
def test_username(self):
self.execute('username')
def test_create_time(self):
self.execute('create_time')
def test_get_num_threads(self):
self.execute('get_num_threads')
def test_get_num_handles(self):
self.execute('get_num_handles')
def test_get_num_fds(self):
self.execute('get_num_fds')
def test_get_threads(self):
self.execute('get_threads')
def test_get_cpu_times(self):
self.execute('get_cpu_times')
def test_get_memory_info(self):
self.execute('get_memory_info')
def test_get_ext_memory_info(self):
self.execute('get_ext_memory_info')
def test_terminal(self):
self.execute('terminal')
@skipUnless(WINDOWS)
def test_resume(self):
self.execute('resume')
def test_getcwd(self):
self.execute('getcwd')
def test_get_cpu_affinity(self):
self.execute('get_cpu_affinity')
def test_set_cpu_affinity(self):
affinity = psutil.Process(os.getpid()).get_cpu_affinity()
self.execute('set_cpu_affinity', affinity)
def test_get_open_files(self):
safe_remove(TESTFN) # needed after UNIX socket test has run
f = open(TESTFN, 'w')
try:
self.execute('get_open_files')
finally:
f.close()
# OSX implementation is unbelievably slow
@skipIf(OSX)
def test_get_memory_maps(self):
self.execute('get_memory_maps')
# Linux implementation is pure python so since it's slow we skip it
@skipIf(LINUX)
def test_get_connections(self):
def create_socket(family, type):
sock = socket.socket(family, type)
sock.bind(('', 0))
if type == socket.SOCK_STREAM:
sock.listen(1)
return sock
socks = []
socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM))
socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM))
if supports_ipv6():
socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM))
socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM))
if hasattr(socket, 'AF_UNIX'):
safe_remove(TESTFN)
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.bind(TESTFN)
s.listen(1)
socks.append(s)
try:
self.execute('get_connections', kind='all')
finally:
for s in socks:
s.close()
p = get_test_subprocess()
DEAD_PROC = psutil.Process(p.pid)
DEAD_PROC.kill()
DEAD_PROC.wait()
del p
class TestProcessObjectLeaksZombie(TestProcessObjectLeaks):
"""Same as above but looks for leaks occurring when dealing with
zombie processes raising NoSuchProcess exception.
"""
proc = DEAD_PROC
if not POSIX:
def test_kill(self):
self.execute('kill')
def test_terminate(self):
self.execute('terminate')
def test_suspend(self):
self.execute('suspend')
def test_resume(self):
self.execute('resume')
def test_wait(self):
self.execute('wait')
class TestModuleFunctionsLeaks(Base):
"""Test leaks of psutil module functions."""
def setUp(self):
gc.collect()
def call(self, function, *args, **kwargs):
obj = getattr(psutil, function)
if callable(obj):
retvalue = obj(*args, **kwargs)
@skipIf(POSIX)
def test_pid_exists(self):
self.execute('pid_exists', os.getpid())
def test_virtual_memory(self):
self.execute('virtual_memory')
def test_swap_memory(self):
self.execute('swap_memory')
def test_cpu_times(self):
self.execute('cpu_times')
def test_per_cpu_times(self):
self.execute('cpu_times', percpu=True)
@skipUnless(WINDOWS)
def test_disk_usage(self):
self.execute('disk_usage', '.')
def test_disk_partitions(self):
self.execute('disk_partitions')
def test_network_io_counters(self):
self.execute('network_io_counters')
def test_disk_io_counters(self):
self.execute('disk_io_counters')
# XXX - on Windows this produces a false positive
@skipIf(WINDOWS)
def test_get_users(self):
self.execute('get_users')
def test_main():
test_suite = unittest.TestSuite()
tests = [TestProcessObjectLeaksZombie,
TestProcessObjectLeaks,
TestModuleFunctionsLeaks,]
for test in tests:
test_suite.addTest(unittest.makeSuite(test))
unittest.TextTestRunner(verbosity=2).run(test_suite)
if __name__ == '__main__':
test_main()
#!/usr/bin/env python
#
# $Id: test_psutil.py 1525 2012-08-16 16:32:03Z g.rodola $
#
# 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.
"""
psutil test suite.
Note: this is targeted for both python 2.x and 3.x so there's no need
to use 2to3 tool first.
"""
from __future__ import division
import unittest
import os
import sys
import subprocess
import time
import signal
import types
import traceback
import socket
import warnings
import atexit
import errno
import threading
import tempfile
import stat
import collections
import datetime
import psutil
from psutil._compat import PY3, callable, long
PYTHON = os.path.realpath(sys.executable)
DEVNULL = open(os.devnull, 'r+')
TESTFN = os.path.join(os.getcwd(), "$testfile")
POSIX = os.name == 'posix'
LINUX = sys.platform.startswith("linux")
WINDOWS = sys.platform.startswith("win32")
OSX = sys.platform.startswith("darwin")
BSD = sys.platform.startswith("freebsd")
_subprocesses_started = set()
def get_test_subprocess(cmd=None, stdout=DEVNULL, stderr=DEVNULL, stdin=None,
wait=False):
"""Return a subprocess.Popen object to use in tests.
By default stdout and stderr are redirected to /dev/null and the
python interpreter is used as test process.
If 'wait' is True attemps to make sure the process is in a
reasonably initialized state.
"""
if cmd is None:
pyline = ""
if wait:
pyline += "open('%s', 'w'); " % TESTFN
pyline += "import time; time.sleep(3600);"
cmd_ = [PYTHON, "-c", pyline]
else:
cmd_ = cmd
sproc = subprocess.Popen(cmd_, stdout=stdout, stderr=stderr, stdin=stdin)
if wait:
if cmd is None:
stop_at = time.time() + 3
while time.time() > stop_at:
if os.path.exists(TESTFN):
break
time.sleep(0.001)
else:
warn("couldn't make sure test file was actually created")
else:
wait_for_pid(sproc.pid)
_subprocesses_started.add(sproc.pid)
return sproc
def warn(msg, warntype=RuntimeWarning):
"""Raise a warning msg."""
warnings.warn(msg, warntype)
def sh(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE):
"""run cmd in a subprocess and return its output.
raises RuntimeError on error.
"""
p = subprocess.Popen(cmdline, shell=True, stdout=stdout, stderr=stderr)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise RuntimeError(stderr)
if stderr:
warn(stderr)
if PY3:
stdout = str(stdout, sys.stdout.encoding)
return stdout.strip()
def which(program):
"""Same as UNIX which command. Return None on command not found."""
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
def wait_for_pid(pid, timeout=1):
"""Wait for pid to show up in the process list then return.
Used in the test suite to give time the sub process to initialize.
"""
raise_at = time.time() + timeout
while 1:
if pid in psutil.get_pid_list():
# give it one more iteration to allow full initialization
time.sleep(0.01)
return
time.sleep(0.0001)
if time.time() >= raise_at:
raise RuntimeError("Timed out")
def reap_children(search_all=False):
"""Kill any subprocess started by this test suite and ensure that
no zombies stick around to hog resources and create problems when
looking for refleaks.
"""
pids = _subprocesses_started
if search_all:
this_process = psutil.Process(os.getpid())
for p in this_process.get_children(recursive=True):
pids.add(p.pid)
while pids:
pid = pids.pop()
try:
child = psutil.Process(pid)
child.kill()
except psutil.NoSuchProcess:
pass
except psutil.AccessDenied:
warn("couldn't kill child process with pid %s" % pid)
else:
child.wait(timeout=3)
def check_ip_address(addr, family):
"""Attempts to check IP address's validity."""
if not addr:
return
ip, port = addr
assert isinstance(port, int), port
if family == socket.AF_INET:
ip = list(map(int, ip.split('.')))
assert len(ip) == 4, ip
for num in ip:
assert 0 <= num <= 255, ip
assert 0 <= port <= 65535, port
def safe_remove(fname):
try:
os.remove(fname)
except OSError:
pass
def call_until(fun, expr, timeout=1):
"""Keep calling function for timeout secs and exit if eval()
expression is True.
"""
stop_at = time.time() + timeout
while time.time() < stop_at:
ret = fun()
if eval(expr):
return ret
time.sleep(0.001)
raise RuntimeError('timed out (ret=%r)' % ret)
def skipIf(condition, reason="", warn=False):
"""Decorator which skip a test under if condition is satisfied.
This is a substitute of unittest.skipIf which is available
only in python 2.7 and 3.2.
If 'reason' argument is provided this will be printed during
tests execution.
If 'warn' is provided a RuntimeWarning will be shown when all
tests are run.
"""
def outer(fun, *args, **kwargs):
def inner(self):
if condition:
sys.stdout.write("skipped-")
sys.stdout.flush()
if warn:
objname = "%s.%s" % (self.__class__.__name__, fun.__name__)
msg = "%s was skipped" % objname
if reason:
msg += "; reason: " + repr(reason)
atexit.register(warn, msg)
return
else:
return fun(self, *args, **kwargs)
return inner
return outer
def skipUnless(condition, reason="", warn=False):
"""Contrary of skipIf."""
if not condition:
return skipIf(True, reason, warn)
return skipIf(False)
def ignore_access_denied(fun):
"""Decorator to Ignore AccessDenied exceptions."""
def outer(fun, *args, **kwargs):
def inner(self):
try:
return fun(self, *args, **kwargs)
except psutil.AccessDenied:
pass
return inner
return outer
def supports_ipv6():
"""Return True if IPv6 is supported on this platform."""
if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
return False
sock = None
try:
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.bind(("::1", 0))
except (socket.error, socket.gaierror):
return False
else:
return True
finally:
if sock is not None:
sock.close()
class ThreadTask(threading.Thread):
"""A thread object used for running process thread tests."""
def __init__(self):
threading.Thread.__init__(self)
self._running = False
self._interval = None
self._flag = threading.Event()
def __repr__(self):
name = self.__class__.__name__
return '<%s running=%s at %#x>' % (name, self._running, id(self))
def start(self, interval=0.001):
"""Start thread and keep it running until an explicit
stop() request. Polls for shutdown every 'timeout' seconds.
"""
if self._running:
raise ValueError("already started")
self._interval = interval
threading.Thread.start(self)
self._flag.wait()
def run(self):
self._running = True
self._flag.set()
while self._running:
time.sleep(self._interval)
def stop(self):
"""Stop thread execution and and waits until it is stopped."""
if not self._running:
raise ValueError("already stopped")
self._running = False
self.join()
class TestCase(unittest.TestCase):
def setUp(self):
safe_remove(TESTFN)
def tearDown(self):
reap_children()
if not hasattr(unittest.TestCase, "assertIn"):
def assertIn(self, member, container, msg=None):
if member not in container:
self.fail(msg or \
'%s not found in %s' % (repr(member), repr(container)))
def assert_eq_w_tol(self, first, second, tolerance):
difference = abs(first - second)
if difference <= tolerance:
return
msg = '%r != %r within %r delta (%r difference)' \
% (first, second, tolerance, difference)
raise AssertionError(msg)
# ============================
# tests for system-related API
# ============================
def test_process_iter(self):
assert os.getpid() in [x.pid for x in psutil.process_iter()]
sproc = get_test_subprocess()
assert sproc.pid in [x.pid for x in psutil.process_iter()]
p = psutil.Process(sproc.pid)
p.kill()
p.wait()
assert sproc.pid not in [x.pid for x in psutil.process_iter()]
def test_TOTAL_PHYMEM(self):
x = psutil.TOTAL_PHYMEM
assert isinstance(x, (int, long))
assert x > 0
self.assertEqual(x, psutil.virtual_memory().total)
def test_BOOT_TIME(self):
x = psutil.BOOT_TIME
assert isinstance(x, float)
assert x > 0
assert x < time.time(), x
def test_NUM_CPUS(self):
self.assertEqual(psutil.NUM_CPUS, len(psutil.cpu_times(percpu=True)))
assert psutil.NUM_CPUS >= 1, psutil.NUM_CPUS
@skipUnless(POSIX)
def test_PAGESIZE(self):
# pagesize is used internally to perform different calculations
# and it's determined by using SC_PAGE_SIZE; make sure
# getpagesize() returns the same value.
import resource
self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize())
def test_deprecated_apis(self):
warnings.filterwarnings("error")
p = psutil.Process(os.getpid())
try:
self.assertRaises(DeprecationWarning, psutil.virtmem_usage)
self.assertRaises(DeprecationWarning, psutil.used_phymem)
self.assertRaises(DeprecationWarning, psutil.avail_phymem)
self.assertRaises(DeprecationWarning, psutil.total_virtmem)
self.assertRaises(DeprecationWarning, psutil.used_virtmem)
self.assertRaises(DeprecationWarning, psutil.avail_virtmem)
self.assertRaises(DeprecationWarning, psutil.phymem_usage)
self.assertRaises(DeprecationWarning, psutil.get_process_list)
self.assertRaises(DeprecationWarning, psutil.get_process_list)
if LINUX:
self.assertRaises(DeprecationWarning, psutil.phymem_buffers)
self.assertRaises(DeprecationWarning, psutil.cached_phymem)
try:
p.nice
except DeprecationWarning:
pass
else:
self.fail("p.nice didn't raise DeprecationWarning")
finally:
warnings.resetwarnings()
def test_deprecated_apis_retval(self):
warnings.filterwarnings("ignore")
p = psutil.Process(os.getpid())
try:
self.assertEqual(psutil.total_virtmem(), psutil.swap_memory().total)
self.assertEqual(psutil.get_process_list(), list(psutil.process_iter()))
self.assertEqual(p.nice, p.get_nice())
finally:
warnings.resetwarnings()
def test_virtual_memory(self):
mem = psutil.virtual_memory()
assert mem.total > 0, mem
assert mem.available > 0, mem
assert 0 <= mem.percent <= 100, mem
assert mem.used > 0, mem
assert mem.free >= 0, mem
for name in mem._fields:
if name != 'total':
value = getattr(mem, name)
if not value >= 0:
self.fail("%r < 0 (%s)" % (name, value))
if value > mem.total:
self.fail("%r > total (total=%s, %s=%s)" \
% (name, mem.total, name, value))
def test_swap_memory(self):
mem = psutil.swap_memory()
assert mem.total > 0, mem
assert mem.used >= 0, mem
assert mem.free > 0, mem
assert 0 <= mem.percent <= 100, mem
assert mem.sin >= 0, mem
assert mem.sout >= 0, mem
def test_pid_exists(self):
sproc = get_test_subprocess(wait=True)
assert psutil.pid_exists(sproc.pid)
p = psutil.Process(sproc.pid)
p.kill()
p.wait()
self.assertFalse(psutil.pid_exists(sproc.pid))
self.assertFalse(psutil.pid_exists(-1))
def test_pid_exists_2(self):
reap_children()
pids = psutil.get_pid_list()
for pid in pids:
try:
assert psutil.pid_exists(pid)
except AssertionError:
# in case the process disappeared in meantime fail only
# if it is no longer in get_pid_list()
time.sleep(.1)
if pid in psutil.get_pid_list():
self.fail(pid)
pids = range(max(pids) + 5000, max(pids) + 6000)
for pid in pids:
self.assertFalse(psutil.pid_exists(pid))
def test_get_pid_list(self):
plist = [x.pid for x in psutil.process_iter()]
pidlist = psutil.get_pid_list()
self.assertEqual(plist.sort(), pidlist.sort())
# make sure every pid is unique
self.assertEqual(len(pidlist), len(set(pidlist)))
def test_test(self):
# test for psutil.test() function
stdout = sys.stdout
sys.stdout = DEVNULL
try:
psutil.test()
finally:
sys.stdout = stdout
def test_sys_cpu_times(self):
total = 0
times = psutil.cpu_times()
sum(times)
for cp_time in times:
assert isinstance(cp_time, float)
assert cp_time >= 0.0, cp_time
total += cp_time
self.assertEqual(total, sum(times))
str(times)
def test_sys_cpu_times2(self):
t1 = sum(psutil.cpu_times())
time.sleep(0.1)
t2 = sum(psutil.cpu_times())
difference = t2 - t1
if not difference >= 0.05:
self.fail("difference %s" % difference)
def test_sys_per_cpu_times(self):
for times in psutil.cpu_times(percpu=True):
total = 0
sum(times)
for cp_time in times:
assert isinstance(cp_time, float)
assert cp_time >= 0.0, cp_time
total += cp_time
self.assertEqual(total, sum(times))
str(times)
def test_sys_per_cpu_times2(self):
tot1 = psutil.cpu_times(percpu=True)
stop_at = time.time() + 0.1
while 1:
if time.time() >= stop_at:
break
tot2 = psutil.cpu_times(percpu=True)
for t1, t2 in zip(tot1, tot2):
t1, t2 = sum(t1), sum(t2)
difference = t2 - t1
if difference >= 0.05:
return
self.fail()
def test_sys_cpu_percent(self):
psutil.cpu_percent(interval=0.001)
psutil.cpu_percent(interval=0.001)
for x in range(1000):
percent = psutil.cpu_percent(interval=None)
assert isinstance(percent, float)
assert percent >= 0.0, percent
assert percent <= 100.0, percent
def test_sys_per_cpu_percent(self):
psutil.cpu_percent(interval=0.001, percpu=True)
psutil.cpu_percent(interval=0.001, percpu=True)
for x in range(1000):
percents = psutil.cpu_percent(interval=None, percpu=True)
for percent in percents:
assert isinstance(percent, float)
assert percent >= 0.0, percent
assert percent <= 100.0, percent
def test_disk_usage(self):
usage = psutil.disk_usage(os.getcwd())
assert usage.total > 0, usage
assert usage.used > 0, usage
assert usage.free > 0, usage
assert usage.total > usage.used, usage
assert usage.total > usage.free, usage
assert 0 <= usage.percent <= 100, usage.percent
# if path does not exist OSError ENOENT is expected across
# all platforms
fname = tempfile.mktemp()
try:
psutil.disk_usage(fname)
except OSError:
err = sys.exc_info()[1]
if err.args[0] != errno.ENOENT:
raise
else:
self.fail("OSError not raised")
def test_disk_partitions(self):
for disk in psutil.disk_partitions(all=False):
assert os.path.exists(disk.device), disk
assert os.path.isdir(disk.mountpoint), disk
assert disk.fstype, disk
assert isinstance(disk.opts, str)
for disk in psutil.disk_partitions(all=True):
if not WINDOWS:
try:
os.stat(disk.mountpoint)
except OSError:
# http://mail.python.org/pipermail/python-dev/2012-June/120787.html
err = sys.exc_info()[1]
if err.errno not in (errno.EPERM, errno.EACCES):
raise
else:
assert os.path.isdir(disk.mountpoint), disk.mountpoint
assert isinstance(disk.fstype, str)
assert isinstance(disk.opts, str)
def find_mount_point(path):
path = os.path.abspath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path
mount = find_mount_point(__file__)
mounts = [x.mountpoint for x in psutil.disk_partitions(all=True)]
self.assertIn(mount, mounts)
psutil.disk_usage(mount)
def test_network_io_counters(self):
def check_ntuple(nt):
self.assertEqual(nt[0], nt.bytes_sent)
self.assertEqual(nt[1], nt.bytes_recv)
self.assertEqual(nt[2], nt.packets_sent)
self.assertEqual(nt[3], nt.packets_recv)
self.assertEqual(nt[4], nt.errin)
self.assertEqual(nt[5], nt.errout)
self.assertEqual(nt[6], nt.dropin)
self.assertEqual(nt[7], nt.dropout)
assert nt.bytes_sent >= 0, nt
assert nt.bytes_recv >= 0, nt
assert nt.packets_sent >= 0, nt
assert nt.packets_recv >= 0, nt
assert nt.errin >= 0, nt
assert nt.errout >= 0, nt
assert nt.dropin >= 0, nt
assert nt.dropout >= 0, nt
ret = psutil.network_io_counters(pernic=False)
check_ntuple(ret)
ret = psutil.network_io_counters(pernic=True)
assert ret != []
for key in ret:
assert key
check_ntuple(ret[key])
def test_disk_io_counters(self):
def check_ntuple(nt):
self.assertEqual(nt[0], nt.read_count)
self.assertEqual(nt[1], nt.write_count)
self.assertEqual(nt[2], nt.read_bytes)
self.assertEqual(nt[3], nt.write_bytes)
self.assertEqual(nt[4], nt.read_time)
self.assertEqual(nt[5], nt.write_time)
assert nt.read_count >= 0, nt
assert nt.write_count >= 0, nt
assert nt.read_bytes >= 0, nt
assert nt.write_bytes >= 0, nt
assert nt.read_time >= 0, nt
assert nt.write_time >= 0, nt
ret = psutil.disk_io_counters(perdisk=False)
check_ntuple(ret)
ret = psutil.disk_io_counters(perdisk=True)
for key in ret:
assert key, key
check_ntuple(ret[key])
def test_get_users(self):
users = psutil.get_users()
assert users
for user in users:
assert user.name, user
user.terminal
user.host
assert user.started > 0.0, user
datetime.datetime.fromtimestamp(user.started)
# ====================
# Process object tests
# ====================
def test_kill(self):
sproc = get_test_subprocess(wait=True)
test_pid = sproc.pid
p = psutil.Process(test_pid)
name = p.name
p.kill()
p.wait()
self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
def test_terminate(self):
sproc = get_test_subprocess(wait=True)
test_pid = sproc.pid
p = psutil.Process(test_pid)
name = p.name
p.terminate()
p.wait()
self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
def test_send_signal(self):
if POSIX:
sig = signal.SIGKILL
else:
sig = signal.SIGTERM
sproc = get_test_subprocess()
test_pid = sproc.pid
p = psutil.Process(test_pid)
name = p.name
p.send_signal(sig)
p.wait()
self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
def test_wait(self):
# check exit code signal
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.kill()
code = p.wait()
if os.name == 'posix':
self.assertEqual(code, signal.SIGKILL)
else:
self.assertEqual(code, 0)
self.assertFalse(p.is_running())
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.terminate()
code = p.wait()
if os.name == 'posix':
self.assertEqual(code, signal.SIGTERM)
else:
self.assertEqual(code, 0)
self.assertFalse(p.is_running())
# check sys.exit() code
code = "import time, sys; time.sleep(0.01); sys.exit(5);"
sproc = get_test_subprocess([PYTHON, "-c", code])
p = psutil.Process(sproc.pid)
self.assertEqual(p.wait(), 5)
self.assertFalse(p.is_running())
# Test wait() issued twice.
# It is not supposed to raise NSP when the process is gone.
# On UNIX this should return None, on Windows it should keep
# returning the exit code.
sproc = get_test_subprocess([PYTHON, "-c", code])
p = psutil.Process(sproc.pid)
self.assertEqual(p.wait(), 5)
self.assertIn(p.wait(), (5, None))
# test timeout
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.name
self.assertRaises(psutil.TimeoutExpired, p.wait, 0.01)
# timeout < 0 not allowed
self.assertRaises(ValueError, p.wait, -1)
@skipUnless(POSIX)
def test_wait_non_children(self):
# test wait() against processes which are not our children
code = "import sys;"
code += "from subprocess import Popen, PIPE;"
code += "cmd = ['%s', '-c', 'import time; time.sleep(10)'];" %PYTHON
code += "sp = Popen(cmd, stdout=PIPE);"
code += "sys.stdout.write(str(sp.pid));"
sproc = get_test_subprocess([PYTHON, "-c", code], stdout=subprocess.PIPE)
grandson_pid = int(sproc.stdout.read())
grandson_proc = psutil.Process(grandson_pid)
try:
self.assertRaises(psutil.TimeoutExpired, grandson_proc.wait, 0.01)
grandson_proc.kill()
ret = grandson_proc.wait()
self.assertEqual(ret, None)
finally:
if grandson_proc.is_running():
grandson_proc.kill()
grandson_proc.wait()
def test_wait_timeout_0(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
self.assertRaises(psutil.TimeoutExpired, p.wait, 0)
p.kill()
stop_at = time.time() + 2
while 1:
try:
code = p.wait(0)
except psutil.TimeoutExpired:
if time.time() >= stop_at:
raise
else:
break
if os.name == 'posix':
self.assertEqual(code, signal.SIGKILL)
else:
self.assertEqual(code, 0)
self.assertFalse(p.is_running())
def test_cpu_percent(self):
p = psutil.Process(os.getpid())
p.get_cpu_percent(interval=0.001)
p.get_cpu_percent(interval=0.001)
for x in range(100):
percent = p.get_cpu_percent(interval=None)
assert isinstance(percent, float)
assert percent >= 0.0, percent
if os.name != 'posix':
assert percent <= 100.0, percent
else:
assert percent >= 0.0, percent
def test_cpu_times(self):
times = psutil.Process(os.getpid()).get_cpu_times()
assert (times.user > 0.0) or (times.system > 0.0), times
# make sure returned values can be pretty printed with strftime
time.strftime("%H:%M:%S", time.localtime(times.user))
time.strftime("%H:%M:%S", time.localtime(times.system))
# Test Process.cpu_times() against os.times()
# os.times() is broken on Python 2.6
# http://bugs.python.org/issue1040026
# XXX fails on OSX: not sure if it's for os.times(). We should
# try this with Python 2.7 and re-enable the test.
@skipUnless(sys.version_info > (2, 6, 1) and not OSX)
def test_cpu_times2(self):
user_time, kernel_time = psutil.Process(os.getpid()).get_cpu_times()
utime, ktime = os.times()[:2]
# Use os.times()[:2] as base values to compare our results
# using a tolerance of +/- 0.1 seconds.
# It will fail if the difference between the values is > 0.1s.
if (max([user_time, utime]) - min([user_time, utime])) > 0.1:
self.fail("expected: %s, found: %s" %(utime, user_time))
if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1:
self.fail("expected: %s, found: %s" %(ktime, kernel_time))
def test_create_time(self):
sproc = get_test_subprocess(wait=True)
now = time.time()
p = psutil.Process(sproc.pid)
create_time = p.create_time
# Use time.time() as base value to compare our result using a
# tolerance of +/- 1 second.
# It will fail if the difference between the values is > 2s.
difference = abs(create_time - now)
if difference > 2:
self.fail("expected: %s, found: %s, difference: %s"
% (now, create_time, difference))
# make sure returned value can be pretty printed with strftime
time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time))
@skipIf(WINDOWS)
def test_terminal(self):
tty = sh('tty')
p = psutil.Process(os.getpid())
self.assertEqual(p.terminal, tty)
@skipIf(OSX, warn=False)
def test_get_io_counters(self):
p = psutil.Process(os.getpid())
# test reads
io1 = p.get_io_counters()
f = open(PYTHON, 'rb')
f.read()
f.close()
io2 = p.get_io_counters()
if not BSD:
assert io2.read_count > io1.read_count, (io1, io2)
self.assertEqual(io2.write_count, io1.write_count)
assert io2.read_bytes >= io1.read_bytes, (io1, io2)
assert io2.write_bytes >= io1.write_bytes, (io1, io2)
# test writes
io1 = p.get_io_counters()
f = tempfile.TemporaryFile()
if PY3:
f.write(bytes("x" * 1000000, 'ascii'))
else:
f.write("x" * 1000000)
f.close()
io2 = p.get_io_counters()
assert io2.write_count >= io1.write_count, (io1, io2)
assert io2.write_bytes >= io1.write_bytes, (io1, io2)
assert io2.read_count >= io1.read_count, (io1, io2)
assert io2.read_bytes >= io1.read_bytes, (io1, io2)
@skipUnless(LINUX)
def test_get_set_ionice(self):
from psutil import (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE,
IOPRIO_CLASS_IDLE)
self.assertEqual(IOPRIO_CLASS_NONE, 0)
self.assertEqual(IOPRIO_CLASS_RT, 1)
self.assertEqual(IOPRIO_CLASS_BE, 2)
self.assertEqual(IOPRIO_CLASS_IDLE, 3)
p = psutil.Process(os.getpid())
try:
p.set_ionice(2)
ioclass, value = p.get_ionice()
self.assertEqual(ioclass, 2)
self.assertEqual(value, 4)
#
p.set_ionice(3)
ioclass, value = p.get_ionice()
self.assertEqual(ioclass, 3)
self.assertEqual(value, 0)
#
p.set_ionice(2, 0)
ioclass, value = p.get_ionice()
self.assertEqual(ioclass, 2)
self.assertEqual(value, 0)
p.set_ionice(2, 7)
ioclass, value = p.get_ionice()
self.assertEqual(ioclass, 2)
self.assertEqual(value, 7)
self.assertRaises(ValueError, p.set_ionice, 2, 10)
finally:
p.set_ionice(IOPRIO_CLASS_NONE)
def test_get_num_threads(self):
# on certain platforms such as Linux we might test for exact
# thread number, since we always have with 1 thread per process,
# but this does not apply across all platforms (OSX, Windows)
p = psutil.Process(os.getpid())
step1 = p.get_num_threads()
thread = ThreadTask()
thread.start()
try:
step2 = p.get_num_threads()
self.assertEqual(step2, step1 + 1)
thread.stop()
finally:
if thread._running:
thread.stop()
@skipUnless(WINDOWS)
def test_get_num_handles(self):
# a better test is done later into test/_windows.py
p = psutil.Process(os.getpid())
assert p.get_num_handles() > 0
def test_get_threads(self):
p = psutil.Process(os.getpid())
step1 = p.get_threads()
thread = ThreadTask()
thread.start()
try:
step2 = p.get_threads()
self.assertEqual(len(step2), len(step1) + 1)
# on Linux, first thread id is supposed to be this process
if LINUX:
self.assertEqual(step2[0].id, os.getpid())
athread = step2[0]
# test named tuple
self.assertEqual(athread.id, athread[0])
self.assertEqual(athread.user_time, athread[1])
self.assertEqual(athread.system_time, athread[2])
# test num threads
thread.stop()
finally:
if thread._running:
thread.stop()
def test_get_memory_info(self):
p = psutil.Process(os.getpid())
# step 1 - get a base value to compare our results
rss1, vms1 = p.get_memory_info()
percent1 = p.get_memory_percent()
assert rss1 > 0
assert vms1 > 0
# step 2 - allocate some memory
memarr = [None] * 1500000
rss2, vms2 = p.get_memory_info()
percent2 = p.get_memory_percent()
# make sure that the memory usage bumped up
assert rss2 > rss1
assert vms2 >= vms1 # vms might be equal
assert percent2 > percent1
del memarr
# def test_get_ext_memory_info(self):
# # tested later in fetch all test suite
def test_get_memory_maps(self):
p = psutil.Process(os.getpid())
maps = p.get_memory_maps()
paths = [x for x in maps]
self.assertEqual(len(paths), len(set(paths)))
ext_maps = p.get_memory_maps(grouped=False)
for nt in maps:
if not nt.path.startswith('['):
assert os.path.isabs(nt.path), nt.path
if POSIX:
assert os.path.exists(nt.path), nt.path
else:
# XXX - On Windows we have this strange behavior with
# 64 bit dlls: they are visible via explorer but cannot
# be accessed via os.stat() (wtf?).
if '64' not in os.path.basename(nt.path):
assert os.path.exists(nt.path), nt.path
for nt in ext_maps:
for fname in nt._fields:
value = getattr(nt, fname)
if fname == 'path':
continue
elif fname in ('addr', 'perms'):
assert value, value
else:
assert isinstance(value, (int, long))
assert value >= 0, value
def test_get_memory_percent(self):
p = psutil.Process(os.getpid())
assert p.get_memory_percent() > 0.0
def test_pid(self):
sproc = get_test_subprocess()
self.assertEqual(psutil.Process(sproc.pid).pid, sproc.pid)
def test_is_running(self):
sproc = get_test_subprocess(wait=True)
p = psutil.Process(sproc.pid)
assert p.is_running()
assert p.is_running()
p.kill()
p.wait()
assert not p.is_running()
assert not p.is_running()
def test_exe(self):
sproc = get_test_subprocess(wait=True)
exe = psutil.Process(sproc.pid).exe
try:
self.assertEqual(exe, PYTHON)
except AssertionError:
# certain platforms such as BSD are more accurate returning:
# "/usr/local/bin/python2.7"
# ...instead of:
# "/usr/local/bin/python"
# We do not want to consider this difference in accuracy
# an error.
ver = "%s.%s" % (sys.version_info[0], sys.version_info[1])
self.assertEqual(exe.replace(ver, ''), PYTHON.replace(ver, ''))
def test_cmdline(self):
sproc = get_test_subprocess([PYTHON, "-E"], wait=True)
self.assertEqual(psutil.Process(sproc.pid).cmdline, [PYTHON, "-E"])
def test_name(self):
sproc = get_test_subprocess(PYTHON, wait=True)
pyexe = os.path.basename(os.path.realpath(sys.executable)).lower()
self.assertEqual(psutil.Process(sproc.pid).name.lower(), pyexe)
if os.name == 'posix':
def test_uids(self):
p = psutil.Process(os.getpid())
real, effective, saved = p.uids
# os.getuid() refers to "real" uid
self.assertEqual(real, os.getuid())
# os.geteuid() refers to "effective" uid
self.assertEqual(effective, os.geteuid())
# no such thing as os.getsuid() ("saved" uid), but starting
# from python 2.7 we have os.getresuid()[2]
if hasattr(os, "getresuid"):
self.assertEqual(saved, os.getresuid()[2])
def test_gids(self):
p = psutil.Process(os.getpid())
real, effective, saved = p.gids
# os.getuid() refers to "real" uid
self.assertEqual(real, os.getgid())
# os.geteuid() refers to "effective" uid
self.assertEqual(effective, os.getegid())
# no such thing as os.getsuid() ("saved" uid), but starting
# from python 2.7 we have os.getresgid()[2]
if hasattr(os, "getresuid"):
self.assertEqual(saved, os.getresgid()[2])
def test_nice(self):
p = psutil.Process(os.getpid())
self.assertRaises(TypeError, p.set_nice, "str")
try:
try:
first_nice = p.get_nice()
p.set_nice(1)
self.assertEqual(p.get_nice(), 1)
# going back to previous nice value raises AccessDenied on OSX
if not OSX:
p.set_nice(0)
self.assertEqual(p.get_nice(), 0)
except psutil.AccessDenied:
pass
finally:
try:
p.set_nice(first_nice)
except psutil.AccessDenied:
pass
if os.name == 'nt':
def test_nice(self):
p = psutil.Process(os.getpid())
self.assertRaises(TypeError, p.set_nice, "str")
try:
self.assertEqual(p.get_nice(), psutil.NORMAL_PRIORITY_CLASS)
p.set_nice(psutil.HIGH_PRIORITY_CLASS)
self.assertEqual(p.get_nice(), psutil.HIGH_PRIORITY_CLASS)
p.set_nice(psutil.NORMAL_PRIORITY_CLASS)
self.assertEqual(p.get_nice(), psutil.NORMAL_PRIORITY_CLASS)
finally:
p.set_nice(psutil.NORMAL_PRIORITY_CLASS)
def test_status(self):
p = psutil.Process(os.getpid())
self.assertEqual(p.status, psutil.STATUS_RUNNING)
self.assertEqual(str(p.status), "running")
def test_status_constants(self):
# STATUS_* constants are supposed to be comparable also by
# using their str representation
self.assertTrue(psutil.STATUS_RUNNING == 0)
self.assertTrue(psutil.STATUS_RUNNING == long(0))
self.assertTrue(psutil.STATUS_RUNNING == 'running')
self.assertFalse(psutil.STATUS_RUNNING == 1)
self.assertFalse(psutil.STATUS_RUNNING == 'sleeping')
self.assertFalse(psutil.STATUS_RUNNING != 0)
self.assertFalse(psutil.STATUS_RUNNING != 'running')
self.assertTrue(psutil.STATUS_RUNNING != 1)
self.assertTrue(psutil.STATUS_RUNNING != 'sleeping')
def test_username(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
if POSIX:
import pwd
self.assertEqual(p.username, pwd.getpwuid(os.getuid()).pw_name)
elif WINDOWS:
expected_username = os.environ['USERNAME']
expected_domain = os.environ['USERDOMAIN']
domain, username = p.username.split('\\')
self.assertEqual(domain, expected_domain)
self.assertEqual(username, expected_username)
else:
p.username
@skipIf(not hasattr(psutil.Process, "getcwd"))
def test_getcwd(self):
sproc = get_test_subprocess(wait=True)
p = psutil.Process(sproc.pid)
self.assertEqual(p.getcwd(), os.getcwd())
@skipIf(not hasattr(psutil.Process, "getcwd"))
def test_getcwd_2(self):
cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(10)"]
sproc = get_test_subprocess(cmd, wait=True)
p = psutil.Process(sproc.pid)
call_until(p.getcwd, "ret == os.path.dirname(os.getcwd())", timeout=1)
@skipIf(not hasattr(psutil.Process, "get_cpu_affinity"))
def test_cpu_affinity(self):
p = psutil.Process(os.getpid())
initial = p.get_cpu_affinity()
all_cpus = list(range(len(psutil.cpu_percent(percpu=True))))
#
for n in all_cpus:
p.set_cpu_affinity([n])
self.assertEqual(p.get_cpu_affinity(), [n])
#
p.set_cpu_affinity(all_cpus)
self.assertEqual(p.get_cpu_affinity(), all_cpus)
#
p.set_cpu_affinity(initial)
invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10]
self.assertRaises(ValueError, p.set_cpu_affinity, invalid_cpu)
def test_get_open_files(self):
# current process
p = psutil.Process(os.getpid())
files = p.get_open_files()
self.assertFalse(TESTFN in files)
f = open(TESTFN, 'w')
call_until(p.get_open_files, "len(ret) != %i" % len(files))
filenames = [x.path for x in p.get_open_files()]
self.assertIn(TESTFN, filenames)
f.close()
for file in filenames:
assert os.path.isfile(file), file
# another process
cmdline = "import time; f = open(r'%s', 'r'); time.sleep(100);" % TESTFN
sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True)
p = psutil.Process(sproc.pid)
for x in range(100):
filenames = [x.path for x in p.get_open_files()]
if TESTFN in filenames:
break
time.sleep(.01)
else:
self.assertIn(TESTFN, filenames)
for file in filenames:
assert os.path.isfile(file), file
def test_get_open_files2(self):
# test fd and path fields
fileobj = open(TESTFN, 'w')
p = psutil.Process(os.getpid())
for path, fd in p.get_open_files():
if path == fileobj.name or fd == fileobj.fileno():
break
else:
self.fail("no file found; files=%s" % repr(p.get_open_files()))
self.assertEqual(path, fileobj.name)
if WINDOWS:
self.assertEqual(fd, -1)
else:
self.assertEqual(fd, fileobj.fileno())
# test positions
ntuple = p.get_open_files()[0]
self.assertEqual(ntuple[0], ntuple.path)
self.assertEqual(ntuple[1], ntuple.fd)
# test file is gone
fileobj.close()
self.assertTrue(fileobj.name not in p.get_open_files())
def test_get_connections(self):
arg = "import socket, time;" \
"s = socket.socket();" \
"s.bind(('127.0.0.1', 0));" \
"s.listen(1);" \
"conn, addr = s.accept();" \
"time.sleep(100);"
sproc = get_test_subprocess([PYTHON, "-c", arg])
p = psutil.Process(sproc.pid)
for x in range(100):
cons = p.get_connections()
if cons:
break
time.sleep(.01)
self.assertEqual(len(cons), 1)
con = cons[0]
self.assertEqual(con.family, socket.AF_INET)
self.assertEqual(con.type, socket.SOCK_STREAM)
self.assertEqual(con.status, "LISTEN")
ip, port = con.local_address
self.assertEqual(ip, '127.0.0.1')
self.assertEqual(con.remote_address, ())
if WINDOWS:
self.assertEqual(con.fd, -1)
else:
assert con.fd > 0, con
# test positions
self.assertEqual(con[0], con.fd)
self.assertEqual(con[1], con.family)
self.assertEqual(con[2], con.type)
self.assertEqual(con[3], con.local_address)
self.assertEqual(con[4], con.remote_address)
self.assertEqual(con[5], con.status)
# test kind arg
self.assertRaises(ValueError, p.get_connections, 'foo')
@skipUnless(supports_ipv6())
def test_get_connections_ipv6(self):
s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
s.bind(('::1', 0))
s.listen(1)
cons = psutil.Process(os.getpid()).get_connections()
s.close()
self.assertEqual(len(cons), 1)
self.assertEqual(cons[0].local_address[0], '::1')
@skipUnless(hasattr(socket, 'AF_UNIX'))
def test_get_connections_unix(self):
# tcp
safe_remove(TESTFN)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(TESTFN)
conn = psutil.Process(os.getpid()).get_connections(kind='unix')[0]
self.assertEqual(conn.fd, sock.fileno())
self.assertEqual(conn.family, socket.AF_UNIX)
self.assertEqual(conn.type, socket.SOCK_STREAM)
self.assertEqual(conn.local_address, TESTFN)
self.assertTrue(not conn.remote_address)
self.assertTrue(not conn.status)
sock.close()
# udp
safe_remove(TESTFN)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(TESTFN)
conn = psutil.Process(os.getpid()).get_connections(kind='unix')[0]
self.assertEqual(conn.type, socket.SOCK_DGRAM)
sock.close()
@skipUnless(hasattr(socket, "fromfd") and not WINDOWS)
def test_connection_fromfd(self):
sock = socket.socket()
sock.bind(('localhost', 0))
sock.listen(1)
p = psutil.Process(os.getpid())
for conn in p.get_connections():
if conn.fd == sock.fileno():
break
else:
sock.close()
self.fail("couldn't find socket fd")
dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
try:
self.assertEqual(dupsock.getsockname(), conn.local_address)
self.assertNotEqual(sock.fileno(), dupsock.fileno())
finally:
sock.close()
dupsock.close()
def test_get_connections_all(self):
tcp_template = "import socket;" \
"s = socket.socket($family, socket.SOCK_STREAM);" \
"s.bind(('$addr', 0));" \
"s.listen(1);" \
"conn, addr = s.accept();"
udp_template = "import socket, time;" \
"s = socket.socket($family, socket.SOCK_DGRAM);" \
"s.bind(('$addr', 0));" \
"time.sleep(100);"
from string import Template
tcp4_template = Template(tcp_template).substitute(family=socket.AF_INET,
addr="127.0.0.1")
udp4_template = Template(udp_template).substitute(family=socket.AF_INET,
addr="127.0.0.1")
tcp6_template = Template(tcp_template).substitute(family=socket.AF_INET6,
addr="::1")
udp6_template = Template(udp_template).substitute(family=socket.AF_INET6,
addr="::1")
# launch various subprocess instantiating a socket of various
# families and types to enrich psutil results
tcp4_proc = get_test_subprocess([PYTHON, "-c", tcp4_template])
udp4_proc = get_test_subprocess([PYTHON, "-c", udp4_template])
if supports_ipv6():
tcp6_proc = get_test_subprocess([PYTHON, "-c", tcp6_template])
udp6_proc = get_test_subprocess([PYTHON, "-c", udp6_template])
else:
tcp6_proc = None
udp6_proc = None
# check matches against subprocesses just created
all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", "tcp6",
"udp", "udp4", "udp6")
for p in psutil.Process(os.getpid()).get_children():
for conn in p.get_connections():
# TCP v4
if p.pid == tcp4_proc.pid:
self.assertEqual(conn.family, socket.AF_INET)
self.assertEqual(conn.type, socket.SOCK_STREAM)
self.assertEqual(conn.local_address[0], "127.0.0.1")
self.assertEqual(conn.remote_address, ())
self.assertEqual(conn.status, "LISTEN")
for kind in all_kinds:
cons = p.get_connections(kind=kind)
if kind in ("all", "inet", "inet4", "tcp", "tcp4"):
assert cons != [], cons
else:
self.assertEqual(cons, [], cons)
# UDP v4
elif p.pid == udp4_proc.pid:
self.assertEqual(conn.family, socket.AF_INET)
self.assertEqual(conn.type, socket.SOCK_DGRAM)
self.assertEqual(conn.local_address[0], "127.0.0.1")
self.assertEqual(conn.remote_address, ())
self.assertEqual(conn.status, "")
for kind in all_kinds:
cons = p.get_connections(kind=kind)
if kind in ("all", "inet", "inet4", "udp", "udp4"):
assert cons != [], cons
else:
self.assertEqual(cons, [], cons)
# TCP v6
elif p.pid == getattr(tcp6_proc, "pid", None):
self.assertEqual(conn.family, socket.AF_INET6)
self.assertEqual(conn.type, socket.SOCK_STREAM)
self.assertIn(conn.local_address[0], ("::", "::1"))
self.assertEqual(conn.remote_address, ())
self.assertEqual(conn.status, "LISTEN")
for kind in all_kinds:
cons = p.get_connections(kind=kind)
if kind in ("all", "inet", "inet6", "tcp", "tcp6"):
assert cons != [], cons
else:
self.assertEqual(cons, [], cons)
# UDP v6
elif p.pid == getattr(udp6_proc, "pid", None):
self.assertEqual(conn.family, socket.AF_INET6)
self.assertEqual(conn.type, socket.SOCK_DGRAM)
self.assertIn(conn.local_address[0], ("::", "::1"))
self.assertEqual(conn.remote_address, ())
self.assertEqual(conn.status, "")
for kind in all_kinds:
cons = p.get_connections(kind=kind)
if kind in ("all", "inet", "inet6", "udp", "udp6"):
assert cons != [], cons
else:
self.assertEqual(cons, [], cons)
@skipUnless(POSIX)
def test_get_num_fds(self):
p = psutil.Process(os.getpid())
start = p.get_num_fds()
file = open(TESTFN, 'w')
self.assertEqual(p.get_num_fds(), start + 1)
sock = socket.socket()
self.assertEqual(p.get_num_fds(), start + 2)
file.close()
sock.close()
self.assertEqual(p.get_num_fds(), start)
def test_get_num_ctx_switches(self):
p = psutil.Process(os.getpid())
before = sum(p.get_num_ctx_switches())
for x in range(50000):
after = sum(p.get_num_ctx_switches())
if after > before:
return
self.fail("num ctx switches still the same after 50.000 iterations")
def test_parent_ppid(self):
this_parent = os.getpid()
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
self.assertEqual(p.ppid, this_parent)
self.assertEqual(p.parent.pid, this_parent)
# no other process is supposed to have us as parent
for p in psutil.process_iter():
if p.pid == sproc.pid:
continue
self.assertTrue(p.ppid != this_parent)
def test_get_children(self):
p = psutil.Process(os.getpid())
self.assertEqual(p.get_children(), [])
self.assertEqual(p.get_children(recursive=True), [])
sproc = get_test_subprocess()
children1 = p.get_children()
children2 = p.get_children(recursive=True)
for children in (children1, children2):
self.assertEqual(len(children), 1)
self.assertEqual(children[0].pid, sproc.pid)
self.assertEqual(children[0].ppid, os.getpid())
def test_get_children_recursive(self):
# here we create a subprocess which creates another one as in:
# A (parent) -> B (child) -> C (grandchild)
s = "import subprocess, os, sys, time;"
s += "PYTHON = os.path.realpath(sys.executable);"
s += "cmd = [PYTHON, '-c', 'import time; time.sleep(3600);'];"
s += "subprocess.Popen(cmd);"
s += "time.sleep(3600);"
get_test_subprocess(cmd=[PYTHON, "-c", s])
p = psutil.Process(os.getpid())
self.assertEqual(len(p.get_children(recursive=False)), 1)
# give the grandchild some time to start
stop_at = time.time() + 1.5
while time.time() < stop_at:
children = p.get_children(recursive=True)
if len(children) > 1:
break
self.assertEqual(len(children), 2)
self.assertEqual(children[0].ppid, os.getpid())
self.assertEqual(children[1].ppid, children[0].pid)
def test_get_children_duplicates(self):
# find the process which has the highest number of children
from psutil._compat import defaultdict
table = defaultdict(int)
for p in psutil.process_iter():
try:
table[p.ppid] += 1
except psutil.Error:
pass
# this is the one, now let's make sure there are no duplicates
pid = max(sorted(table, key=lambda x: table[x]))
p = psutil.Process(pid)
try:
c = p.get_children(recursive=True)
except psutil.AccessDenied: # windows
pass
else:
self.assertEqual(len(c), len(set(c)))
def test_suspend_resume(self):
sproc = get_test_subprocess(wait=True)
p = psutil.Process(sproc.pid)
p.suspend()
for x in range(100):
if p.status == psutil.STATUS_STOPPED:
break
time.sleep(0.01)
self.assertEqual(str(p.status), "stopped")
p.resume()
assert p.status != psutil.STATUS_STOPPED, p.status
def test_invalid_pid(self):
self.assertRaises(TypeError, psutil.Process, "1")
self.assertRaises(TypeError, psutil.Process, None)
# Refers to Issue #12
self.assertRaises(psutil.NoSuchProcess, psutil.Process, -1)
def test_as_dict(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
d = p.as_dict()
try:
import json
except ImportError:
pass
else:
# dict is supposed to be hashable
json.dumps(d)
#
d = p.as_dict(attrs=['exe', 'name'])
self.assertEqual(sorted(d.keys()), ['exe', 'name'])
#
p = psutil.Process(min(psutil.get_pid_list()))
d = p.as_dict(attrs=['get_connections'], ad_value='foo')
if not isinstance(d['connections'], list):
self.assertEqual(d['connections'], 'foo')
def test_zombie_process(self):
# Test that NoSuchProcess exception gets raised in case the
# process dies after we create the Process object.
# Example:
# >>> proc = Process(1234)
# >>> time.sleep(5) # time-consuming task, process dies in meantime
# >>> proc.name
# Refers to Issue #15
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.kill()
p.wait()
for name in dir(p):
if name.startswith('_')\
or name in ('pid', 'send_signal', 'is_running', 'set_ionice',
'wait', 'set_cpu_affinity', 'create_time', 'set_nice',
'nice'):
continue
try:
meth = getattr(p, name)
if callable(meth):
meth()
except psutil.NoSuchProcess:
pass
else:
self.fail("NoSuchProcess exception not raised for %r" % name)
# other methods
try:
if os.name == 'posix':
p.set_nice(1)
else:
p.set_nice(psutil.NORMAL_PRIORITY_CLASS)
except psutil.NoSuchProcess:
pass
else:
self.fail("exception not raised")
if hasattr(p, 'set_ionice'):
self.assertRaises(psutil.NoSuchProcess, p.set_ionice, 2)
self.assertRaises(psutil.NoSuchProcess, p.send_signal, signal.SIGTERM)
self.assertRaises(psutil.NoSuchProcess, p.set_nice, 0)
self.assertFalse(p.is_running())
if hasattr(p, "set_cpu_affinity"):
self.assertRaises(psutil.NoSuchProcess, p.set_cpu_affinity, [0])
def test__str__(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
self.assertIn(str(sproc.pid), str(p))
# python shows up as 'Python' in cmdline on OS X so test fails on OS X
if not OSX:
self.assertIn(os.path.basename(PYTHON), str(p))
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.kill()
p.wait()
self.assertIn(str(sproc.pid), str(p))
self.assertIn("terminated", str(p))
@skipIf(LINUX)
def test_pid_0(self):
# Process(0) is supposed to work on all platforms except Linux
p = psutil.Process(0)
self.assertTrue(p.name)
if os.name == 'posix':
self.assertEqual(p.uids.real, 0)
self.assertEqual(p.gids.real, 0)
self.assertIn(p.ppid, (0, 1))
#self.assertEqual(p.exe, "")
self.assertEqual(p.cmdline, [])
try:
p.get_num_threads()
except psutil.AccessDenied:
pass
try:
p.get_memory_info()
except psutil.AccessDenied:
pass
# username property
if POSIX:
self.assertEqual(p.username, 'root')
elif WINDOWS:
self.assertEqual(p.username, 'NT AUTHORITY\\SYSTEM')
else:
p.username
self.assertIn(0, psutil.get_pid_list())
self.assertTrue(psutil.pid_exists(0))
def test_Popen(self):
# Popen class test
# XXX this test causes a ResourceWarning on Python 3 because
# psutil.__subproc instance doesn't get propertly freed.
# Not sure what to do though.
cmd = [PYTHON, "-c", "import time; time.sleep(3600);"]
proc = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
try:
proc.name
proc.stdin
self.assertTrue(hasattr(proc, 'name'))
self.assertTrue(hasattr(proc, 'stdin'))
self.assertRaises(AttributeError, getattr, proc, 'foo')
finally:
proc.kill()
proc.wait()
class TestFetchAllProcesses(unittest.TestCase):
# Iterates over all running processes and performs some sanity
# checks against Process API's returned values.
# Python 2.4 compatibility
if not hasattr(unittest.TestCase, "assertIn"):
def assertIn(self, member, container, msg=None):
if member not in container:
self.fail(msg or \
'%s not found in %s' % (repr(member), repr(container)))
def setUp(self):
if POSIX:
import pwd
pall = pwd.getpwall()
self._uids = set([x.pw_uid for x in pall])
self._usernames = set([x.pw_name for x in pall])
def test_fetch_all(self):
valid_procs = 0
excluded_names = ['send_signal', 'suspend', 'resume', 'terminate',
'kill', 'wait', 'as_dict', 'get_cpu_percent', 'nice',
'parent', 'get_children', 'pid']
attrs = []
for name in dir(psutil.Process):
if name.startswith("_"):
continue
if name.startswith("set_"):
continue
if name in excluded_names:
continue
attrs.append(name)
for p in psutil.process_iter():
for name in attrs:
try:
try:
attr = getattr(p, name, None)
if attr is not None and callable(attr):
ret = attr()
else:
ret = attr
valid_procs += 1
except (psutil.NoSuchProcess, psutil.AccessDenied):
err = sys.exc_info()[1]
self.assertEqual(err.pid, p.pid)
if err.name:
# make sure exception's name attr is set
# with the actual process name
self.assertEqual(err.name, p.name)
self.assertTrue(str(err))
self.assertTrue(err.msg)
else:
if ret not in (0, 0.0, [], None, ''):
assert ret, ret
meth = getattr(self, name)
meth(ret)
except Exception:
err = sys.exc_info()[1]
trace = traceback.format_exc()
self.fail('%s\nproc=%s, method=%r, retvalue=%r'
% (trace, p, name, ret))
# we should always have a non-empty list, not including PID 0 etc.
# special cases.
self.assertTrue(valid_procs > 0)
def cmdline(self, ret):
pass
def exe(self, ret):
if not ret:
assert ret == ''
else:
assert os.path.isabs(ret), ret
# Note: os.stat() may return False even if the file is there
# hence we skip the test, see:
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
if POSIX:
assert os.path.isfile(ret), ret
if hasattr(os, 'access') and hasattr(os, "X_OK"):
self.assertTrue(os.access(ret, os.X_OK))
def ppid(self, ret):
self.assertTrue(ret >= 0)
def name(self, ret):
self.assertTrue(isinstance(ret, str))
self.assertTrue(ret)
def create_time(self, ret):
self.assertTrue(ret > 0)
if not WINDOWS:
self.assertTrue(ret >= psutil.BOOT_TIME)
# make sure returned value can be pretty printed
# with strftime
time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret))
def uids(self, ret):
for uid in ret:
self.assertTrue(uid >= 0)
self.assertIn(uid, self._uids)
def gids(self, ret):
# note: testing all gids as above seems not to be reliable for
# gid == 30 (nodoby); not sure why.
for gid in ret:
self.assertTrue(gid >= 0)
#self.assertIn(uid, self.gids)
def username(self, ret):
self.assertTrue(ret)
if os.name == 'posix':
self.assertIn(ret, self._usernames)
def status(self, ret):
self.assertTrue(ret >= 0)
self.assertTrue(str(ret) != '?')
def get_io_counters(self, ret):
for field in ret:
if field != -1:
self.assertTrue(field >= 0)
def get_ionice(self, ret):
self.assertTrue(ret.ioclass >= 0)
self.assertTrue(ret.value >= 0)
def get_num_threads(self, ret):
self.assertTrue(ret >= 1)
def get_threads(self, ret):
for t in ret:
self.assertTrue(t.id >= 0)
self.assertTrue(t.user_time >= 0)
self.assertTrue(t.system_time >= 0)
def get_cpu_times(self, ret):
self.assertTrue(ret.user >= 0)
self.assertTrue(ret.system >= 0)
def get_memory_info(self, ret):
self.assertTrue(ret.rss >= 0)
self.assertTrue(ret.vms >= 0)
def get_ext_memory_info(self, ret):
for name in ret._fields:
self.assertTrue(getattr(ret, name) >= 0)
if POSIX and ret.vms != 0:
# VMS is always supposed to be the highest
for name in ret._fields:
if name != 'vms':
value = getattr(ret, name)
assert ret.vms > value, ret
elif WINDOWS:
assert ret.peak_wset >= ret.wset, ret
assert ret.peak_paged_pool >= ret.paged_pool, ret
assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret
assert ret.peak_pagefile >= ret.pagefile, ret
def get_open_files(self, ret):
for f in ret:
if WINDOWS:
assert f.fd == -1, f
else:
assert isinstance(f.fd, int), f
assert os.path.isabs(f.path), f
assert os.path.isfile(f.path), f
def get_num_fds(self, ret):
self.assertTrue(ret >= 0)
def get_connections(self, ret):
# all values are supposed to match Linux's tcp_states.h states
# table across all platforms.
valid_conn_states = ["ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1",
"FIN_WAIT2", "TIME_WAIT", "CLOSE", "CLOSE_WAIT",
"LAST_ACK", "LISTEN", "CLOSING", ""]
for conn in ret:
self.assertIn(conn.type, (socket.SOCK_STREAM, socket.SOCK_DGRAM))
self.assertIn(conn.family, (socket.AF_INET, socket.AF_INET6))
check_ip_address(conn.local_address, conn.family)
check_ip_address(conn.remote_address, conn.family)
if conn.status not in valid_conn_states:
self.fail("%s is not a valid status" %conn.status)
# actually try to bind the local socket; ignore IPv6
# sockets as their address might be represented as
# an IPv4-mapped-address (e.g. "::127.0.0.1")
# and that's rejected by bind()
if conn.family == socket.AF_INET:
s = socket.socket(conn.family, conn.type)
s.bind((conn.local_address[0], 0))
s.close()
if not WINDOWS and hasattr(socket, 'fromfd'):
dupsock = None
try:
try:
dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
except (socket.error, OSError):
err = sys.exc_info()[1]
if err.args[0] == errno.EBADF:
continue
raise
# python >= 2.5
if hasattr(dupsock, "family"):
self.assertEqual(dupsock.family, conn.family)
self.assertEqual(dupsock.type, conn.type)
finally:
if dupsock is not None:
dupsock.close()
def getcwd(self, ret):
if ret is not None: # BSD may return None
assert os.path.isabs(ret), ret
try:
st = os.stat(ret)
except OSError:
err = sys.exc_info()[1]
# directory has been removed in mean time
if err.errno != errno.ENOENT:
raise
else:
self.assertTrue(stat.S_ISDIR(st.st_mode))
def get_memory_percent(self, ret):
assert 0 <= ret <= 100, ret
def is_running(self, ret):
self.assertTrue(ret)
def get_cpu_affinity(self, ret):
assert ret != [], ret
def terminal(self, ret):
if ret is not None:
assert os.path.isabs(ret), ret
assert os.path.exists(ret), ret
def get_memory_maps(self, ret):
for nt in ret:
for fname in nt._fields:
value = getattr(nt, fname)
if fname == 'path':
if not value.startswith('['):
assert os.path.isabs(nt.path), nt.path
# commented as on Linux we might get '/foo/bar (deleted)'
#assert os.path.exists(nt.path), nt.path
elif fname in ('addr', 'perms'):
self.assertTrue(value)
else:
assert isinstance(value, (int, long))
assert value >= 0, value
def get_num_handles(self, ret):
if WINDOWS:
assert ret >= 0
else:
assert ret > 0
def get_nice(self, ret):
if POSIX:
assert -20 <= ret <= 20, ret
else:
priorities = [getattr(psutil, x) for x in dir(psutil)
if x.endswith('_PRIORITY_CLASS')]
self.assertIn(ret, priorities)
def get_num_ctx_switches(self, ret):
self.assertTrue(ret.voluntary >= 0)
self.assertTrue(ret.involuntary >= 0)
if hasattr(os, 'getuid'):
class LimitedUserTestCase(TestCase):
"""Repeat the previous tests by using a limited user.
Executed only on UNIX and only if the user who run the test script
is root.
"""
# the uid/gid the test suite runs under
PROCESS_UID = os.getuid()
PROCESS_GID = os.getgid()
def __init__(self, *args, **kwargs):
TestCase.__init__(self, *args, **kwargs)
# re-define all existent test methods in order to
# ignore AccessDenied exceptions
for attr in [x for x in dir(self) if x.startswith('test')]:
meth = getattr(self, attr)
def test_(self):
try:
meth()
except psutil.AccessDenied:
pass
setattr(self, attr, types.MethodType(test_, self))
def setUp(self):
os.setegid(1000)
os.seteuid(1000)
TestCase.setUp(self)
def tearDown(self):
os.setegid(self.PROCESS_UID)
os.seteuid(self.PROCESS_GID)
TestCase.tearDown(self)
def test_nice(self):
try:
psutil.Process(os.getpid()).set_nice(-1)
except psutil.AccessDenied:
pass
else:
self.fail("exception not raised")
def cleanup():
reap_children(search_all=True)
DEVNULL.close()
safe_remove(TESTFN)
atexit.register(cleanup)
def test_main():
tests = []
test_suite = unittest.TestSuite()
tests.append(TestCase)
tests.append(TestFetchAllProcesses)
if POSIX:
from _posix import PosixSpecificTestCase
tests.append(PosixSpecificTestCase)
# import the specific platform test suite
if LINUX:
from _linux import LinuxSpecificTestCase as stc
elif WINDOWS:
from _windows import WindowsSpecificTestCase as stc
from _windows import TestDualProcessImplementation
tests.append(TestDualProcessImplementation)
elif OSX:
from _osx import OSXSpecificTestCase as stc
elif BSD:
from _bsd import BSDSpecificTestCase as stc
tests.append(stc)
if hasattr(os, 'getuid'):
if os.getuid() == 0:
tests.append(LimitedUserTestCase)
else:
atexit.register(warn, "Couldn't run limited user tests ("
"super-user privileges are required)")
for test_class in tests:
test_suite.addTest(unittest.makeSuite(test_class))
unittest.TextTestRunner(verbosity=2).run(test_suite)
if __name__ == '__main__':
test_main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment