new file mode 100644
--- /dev/null
+++ b/python/psutil/CREDITS
@@ -0,0 +1,119 @@
+
+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
new file mode 100644
--- /dev/null
+++ b/python/psutil/HISTORY
@@ -0,0 +1,463 @@
+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.
new file mode 100644
--- /dev/null
+++ b/python/psutil/INSTALL
@@ -0,0 +1,110 @@
+==================
+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
+
new file mode 100644
--- /dev/null
+++ b/python/psutil/LICENSE
@@ -0,0 +1,27 @@
+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.
new file mode 100644
--- /dev/null
+++ b/python/psutil/MANIFEST.in
@@ -0,0 +1,9 @@
+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
new file mode 100644
--- /dev/null
+++ b/python/psutil/PKG-INFO
@@ -0,0 +1,252 @@
+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
new file mode 100644
--- /dev/null
+++ b/python/psutil/README
@@ -0,0 +1,208 @@
+===========
+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
+>>>
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/disk_usage.py
@@ -0,0 +1,48 @@
+#!/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())
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/free.py
@@ -0,0 +1,33 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/iotop.py
@@ -0,0 +1,161 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/killall.py
@@ -0,0 +1,33 @@
+#!/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())
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/meminfo.py
@@ -0,0 +1,33 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/netstat.py
@@ -0,0 +1,52 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/nettop.py
@@ -0,0 +1,144 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/pmap.py
@@ -0,0 +1,37 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/process_detail.py
@@ -0,0 +1,134 @@
+#!/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())
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/top.py
@@ -0,0 +1,200 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/examples/who.py
@@ -0,0 +1,32 @@
+#!/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()
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/__init__.py
@@ -0,0 +1,1195 @@
+#!/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("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
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_common.py
@@ -0,0 +1,193 @@
+#/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')
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_compat.py
@@ -0,0 +1,270 @@
+#!/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
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psbsd.py
@@ -0,0 +1,328 @@
+#!/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
new file mode 100755
--- /dev/null
+++ b/python/psutil/psutil/_pslinux.py
@@ -0,0 +1,1011 @@
+#!/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)
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psmswindows.py
@@ -0,0 +1,423 @@
+#!/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))
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psosx.py
@@ -0,0 +1,293 @@
+#!/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)
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psposix.py
@@ -0,0 +1,118 @@
+#!/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
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_bsd.c
@@ -0,0 +1,1777 @@
+/*
+ * $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(
+ ¤t.duration[DEVSTAT_READ], NULL), // r time
+ (long long)devstat_compute_etime(
+ ¤t.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
+}
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_bsd.h
@@ -0,0 +1,52 @@
+/*
+ * $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);
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_common.c
@@ -0,0 +1,39 @@
+/*
+ * $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;
+}
+
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_common.h
@@ -0,0 +1,13 @@
+/*
+ * $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);
+
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_linux.c
@@ -0,0 +1,338 @@
+/*
+ * $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
+}
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_linux.h
@@ -0,0 +1,19 @@
+/*
+ * $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);
new file mode 100644
--- /dev/null
+++ b/python/psutil/psutil/_psutil_mswindows.c
@@ -0,0 +1,2904 @@
+/*
+ * $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,
+ ¤tDirectory, sizeof(currentDirectory), NULL))
+#else
+ if (!ReadProcessMemory(processHandle, (PCHAR)rtlUserProcParamsAddress + 0x24,
+ ¤tDirectory, sizeof(currentDirectory), NULL))
+#endif
+ {
+ CloseHandle(processHandle);
+ if (GetLastError() == ERROR_PARTIAL_COPY) {
+ // this occurs quite often with system processes
+ return AccessDenied();
+ }
+ else {
+ return PyErr_SetFromWindowsErr(0);
+ }
+ }
+
+ // allocate memory to hold cwd
+ currentDirectoryContent = (WCHAR *)malloc(currentDirectory.Length+1);
+
+ // 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++;
+ }
+ ret