psutil-3.4.2/0000775000175000017500000000000012647732503015015 5ustar giampaologiampaolo00000000000000psutil-3.4.2/DEVNOTES.rst0000666000175000017500000000030112635015712016763 0ustar giampaologiampaolo00000000000000NetBSD ====== Setup ----- - $ PKG_PATH="http://ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/i386/7.0/All" $ export PKG_PATH $ pkg_add -v pkgin $ pkgin install git python27 screen wget gcc psutil-3.4.2/README.rst0000664000175000017500000004265712647732434016525 0ustar giampaologiampaolo00000000000000.. image:: https://img.shields.io/pypi/dm/psutil.svg :target: https://pypi.python.org/pypi/psutil#downloads :alt: Downloads this month .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master :target: https://travis-ci.org/giampaolo/psutil :alt: Linux tests (Travis) .. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true :target: https://ci.appveyor.com/project/giampaolo/psutil :alt: Windows tests (Appveyor) .. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github :target: https://coveralls.io/github/giampaolo/psutil?branch=master :alt: Test coverage (coverall.io) .. image:: https://img.shields.io/pypi/v/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: Latest version .. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg :target: https://github.com/giampaolo/psutil/ :alt: Github stars .. image:: https://img.shields.io/pypi/l/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: License =========== Quick links =========== - `Home page `_ - `Documentation `_ - `Installation `_ - `Download `_ - `Forum `_ - `Blog `_ - `Development guide `_ - `What's new `_ ======= Summary ======= psutil (python system and process utilities) is a cross-platform library for retrieving information on **running processes** and **system utilization** (CPU, memory, disks, network) in Python. It is useful mainly for **system monitoring**, **profiling and limiting process resources** and **management of running processes**. It implements many functionalities offered by command line tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports **Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD** and **NetBSD**, both **32-bit** and **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of Python 2.4 and 2.5 may use `2.1.3 `__ version). `PyPy `__ is also known to work. ==================== Example applications ==================== .. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/top.png :alt: top .. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/nettop.png :alt: nettop .. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/iotop.png :alt: iotop See also: * https://github.com/nicolargo/glances * https://github.com/google/grr * https://github.com/Jahaja/psdash ============== Example usages ============== CPU === .. code-block:: python >>> import psutil >>> psutil.cpu_times() scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0) >>> >>> 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, 3.7, 9.2] [7.0, 8.5, 2.4, 2.1] [1.2, 9.0, 9.9, 7.2] >>> >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) >>> >>> psutil.cpu_count() 4 >>> psutil.cpu_count(logical=False) 2 >>> Memory ====== .. code-block:: python >>> psutil.virtual_memory() svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) >>> psutil.swap_memory() sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== .. code-block:: python >>> psutil.disk_partitions() [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= .. code-block:: python >>> psutil.net_io_counters(pernic=True) {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] >>> >>> psutil.net_if_addrs() {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None), snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None), snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)], 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None), snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None), snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]} >>> >>> psutil.net_if_stats() {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} Other system info ================= .. code-block:: python >>> psutil.users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.boot_time() 1365519115.0 >>> Process management ================== .. code-block:: python >>> import psutil >>> psutil.pids() [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.cwd() '/home/giampaolo' >>> p.cmdline() ['/usr/bin/python', 'main.py'] >>> >>> p.status() 'running' >>> p.username() 'giampaolo' >>> p.create_time() 1267551141.5019531 >>> p.terminal() '/dev/pts/0' >>> >>> p.uids() puids(real=1000, effective=1000, saved=1000) >>> p.gids() pgids(real=1000, effective=1000, saved=1000) >>> >>> p.cpu_times() pcputimes(user=1.02, system=0.31) >>> p.cpu_percent(interval=1.0) 12.1 >>> p.cpu_affinity() [0, 1, 2, 3] >>> p.cpu_affinity([0]) # set >>> >>> p.memory_percent() 0.63423 >>> >>> p.memory_info() pmem(rss=7471104, vms=68513792) >>> p.memory_info_ex() extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.memory_maps() [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0), pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.io_counters() pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.open_files() [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 >>> p.num_fds() 8 >>> p.threads() [pthread(id=5234, user_time=22.5, system_time=9.2891), pthread(id=5235, user_time=0.0, system_time=0.0), pthread(id=5236, user_time=0.0, system_time=0.0), pthread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.num_ctx_switches() pctxsw(voluntary=78, involuntary=19) >>> >>> p.nice() 0 >>> p.nice(10) # set >>> >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) >>> p.ionice() pionice(ioclass=, value=0) >>> >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) >>> p.rlimit(psutil.RLIMIT_NOFILE) (5, 5) >>> >>> 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 >>> Further process APIs ==================== .. code-block:: python >>> for p in psutil.process_iter(): ... print(p) ... psutil.Process(pid=1, name='init') psutil.Process(pid=2, name='kthreadd') psutil.Process(pid=3, name='ksoftirqd/0') ... >>> >>> def on_terminate(proc): ... print("process {} terminated".format(proc)) ... >>> # waits for multiple processes to terminate >>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate) >>> ====== Donate ====== A lot of time and effort went into making psutil as it is right now. If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' `_) some money. I only ask for a small donation, but of course I appreciate any amount. .. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8 :alt: Donate via PayPal Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin `_. ============ Mailing list ============ http://groups.google.com/group/psutil/ ======== Timeline ======== - 2016-01-20: `psutil-3.4.2.tar.gz `_ - 2016-01-15: `psutil-3.4.1.tar.gz `_ - 2015-11-25: `psutil-3.3.0.tar.gz `_ - 2015-10-04: `psutil-3.2.2.tar.gz `_ - 2015-09-03: `psutil-3.2.1.tar.gz `_ - 2015-09-02: `psutil-3.2.0.tar.gz `_ - 2015-07-15: `psutil-3.1.1.tar.gz `_ - 2015-07-15: `psutil-3.1.0.tar.gz `_ - 2015-06-18: `psutil-3.0.1.tar.gz `_ - 2015-06-13: `psutil-3.0.0.tar.gz `_ - 2015-02-02: `psutil-2.2.1.tar.gz `_ - 2015-01-06: `psutil-2.2.0.tar.gz `_ - 2014-09-26: `psutil-2.1.3.tar.gz `_ - 2014-09-21: `psutil-2.1.2.tar.gz `_ - 2014-04-30: `psutil-2.1.1.tar.gz `_ - 2014-04-08: `psutil-2.1.0.tar.gz `_ - 2014-03-10: `psutil-2.0.0.tar.gz `_ - 2013-11-25: `psutil-1.2.1.tar.gz `_ - 2013-11-20: `psutil-1.2.0.tar.gz `_ - 2013-11-07: `psutil-1.1.3.tar.gz `_ - 2013-10-22: `psutil-1.1.2.tar.gz `_ - 2013-10-08: `psutil-1.1.1.tar.gz `_ - 2013-09-28: `psutil-1.1.0.tar.gz `_ - 2013-07-12: `psutil-1.0.1.tar.gz `_ - 2013-07-10: `psutil-1.0.0.tar.gz `_ - 2013-05-03: `psutil-0.7.1.tar.gz `_ - 2013-04-12: `psutil-0.7.0.tar.gz `_ - 2012-08-16: `psutil-0.6.1.tar.gz `_ - 2012-08-13: `psutil-0.6.0.tar.gz `_ - 2012-06-29: `psutil-0.5.1.tar.gz `_ - 2012-06-27: `psutil-0.5.0.tar.gz `_ - 2011-12-14: `psutil-0.4.1.tar.gz `_ - 2011-10-29: `psutil-0.4.0.tar.gz `_ - 2011-07-08: `psutil-0.3.0.tar.gz `_ - 2011-03-20: `psutil-0.2.1.tar.gz `_ - 2010-11-13: `psutil-0.2.0.tar.gz `_ - 2010-03-02: `psutil-0.1.3.tar.gz `_ - 2009-05-06: `psutil-0.1.2.tar.gz `_ - 2009-03-06: `psutil-0.1.1.tar.gz `_ - 2009-01-27: `psutil-0.1.0.tar.gz `_ psutil-3.4.2/PKG-INFO0000664000175000017500000005577512647732502016134 0ustar giampaologiampaolo00000000000000Metadata-Version: 1.1 Name: psutil Version: 3.4.2 Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python. Home-page: https://github.com/giampaolo/psutil Author: Giampaolo Rodola Author-email: g.rodola gmail com License: BSD Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg :target: https://pypi.python.org/pypi/psutil#downloads :alt: Downloads this month .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master :target: https://travis-ci.org/giampaolo/psutil :alt: Linux tests (Travis) .. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true :target: https://ci.appveyor.com/project/giampaolo/psutil :alt: Windows tests (Appveyor) .. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github :target: https://coveralls.io/github/giampaolo/psutil?branch=master :alt: Test coverage (coverall.io) .. image:: https://img.shields.io/pypi/v/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: Latest version .. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg :target: https://github.com/giampaolo/psutil/ :alt: Github stars .. image:: https://img.shields.io/pypi/l/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: License =========== Quick links =========== - `Home page `_ - `Documentation `_ - `Installation `_ - `Download `_ - `Forum `_ - `Blog `_ - `Development guide `_ - `What's new `_ ======= Summary ======= psutil (python system and process utilities) is a cross-platform library for retrieving information on **running processes** and **system utilization** (CPU, memory, disks, network) in Python. It is useful mainly for **system monitoring**, **profiling and limiting process resources** and **management of running processes**. It implements many functionalities offered by command line tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports **Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD** and **NetBSD**, both **32-bit** and **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of Python 2.4 and 2.5 may use `2.1.3 `__ version). `PyPy `__ is also known to work. ==================== Example applications ==================== .. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/top.png :alt: top .. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/nettop.png :alt: nettop .. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/iotop.png :alt: iotop See also: * https://github.com/nicolargo/glances * https://github.com/google/grr * https://github.com/Jahaja/psdash ============== Example usages ============== CPU === .. code-block:: python >>> import psutil >>> psutil.cpu_times() scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0) >>> >>> 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, 3.7, 9.2] [7.0, 8.5, 2.4, 2.1] [1.2, 9.0, 9.9, 7.2] >>> >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) >>> >>> psutil.cpu_count() 4 >>> psutil.cpu_count(logical=False) 2 >>> Memory ====== .. code-block:: python >>> psutil.virtual_memory() svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) >>> psutil.swap_memory() sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== .. code-block:: python >>> psutil.disk_partitions() [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= .. code-block:: python >>> psutil.net_io_counters(pernic=True) {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] >>> >>> psutil.net_if_addrs() {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None), snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None), snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)], 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None), snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None), snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]} >>> >>> psutil.net_if_stats() {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} Other system info ================= .. code-block:: python >>> psutil.users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.boot_time() 1365519115.0 >>> Process management ================== .. code-block:: python >>> import psutil >>> psutil.pids() [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.cwd() '/home/giampaolo' >>> p.cmdline() ['/usr/bin/python', 'main.py'] >>> >>> p.status() 'running' >>> p.username() 'giampaolo' >>> p.create_time() 1267551141.5019531 >>> p.terminal() '/dev/pts/0' >>> >>> p.uids() puids(real=1000, effective=1000, saved=1000) >>> p.gids() pgids(real=1000, effective=1000, saved=1000) >>> >>> p.cpu_times() pcputimes(user=1.02, system=0.31) >>> p.cpu_percent(interval=1.0) 12.1 >>> p.cpu_affinity() [0, 1, 2, 3] >>> p.cpu_affinity([0]) # set >>> >>> p.memory_percent() 0.63423 >>> >>> p.memory_info() pmem(rss=7471104, vms=68513792) >>> p.memory_info_ex() extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.memory_maps() [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0), pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.io_counters() pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.open_files() [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 >>> p.num_fds() 8 >>> p.threads() [pthread(id=5234, user_time=22.5, system_time=9.2891), pthread(id=5235, user_time=0.0, system_time=0.0), pthread(id=5236, user_time=0.0, system_time=0.0), pthread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.num_ctx_switches() pctxsw(voluntary=78, involuntary=19) >>> >>> p.nice() 0 >>> p.nice(10) # set >>> >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) >>> p.ionice() pionice(ioclass=, value=0) >>> >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) >>> p.rlimit(psutil.RLIMIT_NOFILE) (5, 5) >>> >>> 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 >>> Further process APIs ==================== .. code-block:: python >>> for p in psutil.process_iter(): ... print(p) ... psutil.Process(pid=1, name='init') psutil.Process(pid=2, name='kthreadd') psutil.Process(pid=3, name='ksoftirqd/0') ... >>> >>> def on_terminate(proc): ... print("process {} terminated".format(proc)) ... >>> # waits for multiple processes to terminate >>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate) >>> ====== Donate ====== A lot of time and effort went into making psutil as it is right now. If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' `_) some money. I only ask for a small donation, but of course I appreciate any amount. .. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8 :alt: Donate via PayPal Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin `_. ============ Mailing list ============ http://groups.google.com/group/psutil/ ======== Timeline ======== - 2016-01-20: `psutil-3.4.2.tar.gz `_ - 2016-01-15: `psutil-3.4.1.tar.gz `_ - 2015-11-25: `psutil-3.3.0.tar.gz `_ - 2015-10-04: `psutil-3.2.2.tar.gz `_ - 2015-09-03: `psutil-3.2.1.tar.gz `_ - 2015-09-02: `psutil-3.2.0.tar.gz `_ - 2015-07-15: `psutil-3.1.1.tar.gz `_ - 2015-07-15: `psutil-3.1.0.tar.gz `_ - 2015-06-18: `psutil-3.0.1.tar.gz `_ - 2015-06-13: `psutil-3.0.0.tar.gz `_ - 2015-02-02: `psutil-2.2.1.tar.gz `_ - 2015-01-06: `psutil-2.2.0.tar.gz `_ - 2014-09-26: `psutil-2.1.3.tar.gz `_ - 2014-09-21: `psutil-2.1.2.tar.gz `_ - 2014-04-30: `psutil-2.1.1.tar.gz `_ - 2014-04-08: `psutil-2.1.0.tar.gz `_ - 2014-03-10: `psutil-2.0.0.tar.gz `_ - 2013-11-25: `psutil-1.2.1.tar.gz `_ - 2013-11-20: `psutil-1.2.0.tar.gz `_ - 2013-11-07: `psutil-1.1.3.tar.gz `_ - 2013-10-22: `psutil-1.1.2.tar.gz `_ - 2013-10-08: `psutil-1.1.1.tar.gz `_ - 2013-09-28: `psutil-1.1.0.tar.gz `_ - 2013-07-12: `psutil-1.0.1.tar.gz `_ - 2013-07-10: `psutil-1.0.0.tar.gz `_ - 2013-05-03: `psutil-0.7.1.tar.gz `_ - 2013-04-12: `psutil-0.7.0.tar.gz `_ - 2012-08-16: `psutil-0.6.1.tar.gz `_ - 2012-08-13: `psutil-0.6.0.tar.gz `_ - 2012-06-29: `psutil-0.5.1.tar.gz `_ - 2012-06-27: `psutil-0.5.0.tar.gz `_ - 2011-12-14: `psutil-0.4.1.tar.gz `_ - 2011-10-29: `psutil-0.4.0.tar.gz `_ - 2011-07-08: `psutil-0.3.0.tar.gz `_ - 2011-03-20: `psutil-0.2.1.tar.gz `_ - 2010-11-13: `psutil-0.2.0.tar.gz `_ - 2010-03-02: `psutil-0.1.3.tar.gz `_ - 2009-05-06: `psutil-0.1.2.tar.gz `_ - 2009-03-06: `psutil-0.1.1.tar.gz `_ - 2009-01-27: `psutil-0.1.0.tar.gz `_ Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit Platform: Platform Independent Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Environment :: Win32 (MS Windows) Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000 Classifier: Operating System :: Microsoft Classifier: Operating System :: OS Independent Classifier: Operating System :: POSIX :: BSD :: FreeBSD Classifier: Operating System :: POSIX :: BSD :: NetBSD Classifier: Operating System :: POSIX :: BSD :: OpenBSD Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: SunOS/Solaris Classifier: Operating System :: POSIX Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 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: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Benchmark Classifier: Topic :: System :: Hardware Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking :: Monitoring Classifier: Topic :: System :: Networking Classifier: Topic :: System :: Operating System Classifier: Topic :: System :: Systems Administration Classifier: Topic :: Utilities psutil-3.4.2/MANIFEST.in0000664000175000017500000000076712646164026016563 0ustar giampaologiampaolo00000000000000include .coveragerc include .git-pre-commit include .gitignore include .travis.yml include appveyor.yml include CREDITS include DEVNOTES.rst include HISTORY.rst include INSTALL.rst include LICENSE include make.bat include Makefile include MANIFEST.in include README.rst include setup.py include TODO include tox.ini recursive-exclude docs/_build * recursive-include .ci * recursive-include docs * recursive-include examples *.py recursive-include psutil *.py *.c *.h recursive-include test *.py README* psutil-3.4.2/.git-pre-commit0000775000175000017500000000270112573063206017651 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # This gets executed on 'git commit' and rejects the commit in case the # submitted code does not pass validation. # Install it with "make install-git-hooks" import os import subprocess import sys def main(): out = subprocess.check_output("git diff --cached --name-only", shell=True) files = [x for x in out.split('\n') if x.endswith('.py') and os.path.exists(x)] for path in files: with open(path) as f: data = f.read() # pdb if "pdb.set_trace" in data: for lineno, line in enumerate(data.split('\n'), 1): line = line.rstrip() if "pdb.set_trace" in line: print("%s: %s" % (lineno, line)) sys.exit( "commit aborted: you forgot a pdb in your python code") # bare except clause if "except:" in data: for lineno, line in enumerate(data.split('\n'), 1): line = line.rstrip() if "except:" in line and not line.endswith("# NOQA"): print("%s: %s" % (lineno, line)) sys.exit("commit aborted: bare except clause") # flake8 failed = False for path in files: ret = subprocess.call("python -m flake8 %s" % path, shell=True) if ret != 0: failed = True if failed: sys.exit("commit aborted: python code is not flake8-compliant") main() psutil-3.4.2/.coveragerc0000664000175000017500000000047712572074510017140 0ustar giampaologiampaolo00000000000000[report] include = *psutil* omit = test/* *setup* *_compat.py* exclude_lines = pragma: no cover if __name__ == .__main__.: if sys.platform.startswith if _WINDOWS: import enum if enum is not None: if enum is None: if has_enums: enum.IntEnum except ImportError: psutil-3.4.2/TODO0000664000175000017500000001272512634032632015504 0ustar giampaologiampaolo00000000000000TODO ==== A collection of ideas and notes about stuff to implement in future versions. "#NNN" occurrences refer to bug tracker issues at: https://github.com/giampaolo/psutil/issues PLATFORMS ========= * #429 (patch): NetBSD * #355 (patch): Android * #605 (branch): AIX * #276: GNU/Hurd * DragonFlyBSD HIGHER PRIORITY =============== * #371: CPU temperature (apparently OSX and Linux only; on Linux it requires lm-sensors lib). * #269: expose network ifaces RX/TW queues. This should probably go into net_if_stats(). Figure out on what platforms this is supported: Linux: yes Others: ? * Process.threads(): thread names; patch for OSX available at: https://code.google.com/p/plcrashreporter/issues/detail?id=65 Sample code: https://github.com/janmojzis/pstree/blob/master/proc_kvm.c * Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964) * (Windows) fall back on using WMIC for Process methods returning AccessDenied * #613: thread names. * #604: emulate os.getloadavg() on Windows * #269: NIC rx/tx queue. LOWER PRIORITY ============== * examples/taskmgr-gui.py (using tk). * system-wide number of open file descriptors: * https://jira.hyperic.com/browse/SIGAR-30 * http://www.netadmintools.com/part295.html * Number of system threads. * Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684824(v=vs.85).aspx * #357: what CPU a process is on. * Doc / wiki which compares similarities between UNIX cli tools and psutil. Example: df -a -> psutil.disk_partitions lsof -> psutil.Process.open_files() and psutil.Process.open_connections() killall-> (actual script) tty -> psutil.Process.terminal() who -> psutil.users() DEBATABLE ========= * psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for all running processes in one shot. This can be factored out from Process.children() and exposed as a first class function. PROS: on Windows we can take advantage of _psutil_windows.ppid_map() which is faster than iterating over all pids and calling ppid(). CONS: examples/pstree.py shows this can be easily done in the user code so maybe it's not worth the addition. * advanced cmdline interface exposing the whole API and providing different kind of outputs (e.g. pprinted, colorized, json). * [Linux]: process cgroups (http://en.wikipedia.org/wiki/Cgroups). They look similar to prlimit() in terms of functionality but uglier (they should allow limiting per-process network IO resources though, which is great). Needs further reading. * Should we expose OS constants (psutil.WINDOWS, psutil.OSX etc.)? * Python 3.3. exposed different sched.h functions: http://docs.python.org/dev/whatsnew/3.3.html#os http://bugs.python.org/issue12655 http://docs.python.org/dev/library/os.html#interface-to-the-scheduler It might be worth to take a look and figure out whether we can include some of those in psutil. Also, we can probably reimplement wait_pid() on POSIX which is currently implemented as a busy-loop. * Certain systems provide CPU times about process children. On those systems Process.cpu_times() might return a (user, system, user_children, system_children) ntuple. * Linux: /proc/{PID}/stat * Solaris: pr_cutime and pr_cstime * FreeBSD: none * OSX: none * Windows: none * ...also, os.times() provides 'elapsed' times as well. * ...also Linux provides guest_time and cguest_time. * Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that: - NoSuchProcess inherits from ProcessLookupError - AccessDenied inherits from PermissionError - TimeoutExpired inherits from TimeoutError (debatable) See: http://docs.python.org/3/library/exceptions.html#os-exceptions * Process.threads() might grow an extra "id" parameter so that it can be used as such: >>> p = psutil.Process(os.getpid()) >>> p.threads(id=psutil.current_thread_id()) thread(id=2539, user_time=0.03, system_time=0.02) >>> Note: this leads to questions such as "should we have a custom NoSuchThread exception? Also see issue #418. Note #2: this would work with os.getpid() only. psutil.current_thread_id() might be desirable as per issue #418 though. * should psutil.TimeoutExpired exception have a 'msg' kwarg similar to NoSuchProcess and AccessDenied? Not that we need it, but currently we cannot raise a TimeoutExpired exception with a specific error string. * process_iter() might grow an "attrs" parameter similar to Process.as_dict() invoke the necessary methods and include the results into a "cache" attribute attached to the returned Process instances so that one can avoid catching NSP and AccessDenied: for p in process_iter(attrs=['cpu_percent']): print(p.cache['cpu_percent']) This also leads questions as whether we should introduce a sorting order. * round Process.memory_percent() result? * #550: number of threads per core. * Have psutil.Process().cpu_affinity([]) be an alias for "all CPUs"? COMPATIBILITY BREAKAGE ====================== Removals (will likely happen in 2.2): * (S) psutil.Process.nice (deprecated in 0.5.0) * (S) get_process_list (deprecated in 0.5.0) * (S) psutil.*mem* functions (deprecated in 0.3.0 and 0.6.0) * (M) psutil.network_io_counters (deprecated in 1.0.0) * (M) local_address and remote_address Process.connection() namedtuple fields (deprecated in 1.0.0) REJECTED IDEAS ============== STUB psutil-3.4.2/.gitignore0000664000175000017500000000016712572074510017003 0ustar giampaologiampaolo00000000000000syntax: glob *.al *.bak *.egg-info *.la *.lo *.o *.orig *.pyc *.pyd *.rej *.so *.swp .cache/ .idea/ .tox/ build/ dist/ psutil-3.4.2/make.bat0000664000175000017500000001513112617432670016422 0ustar giampaologiampaolo00000000000000@echo off rem ========================================================================== rem Shortcuts for various tasks, emulating UNIX "make" on Windows. rem It is primarly intended as a shortcut for compiling / installing rem psutil ("make.bat build", "make.bat install") and running tests rem ("make.bat test"). rem rem This script is modeled after my Windows installation which uses: rem - Visual studio 2008 for Python 2.6, 2.7, 3.2 rem - Visual studio 2010 for Python 3.3+ rem ...therefore it might not work on your Windows installation. rem rem By default C:\Python27\python.exe is used. rem To compile for a specific Python version run: rem set PYTHON=C:\Python34\python.exe & make.bat build rem rem To use a different test script: rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test rem ========================================================================== if "%PYTHON%" == "" ( set PYTHON=C:\Python27\python.exe ) if "%TSCRIPT%" == "" ( set TSCRIPT=test\test_psutil.py ) set PYTHON26=C:\Python26\python.exe set PYTHON27=C:\Python27\python.exe set PYTHON33=C:\Python33\python.exe set PYTHON34=C:\Python34\python.exe set PYTHON35=C:\Python35\python.exe set PYTHON26-64=C:\Python26-64\python.exe set PYTHON27-64=C:\Python27-64\python.exe set PYTHON33-64=C:\Python33-64\python.exe set PYTHON34-64=C:\Python34-64\python.exe set PYTHON35-64=C:\Python35-64\python.exe set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON35% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64% %PYTHON35-64% rem Needed to locate the .pypirc file and upload exes on PYPI. set HOME=%USERPROFILE% rem ========================================================================== if "%1" == "help" ( :help echo Run `make ^` where ^ is one of: echo build compile without installing echo build-all build exes + wheels echo clean clean build files echo flake8 run flake8 echo install compile and install echo setup-dev-env install pip, pywin32, wheels, etc. for all python versions echo test run tests echo test-memleaks run memory leak tests echo test-process run process related tests echo test-system run system APIs related tests echo uninstall uninstall echo upload-all upload exes + wheels goto :eof ) if "%1" == "clean" ( for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R) for /r %%R in (*.pyc) do if exist %%R (del /s %%R) for /r %%R in (*.pyd) do if exist %%R (del /s %%R) for /r %%R in (*.orig) do if exist %%R (del /s %%R) for /r %%R in (*.bak) do if exist %%R (del /s %%R) for /r %%R in (*.rej) do if exist %%R (del /s %%R) if exist psutil.egg-info (rmdir /S /Q psutil.egg-info) if exist build (rmdir /S /Q build) if exist dist (rmdir /S /Q dist) goto :eof ) if "%1" == "build" ( :build "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" %PYTHON% setup.py build if %errorlevel% neq 0 goto :error rem copies *.pyd files in ./psutil directory in order to allow rem "import psutil" when using the interactive interpreter from rem within this directory. %PYTHON% setup.py build_ext -i if %errorlevel% neq 0 goto :error goto :eof ) if "%1" == "install" ( :install call :build %PYTHON% setup.py install goto :eof ) if "%1" == "uninstall" ( for %%A in ("%PYTHON%") do ( set folder=%%~dpA ) for /F "delims=" %%i in ('dir /b %folder%\Lib\site-packages\*psutil*') do ( rmdir /S /Q %folder%\Lib\site-packages\%%i ) goto :eof ) if "%1" == "test" ( call :install %PYTHON% %TSCRIPT% goto :eof ) if "%1" == "test-process" ( call :install %PYTHON% -m unittest -v test.test_psutil.TestProcess goto :eof ) if "%1" == "test-system" ( call :install %PYTHON% -m unittest -v test.test_psutil.TestSystem goto :eof ) if "%1" == "test-memleaks" ( call :install %PYTHON% test\test_memory_leaks.py goto :eof ) if "%1" == "build-all" ( :build-all "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" for %%P in (%ALL_PYTHONS%) do ( @echo ------------------------------------------------ @echo building exe for %%P @echo ------------------------------------------------ %%P setup.py build bdist_wininst || goto :error @echo ------------------------------------------------ @echo building wheel for %%P @echo ------------------------------------------------ %%P setup.py build bdist_wheel || goto :error ) echo OK goto :eof ) if "%1" == "upload-all" ( :upload-exes "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" for %%P in (%ALL_PYTHONS%) do ( @echo ------------------------------------------------ @echo uploading exe for %%P @echo ------------------------------------------------ %%P setup.py build bdist_wininst upload || goto :error @echo ------------------------------------------------ @echo uploading wheel for %%P @echo ------------------------------------------------ %%P setup.py build bdist_wheel upload || goto :error ) echo OK goto :eof ) if "%1" == "setup-dev-env" ( :setup-env @echo ------------------------------------------------ @echo downloading pip installer @echo ------------------------------------------------ C:\python27\python.exe -c "import urllib2; r = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); open('get-pip.py', 'wb').write(r.read())" for %%P in (%ALL_PYTHONS%) do ( @echo ------------------------------------------------ @echo installing pip for %%P @echo ------------------------------------------------ %%P get-pip.py ) for %%P in (%ALL_PYTHONS%) do ( @echo ------------------------------------------------ @echo installing deps for %%P @echo ------------------------------------------------ rem mandatory / for unittests %%P -m pip install unittest2 ipaddress mock wmi wheel pypiwin32 --upgrade rem nice to have %%P -m pip install ipdb pep8 pyflakes flake8 --upgrade ) goto :eof ) if "%1" == "flake8" ( :flake8 %PYTHON% -c "from flake8.main import main; main()" goto :eof ) goto :help :error @echo ------------------------------------------------ @echo last command exited with error code %errorlevel% @echo ------------------------------------------------ @exit /b %errorlevel% goto :eof psutil-3.4.2/examples/0000775000175000017500000000000012647732502016632 5ustar giampaologiampaolo00000000000000psutil-3.4.2/examples/ps.py0000775000175000017500000000473512572074510017635 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 'ps -aux' on UNIX. $ python examples/ps.py ... """ import datetime import os import time import psutil def main(): today_day = datetime.date.today() templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s" attrs = ['pid', 'cpu_percent', 'memory_percent', 'name', 'cpu_times', 'create_time', 'memory_info'] if os.name == 'posix': attrs.append('uids') attrs.append('terminal') print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "START", "TIME", "COMMAND")) for p in psutil.process_iter(): try: pinfo = p.as_dict(attrs, ad_value='') except psutil.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") else: ctime = '' cputime = time.strftime("%M:%S", time.localtime(sum(pinfo['cpu_times']))) try: user = p.username() except KeyError: if os.name == 'posix': if pinfo['uids']: user = str(pinfo['uids'].real) else: user = '' else: raise except psutil.Error: user = '' 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__': main() psutil-3.4.2/examples/ifconfig.py0000775000175000017500000000462312572074510020773 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 'ifconfig' on UNIX. $ python examples/ifconfig.py lo (speed=0MB, duplex=?, mtu=65536, up=yes): IPv4 address : 127.0.0.1 broadcast : 127.0.0.1 netmask : 255.0.0.0 IPv6 address : ::1 netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff MAC address : 00:00:00:00:00:00 broadcast : 00:00:00:00:00:00 wlan0 (speed=0MB, duplex=?, mtu=1500, up=yes): IPv4 address : 10.0.3.1 broadcast : 10.0.3.255 netmask : 255.255.255.0 IPv6 address : fe80::3005:adff:fe31:8698 netmask : ffff:ffff:ffff:ffff:: MAC address : 32:05:ad:31:86:98 broadcast : ff:ff:ff:ff:ff:ff eth0 (speed=100MB, duplex=full, mtu=1500, up=yes): IPv4 address : 192.168.1.2 broadcast : 192.168.1.255 netmask : 255.255.255.0 IPv6 address : fe80::c685:8ff:fe45:641 netmask : ffff:ffff:ffff:ffff:: MAC address : c4:85:08:45:06:41 broadcast : ff:ff:ff:ff:ff:ff """ from __future__ import print_function import socket import psutil af_map = { socket.AF_INET: 'IPv4', socket.AF_INET6: 'IPv6', psutil.AF_LINK: 'MAC', } duplex_map = { psutil.NIC_DUPLEX_FULL: "full", psutil.NIC_DUPLEX_HALF: "half", psutil.NIC_DUPLEX_UNKNOWN: "?", } def main(): stats = psutil.net_if_stats() for nic, addrs in psutil.net_if_addrs().items(): if nic in stats: print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % ( nic, stats[nic].speed, duplex_map[stats[nic].duplex], stats[nic].mtu, "yes" if stats[nic].isup else "no")) else: print("%s:" % (nic)) for addr in addrs: print(" %-8s" % af_map.get(addr.family, addr.family), end="") print(" address : %s" % addr.address) if addr.broadcast: print(" broadcast : %s" % addr.broadcast) if addr.netmask: print(" netmask : %s" % addr.netmask) if addr.ptp: print(" p2p : %s" % addr.ptp) print("") if __name__ == '__main__': main() psutil-3.4.2/examples/meminfo.py0000775000175000017500000000271512572074510020641 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. $ python examples/meminfo.py MEMORY ------ Total : 9.7G Available : 4.9G Percent : 49.0 Used : 8.2G Free : 1.4G Active : 5.6G Inactive : 2.1G Buffers : 341.2M Cached : 3.2G SWAP ---- Total : 0B Used : 0B Free : 0B Percent : 0.0 Sin : 0B Sout : 0B """ import psutil 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 pprint_ntuple(nt): for name in nt._fields: value = getattr(nt, name) if name != 'percent': value = bytes2human(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() psutil-3.4.2/examples/disk_usage.py0000775000175000017500000000371212572074510021323 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. $ python examples/disk_usage.py Device Total Used Free Use % Type Mount /dev/sdb3 18.9G 14.7G 3.3G 77% ext4 / /dev/sda6 345.9G 83.8G 244.5G 24% ext4 /home /dev/sda1 296.0M 43.1M 252.9M 14% vfat /boot/efi /dev/sda2 600.0M 312.4M 287.6M 52% fuseblk /media/Recovery """ import sys import os import psutil 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): if os.name == 'nt': if 'cdrom' in part.opts or part.fstype == '': # skip cd-rom drives with no disk in it; they may raise # ENOENT, pop-up a Windows GUI error for a non-ready # partition or just hang. continue 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()) psutil-3.4.2/examples/iotop.py0000775000175000017500000001177112572074510020343 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. Example output: $ python examples/iotop.py Total DISK READ: 0.00 B/s | Total DISK WRITE: 472.00 K/s PID USER DISK READ DISK WRITE COMMAND 13155 giampao 0.00 B/s 428.00 K/s /usr/bin/google-chrome-beta 3260 giampao 0.00 B/s 0.00 B/s bash 3779 giampao 0.00 B/s 0.00 B/s gnome-session --session=ubuntu 3830 giampao 0.00 B/s 0.00 B/s /usr/bin/dbus-launch 3831 giampao 0.00 B/s 0.00 B/s //bin/dbus-daemon --fork --print-pid 5 3841 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi-bus-launcher 3845 giampao 0.00 B/s 0.00 B/s /bin/dbus-daemon 3848 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi2-core/at-spi2-registryd 3862 giampao 0.00 B/s 0.00 B/s /usr/lib/gnome-settings-daemon Author: Giampaolo Rodola' """ import atexit import time import sys try: import curses except ImportError: sys.exit('platform not supported') 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/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.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.io_counters() p._cmdline = ' '.join(p.cmdline()) if not p._cmdline: p._cmdline = p.name() p._username = p.username() except (psutil.NoSuchProcess, psutil.ZombieProcess): 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 True: args = poll(interval) refresh_window(*args) interval = 1 except (KeyboardInterrupt, SystemExit): pass if __name__ == '__main__': main() psutil-3.4.2/examples/killall.py0000775000175000017500000000123712572074510020631 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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()) psutil-3.4.2/examples/free.py0000775000175000017500000000217212572074510020125 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. $ python examples/free.py total used free shared buffers cache Mem: 10125520 8625996 1499524 0 349500 3307836 Swap: 0 0 0 """ import psutil 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() psutil-3.4.2/examples/pmap.py0000775000175000017500000000363012572074510020141 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. $ python examples/pmap.py 32402 pid=32402, name=hg Address RSS Mode Mapping 0000000000400000 1200K r-xp /usr/bin/python2.7 0000000000838000 4K r--p /usr/bin/python2.7 0000000000839000 304K rw-p /usr/bin/python2.7 00000000008ae000 68K rw-p [anon] 000000000275e000 5396K rw-p [heap] 00002b29bb1e0000 124K r-xp /lib/x86_64-linux-gnu/ld-2.17.so 00002b29bb203000 8K rw-p [anon] 00002b29bb220000 528K rw-p [anon] 00002b29bb2d8000 768K rw-p [anon] 00002b29bb402000 4K r--p /lib/x86_64-linux-gnu/ld-2.17.so 00002b29bb403000 8K rw-p /lib/x86_64-linux-gnu/ld-2.17.so 00002b29bb405000 60K r-xp /lib/x86_64-linux-gnu/libpthread-2.17.so 00002b29bb41d000 0K ---p /lib/x86_64-linux-gnu/libpthread-2.17.so 00007fff94be6000 48K rw-p [stack] 00007fff94dd1000 4K r-xp [vdso] ffffffffff600000 0K r-xp [vsyscall] ... """ import sys import psutil def main(): if len(sys.argv) != 2: sys.exit('usage: pmap ') 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.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() psutil-3.4.2/examples/pidof.py0000775000175000017500000000222412572074510020303 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, Giampaolo Rodola', karthikrev. 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 'pidof' cmdline utility. $ pidof python 1140 1138 1136 1134 1133 1129 1127 1125 1121 1120 1119 """ from __future__ import print_function import psutil import sys def pidof(pgname): pids = [] for proc in psutil.process_iter(): # search for matches in the process name and cmdline try: name = proc.name() except psutil.Error: pass else: if name == pgname: pids.append(str(proc.pid)) continue try: cmdline = proc.cmdline() except psutil.Error: pass else: if cmdline and cmdline[0] == pgname: pids.append(str(proc.pid)) return pids def main(): if len(sys.argv) != 2: sys.exit('usage: %s pgname' % __file__) else: pgname = sys.argv[1] pids = pidof(pgname) if pids: print(" ".join(pids)) if __name__ == '__main__': main() psutil-3.4.2/examples/netstat.py0000775000175000017500000000357412572074510020675 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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 -antp' on Linux. $ python examples/netstat.py Proto Local address Remote address Status PID Program name tcp 127.0.0.1:48256 127.0.0.1:45884 ESTABLISHED 13646 chrome tcp 127.0.0.1:47073 127.0.0.1:45884 ESTABLISHED 13646 chrome tcp 127.0.0.1:47072 127.0.0.1:45884 ESTABLISHED 13646 chrome tcp 127.0.0.1:45884 - LISTEN 13651 GoogleTalkPlugi tcp 127.0.0.1:60948 - LISTEN 13651 GoogleTalkPlugi tcp 172.17.42.1:49102 127.0.0.1:19305 CLOSE_WAIT 13651 GoogleTalkPlugi tcp 172.17.42.1:55797 127.0.0.1:443 CLOSE_WAIT 13651 GoogleTalkPlugi ... """ import socket from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM import psutil 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 %-30s %-30s %-13s %-6s %s" print(templ % ( "Proto", "Local address", "Remote address", "Status", "PID", "Program name")) proc_names = {} for p in psutil.process_iter(): try: proc_names[p.pid] = p.name() except psutil.Error: pass for c in psutil.net_connections(kind='inet'): laddr = "%s:%s" % (c.laddr) raddr = "" if c.raddr: raddr = "%s:%s" % (c.raddr) print(templ % ( proto_map[(c.family, c.type)], laddr, raddr or AD, c.status, c.pid or AD, proc_names.get(c.pid, '?')[:15], )) if __name__ == '__main__': main() psutil-3.4.2/examples/who.py0000775000175000017500000000156612572074510020007 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. $ python examples/who.py giampaolo tty7 2014-02-23 17:25 (:0) giampaolo pts/7 2014-02-24 18:25 (:192.168.1.56) giampaolo pts/8 2014-02-24 18:25 (:0) giampaolo pts/9 2014-02-27 01:32 (:0) """ from datetime import datetime import psutil def main(): users = psutil.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() psutil-3.4.2/examples/nettop.py0000775000175000017500000001115012572074510020511 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # # $Id: iotop.py 1160 2011-10-14 18:50:36Z g.rodola@gmail.com $ # # Copyright (c) 2009, 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' $ python examples/nettop.py ----------------------------------------------------------- total bytes: sent: 1.49 G received: 4.82 G total packets: sent: 7338724 received: 8082712 wlan0 TOTAL PER-SEC ----------------------------------------------------------- bytes-sent 1.29 G 0.00 B/s bytes-recv 3.48 G 0.00 B/s pkts-sent 7221782 0 pkts-recv 6753724 0 eth1 TOTAL PER-SEC ----------------------------------------------------------- bytes-sent 131.77 M 0.00 B/s bytes-recv 1.28 G 0.00 B/s pkts-sent 0 0 pkts-recv 1214470 0 """ import atexit import time import sys try: import curses except ImportError: sys.exit('platform not supported') 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.net_io_counters() pnic_before = psutil.net_io_counters(pernic=True) # sleep some time time.sleep(interval) tot_after = psutil.net_io_counters() pnic_after = psutil.net_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 True: args = poll(interval) refresh_window(*args) interval = 1 except (KeyboardInterrupt, SystemExit): pass if __name__ == '__main__': main() psutil-3.4.2/examples/top.py0000775000175000017500000001636312612744236020021 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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' $ python examples/top.py CPU0 [| ] 4.9% CPU1 [||| ] 7.8% CPU2 [ ] 2.0% CPU3 [||||| ] 13.9% Mem [||||||||||||||||||| ] 49.8% 4920M/9888M Swap [ ] 0.0% 0M/0M Processes: 287 (running=1 sleeping=286) Load average: 0.34 0.54 0.46 Uptime: 3 days, 10:16:37 PID USER NI VIRT RES CPU% MEM% TIME+ NAME ------------------------------------------------------------ 989 giampaol 0 66M 12M 7.4 0.1 0:00.61 python 2083 root 0 506M 159M 6.5 1.6 0:29.26 Xorg 4503 giampaol 0 599M 25M 6.5 0.3 3:32.60 gnome-terminal 3868 giampaol 0 358M 8M 2.8 0.1 23:12.60 pulseaudio 3936 giampaol 0 1G 111M 2.8 1.1 33:41.67 compiz 4401 giampaol 0 536M 141M 2.8 1.4 35:42.73 skype 4047 giampaol 0 743M 76M 1.8 0.8 42:03.33 unity-panel-service 13155 giampaol 0 1G 280M 1.8 2.8 41:57.34 chrome 10 root 0 0B 0B 0.9 0.0 4:01.81 rcu_sched 339 giampaol 0 1G 113M 0.9 1.1 8:15.73 chrome ... """ from datetime import datetime from datetime import timedelta import atexit import os import sys import time try: import curses except ImportError: sys.exit('platform not supported') 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', 'nice', 'memory_info', 'memory_percent', 'cpu_percent', 'cpu_times', 'name', 'status']) try: procs_status[p.dict['status']] += 1 except KeyError: procs_status[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 percs = psutil.cpu_percent(interval=0, percpu=True) for cpu_num, perc in enumerate(percs): 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'] is not 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'] = '' if p.dict['username']: username = p.dict['username'][:8] else: username = "" line = templ % (p.pid, username, 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 True: args = poll(interval) refresh_window(*args) interval = 1 except (KeyboardInterrupt, SystemExit): pass if __name__ == '__main__': main() psutil-3.4.2/examples/process_detail.py0000775000175000017500000001214412572074510022204 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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' $ python examples/process_detail.py pid 820 name python exe /usr/bin/python2.7 parent 29613 (bash) cmdline python examples/process_detail.py started 2014-41-27 03:41 user giampaolo uids real=1000, effective=1000, saved=1000 gids real=1000, effective=1000, saved=1000 terminal /dev/pts/17 cwd /ssd/svn/psutil memory 0.1% (resident=10.6M, virtual=58.5M) cpu 0.0% (user=0.09, system=0.0) status running niceness 0 num threads 1 I/O bytes-read=0B, bytes-written=0B open files running threads id=820, user-time=0.09, sys-time=0.0 """ import datetime import os import socket import sys import psutil POSIX = os.name == 'posix' 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 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 as err: sys.exit(str(err)) try: parent = p.parent() if parent: parent = '(%s)' % parent.name() else: parent = '' except psutil.Error: parent = '' if pinfo['create_time'] != ACCESS_DENIED: started = datetime.datetime.fromtimestamp( pinfo['create_time']).strftime('%Y-%m-%d %H:%M') else: started = ACCESS_DENIED io = pinfo.get('io_counters', ACCESS_DENIED) if pinfo['memory_info'] != ACCESS_DENIED: mem = '%s%% (resident=%s, virtual=%s) ' % ( round(pinfo['memory_percent'], 1), convert_bytes(pinfo['memory_info'].rss), convert_bytes(pinfo['memory_info'].vms)) else: mem = ACCESS_DENIED children = p.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 POSIX and pinfo['uids'] and pinfo['gids']: print_('uids', 'real=%s, effective=%s, saved=%s' % pinfo['uids']) if POSIX and pinfo['gids']: print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids']) if POSIX: print_('terminal', pinfo['terminal'] or '') print_('cwd', pinfo['cwd']) print_('memory', mem) print_('cpu', '%s%% (user=%s, system=%s)' % ( pinfo['cpu_percent'], getattr(pinfo['cpu_times'], 'user', '?'), getattr(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'] not in (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.laddr if not conn.raddr: rip, rport = '*', '*' else: rip, rport = conn.raddr 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()) psutil-3.4.2/examples/pstree.py0000775000175000017500000000323312633605765020517 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. """ Similar to 'ps aux --forest' on Linux, prints the process list as a tree structure. $ python examples/pstree.py 0 ? |- 1 init | |- 289 cgmanager | |- 616 upstart-socket-bridge | |- 628 rpcbind | |- 892 upstart-file-bridge | |- 907 dbus-daemon | |- 978 avahi-daemon | | `_ 979 avahi-daemon | |- 987 NetworkManager | | |- 2242 dnsmasq | | `_ 10699 dhclient | |- 993 polkitd | |- 1061 getty | |- 1066 su | | `_ 1190 salt-minion... ... """ from __future__ import print_function import collections import sys import psutil def print_tree(parent, tree, indent=''): try: name = psutil.Process(parent).name() except psutil.Error: name = "?" print(parent, name) if parent not in tree: return children = tree[parent][:-1] for child in children: sys.stdout.write(indent + "|- ") print_tree(child, tree, indent + "| ") child = tree[parent][-1] sys.stdout.write(indent + "`_ ") print_tree(child, tree, indent + " ") def main(): # construct a dict where 'values' are all the processes # having 'key' as their parent tree = collections.defaultdict(list) for p in psutil.process_iter(): try: tree[p.ppid()].append(p.pid) except (psutil.NoSuchProcess, psutil.ZombieProcess): pass # on systems supporting PID 0, PID 0's parent is usually 0 if 0 in tree and 0 in tree[0]: tree[0].remove(0) print_tree(min(tree), tree) if __name__ == '__main__': main() psutil-3.4.2/test/0000775000175000017500000000000012647732502015773 5ustar giampaologiampaolo00000000000000psutil-3.4.2/test/README.rst0000664000175000017500000000143712572074510017462 0ustar giampaologiampaolo00000000000000- The recommended way to run tests (also on Windows) is to cd into parent directory and run ``make test`` - Dependencies for running tests: - python 2.6: ipaddress, mock, unittest2 - python 2.7: ipaddress, mock - python 3.2: ipaddress, mock - python 3.3: ipaddress - python >= 3.4: no deps required - The main test script is ``test_psutil.py``, which also imports platform-specific ``_*.py`` scripts (which should be ignored). - ``test_memory_leaks.py`` looks for memory leaks into C extension modules and must be run separately with ``make test-memleaks``. - To run tests on all supported Python version install tox (pip install tox) then run ``tox``. - Every time a commit is pushed tests are automatically run on Travis: https://travis-ci.org/giampaolo/psutil/ psutil-3.4.2/test/test_psutil.py0000664000175000017500000035567412646126646020755 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """ psutil test suite. Run it with: $ make test If you're on Python < 2.7 unittest2 module must be installed first: https://pypi.python.org/pypi/unittest2 """ from __future__ import division import ast import atexit import collections import contextlib import datetime import errno import functools import json import imp import os import pickle import pprint import re import select import shutil import signal import socket import stat import subprocess import sys import tempfile import textwrap import threading import time import traceback import types import warnings from socket import AF_INET from socket import SOCK_DGRAM from socket import SOCK_STREAM try: import ipaddress # python >= 3.3 except ImportError: ipaddress = None try: from unittest import mock # py3 except ImportError: import mock # requires "pip install mock" import psutil from psutil._common import supports_ipv6 from psutil._compat import callable from psutil._compat import long from psutil._compat import PY3 from psutil._compat import unicode from psutil._compat import which if sys.version_info < (2, 7): import unittest2 as unittest # requires "pip install unittest2" else: import unittest if sys.version_info >= (3, 4): import enum else: enum = None if PY3: import importlib # python <=3.3 if not hasattr(importlib, 'reload'): import imp as importlib else: import imp as importlib # =================================================================== # --- Constants # =================================================================== # conf for retry_before_failing() decorator NO_RETRIES = 10 # bytes tolerance for OS memory related tests MEMORY_TOLERANCE = 500 * 1024 # 500KB # the timeout used in functions which have to wait GLOBAL_TIMEOUT = 3 AF_INET6 = getattr(socket, "AF_INET6") AF_UNIX = getattr(socket, "AF_UNIX", None) PYTHON = os.path.realpath(sys.executable) DEVNULL = open(os.devnull, 'r+') TESTFN = os.path.join(os.getcwd(), "$testfile") TESTFN_UNICODE = TESTFN + "ƒőő" TESTFILE_PREFIX = 'psutil-test-suite-' if not PY3: try: TESTFN_UNICODE = unicode(TESTFN_UNICODE, sys.getfilesystemencoding()) except UnicodeDecodeError: TESTFN_UNICODE = TESTFN + "???" EXAMPLES_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'examples')) POSIX = os.name == 'posix' WINDOWS = os.name == 'nt' if WINDOWS: WIN_VISTA = (6, 0, 0) LINUX = sys.platform.startswith("linux") OSX = sys.platform.startswith("darwin") FREEBSD = sys.platform.startswith("freebsd") OPENBSD = sys.platform.startswith("openbsd") NETBSD = sys.platform.startswith("netbsd") BSD = FREEBSD or OPENBSD or NETBSD SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] # whether we're running this test suite on Travis (https://travis-ci.org/) TRAVIS = bool(os.environ.get('TRAVIS')) # whether we're running this test suite on Appveyor for Windows # (http://www.appveyor.com/) APPVEYOR = bool(os.environ.get('APPVEYOR')) if TRAVIS or 'tox' in sys.argv[0]: import ipaddress if TRAVIS or APPVEYOR: GLOBAL_TIMEOUT = GLOBAL_TIMEOUT * 4 # =================================================================== # --- Utility functions # =================================================================== def cleanup(): reap_children(search_all=True) safe_remove(TESTFN) try: safe_rmdir(TESTFN_UNICODE) except UnicodeEncodeError: pass for path in _testfiles: safe_remove(path) atexit.register(cleanup) atexit.register(lambda: DEVNULL.close()) _subprocesses_started = set() def get_test_subprocess(cmd=None, stdout=DEVNULL, stderr=DEVNULL, stdin=DEVNULL, wait=False): """Return a subprocess.Popen object to use in tests. By default stdout and stderr are redirected to /dev/null and the python interpreter is used as test process. If 'wait' is True attemps to make sure the process is in a reasonably initialized state. """ if cmd is None: pyline = "" if wait: pyline += "open(r'%s', 'w'); " % TESTFN pyline += "import time; time.sleep(60);" cmd_ = [PYTHON, "-c", pyline] else: cmd_ = cmd sproc = subprocess.Popen(cmd_, stdout=stdout, stderr=stderr, stdin=stdin) if wait: if cmd is None: stop_at = time.time() + 3 while stop_at > time.time(): if os.path.exists(TESTFN): break time.sleep(0.001) else: warn("couldn't make sure test file was actually created") else: wait_for_pid(sproc.pid) _subprocesses_started.add(psutil.Process(sproc.pid)) return sproc _testfiles = [] def pyrun(src): """Run python code 'src' in a separate interpreter. Return interpreter subprocess. """ if PY3: src = bytes(src, 'ascii') with tempfile.NamedTemporaryFile( prefix=TESTFILE_PREFIX, delete=False) as f: _testfiles.append(f.name) f.write(src) f.flush() subp = get_test_subprocess([PYTHON, f.name], stdout=None, stderr=None) wait_for_pid(subp.pid) return subp def warn(msg): """Raise a warning msg.""" warnings.warn(msg, UserWarning) def sh(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE): """run cmd in a subprocess and return its output. raises RuntimeError on error. """ p = subprocess.Popen(cmdline, shell=True, stdout=stdout, stderr=stderr) stdout, stderr = p.communicate() if p.returncode != 0: raise RuntimeError(stderr) if stderr: warn(stderr) if PY3: stdout = str(stdout, sys.stdout.encoding or sys.getfilesystemencoding()) return stdout.strip() if POSIX: def get_kernel_version(): """Return a tuple such as (2, 6, 36).""" s = "" uname = os.uname()[2] for c in uname: if c.isdigit() or c == '.': s += c else: break if not s: raise ValueError("can't parse %r" % uname) minor = 0 micro = 0 nums = s.split('.') major = int(nums[0]) if len(nums) >= 2: minor = int(nums[1]) if len(nums) >= 3: micro = int(nums[2]) return (major, minor, micro) if LINUX: RLIMIT_SUPPORT = get_kernel_version() >= (2, 6, 36) else: RLIMIT_SUPPORT = False def wait_for_pid(pid, timeout=GLOBAL_TIMEOUT): """Wait for pid to show up in the process list then return. Used in the test suite to give time the sub process to initialize. """ raise_at = time.time() + timeout while True: if pid in psutil.pids(): # give it one more iteration to allow full initialization time.sleep(0.01) return time.sleep(0.0001) if time.time() >= raise_at: raise RuntimeError("Timed out") def wait_for_file(fname, timeout=GLOBAL_TIMEOUT, delete_file=True): """Wait for a file to be written on disk.""" stop_at = time.time() + 3 while time.time() < stop_at: try: with open(fname, "r") as f: data = f.read() if not data: continue if delete_file: os.remove(fname) return data except IOError: time.sleep(0.001) raise RuntimeError("timed out (couldn't read file)") def reap_children(search_all=False): """Kill any subprocess started by this test suite and ensure that no zombies stick around to hog resources and create problems when looking for refleaks. """ global _subprocesses_started procs = _subprocesses_started.copy() if search_all: this_process = psutil.Process() for p in this_process.children(recursive=True): procs.add(p) for p in procs: try: p.terminate() except psutil.NoSuchProcess: pass gone, alive = psutil.wait_procs(procs, timeout=GLOBAL_TIMEOUT) for p in alive: warn("couldn't terminate process %s" % p) try: p.kill() except psutil.NoSuchProcess: pass _, alive = psutil.wait_procs(alive, timeout=GLOBAL_TIMEOUT) if alive: warn("couldn't not kill processes %s" % str(alive)) _subprocesses_started = set(alive) def check_ip_address(addr, family): """Attempts to check IP address's validity.""" if enum and PY3: assert isinstance(family, enum.IntEnum), family if family == AF_INET: octs = [int(x) for x in addr.split('.')] assert len(octs) == 4, addr for num in octs: assert 0 <= num <= 255, addr if ipaddress: if not PY3: addr = unicode(addr) ipaddress.IPv4Address(addr) elif family == AF_INET6: assert isinstance(addr, str), addr if ipaddress: if not PY3: addr = unicode(addr) ipaddress.IPv6Address(addr) elif family == psutil.AF_LINK: assert re.match('([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr else: raise ValueError("unknown family %r", family) def check_connection_ntuple(conn): """Check validity of a connection namedtuple.""" valid_conn_states = [getattr(psutil, x) for x in dir(psutil) if x.startswith('CONN_')] assert conn[0] == conn.fd assert conn[1] == conn.family assert conn[2] == conn.type assert conn[3] == conn.laddr assert conn[4] == conn.raddr assert conn[5] == conn.status assert conn.type in (SOCK_STREAM, SOCK_DGRAM), repr(conn.type) assert conn.family in (AF_INET, AF_INET6, AF_UNIX), repr(conn.family) assert conn.status in valid_conn_states, conn.status # check IP address and port sanity for addr in (conn.laddr, conn.raddr): if not addr: continue if conn.family in (AF_INET, AF_INET6): assert isinstance(addr, tuple), addr ip, port = addr assert isinstance(port, int), port assert 0 <= port <= 65535, port check_ip_address(ip, conn.family) elif conn.family == AF_UNIX: assert isinstance(addr, (str, None)), addr else: raise ValueError("unknown family %r", conn.family) if conn.family in (AF_INET, AF_INET6): # actually try to bind the local socket; ignore IPv6 # sockets as their address might be represented as # an IPv4-mapped-address (e.g. "::127.0.0.1") # and that's rejected by bind() if conn.family == AF_INET: s = socket.socket(conn.family, conn.type) with contextlib.closing(s): try: s.bind((conn.laddr[0], 0)) except socket.error as err: if err.errno != errno.EADDRNOTAVAIL: raise elif conn.family == AF_UNIX: assert not conn.raddr, repr(conn.raddr) assert conn.status == psutil.CONN_NONE, conn.status if getattr(conn, 'fd', -1) != -1: assert conn.fd > 0, conn if hasattr(socket, 'fromfd') and not WINDOWS: try: dupsock = socket.fromfd(conn.fd, conn.family, conn.type) except (socket.error, OSError) as err: if err.args[0] != errno.EBADF: raise else: with contextlib.closing(dupsock): assert dupsock.family == conn.family assert dupsock.type == conn.type def safe_remove(file): "Convenience function for removing temporary test files" try: os.remove(file) except OSError as err: if err.errno != errno.ENOENT: # # file is being used by another process # if WINDOWS and isinstance(err, WindowsError) and err.errno == 13: # return raise def safe_rmdir(dir): "Convenience function for removing temporary test directories" try: os.rmdir(dir) except OSError as err: if err.errno != errno.ENOENT: raise @contextlib.contextmanager def chdir(dirname): """Context manager which temporarily changes the current directory.""" curdir = os.getcwd() try: os.chdir(dirname) yield finally: os.chdir(curdir) def call_until(fun, expr, timeout=GLOBAL_TIMEOUT): """Keep calling function for timeout secs and exit if eval() expression is True. """ stop_at = time.time() + timeout while time.time() < stop_at: ret = fun() if eval(expr): return ret time.sleep(0.001) raise RuntimeError('timed out (ret=%r)' % ret) def retry_before_failing(ntimes=None): """Decorator which runs a test function and retries N times before actually failing. """ def decorator(fun): @functools.wraps(fun) def wrapper(*args, **kwargs): times = ntimes or NO_RETRIES assert times, times for x in range(times): try: return fun(*args, **kwargs) except AssertionError: pass raise return wrapper return decorator def skip_on_access_denied(only_if=None): """Decorator to Ignore AccessDenied exceptions.""" def decorator(fun): @functools.wraps(fun) def wrapper(*args, **kwargs): try: return fun(*args, **kwargs) except psutil.AccessDenied: if only_if is not None: if not only_if: raise msg = "%r was skipped because it raised AccessDenied" \ % fun.__name__ raise unittest.SkipTest(msg) return wrapper return decorator def skip_on_not_implemented(only_if=None): """Decorator to Ignore NotImplementedError exceptions.""" def decorator(fun): @functools.wraps(fun) def wrapper(*args, **kwargs): try: return fun(*args, **kwargs) except NotImplementedError: if only_if is not None: if not only_if: raise msg = "%r was skipped because it raised NotImplementedError" \ % fun.__name__ raise unittest.SkipTest(msg) return wrapper return decorator def create_temp_executable_file(suffix): tmpdir = None if TRAVIS and OSX: tmpdir = "/private/tmp" fd, path = tempfile.mkstemp( prefix='psu', suffix=suffix, dir=tmpdir) os.close(fd) if which("gcc"): fd, c_file = tempfile.mkstemp( prefix='psu', suffix='.c', dir=tmpdir) os.close(fd) with open(c_file, "w") as f: f.write("void main() { pause(); }") subprocess.check_call(["gcc", c_file, "-o", path]) safe_remove(c_file) else: # fallback - use python's executable shutil.copyfile(sys.executable, path) if POSIX: st = os.stat(path) os.chmod(path, st.st_mode | stat.S_IEXEC) return path if WINDOWS: def get_winver(): wv = sys.getwindowsversion() if hasattr(wv, 'service_pack_major'): # python >= 2.7 sp = wv.service_pack_major or 0 else: r = re.search("\s\d$", wv[4]) if r: sp = int(r.group(0)) else: sp = 0 return (wv[0], wv[1], sp) class ThreadTask(threading.Thread): """A thread object used for running process thread tests.""" def __init__(self): threading.Thread.__init__(self) self._running = False self._interval = None self._flag = threading.Event() def __repr__(self): name = self.__class__.__name__ return '<%s running=%s at %#x>' % (name, self._running, id(self)) def start(self, interval=0.001): """Start thread and keep it running until an explicit stop() request. Polls for shutdown every 'timeout' seconds. """ if self._running: raise ValueError("already started") self._interval = interval threading.Thread.start(self) self._flag.wait() def run(self): self._running = True self._flag.set() while self._running: time.sleep(self._interval) def stop(self): """Stop thread execution and and waits until it is stopped.""" if not self._running: raise ValueError("already stopped") self._running = False self.join() # =================================================================== # --- System-related API tests # =================================================================== class TestSystemAPIs(unittest.TestCase): """Tests for system-related APIs.""" def setUp(self): safe_remove(TESTFN) def tearDown(self): reap_children() def test_process_iter(self): self.assertIn(os.getpid(), [x.pid for x in psutil.process_iter()]) sproc = get_test_subprocess() self.assertIn(sproc.pid, [x.pid for x in psutil.process_iter()]) p = psutil.Process(sproc.pid) p.kill() p.wait() self.assertNotIn(sproc.pid, [x.pid for x in psutil.process_iter()]) with mock.patch('psutil.Process', side_effect=psutil.NoSuchProcess(os.getpid())): self.assertEqual(list(psutil.process_iter()), []) with mock.patch('psutil.Process', side_effect=psutil.AccessDenied(os.getpid())): with self.assertRaises(psutil.AccessDenied): list(psutil.process_iter()) def test_wait_procs(self): def callback(p): l.append(p.pid) l = [] sproc1 = get_test_subprocess() sproc2 = get_test_subprocess() sproc3 = get_test_subprocess() procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] self.assertRaises(ValueError, psutil.wait_procs, procs, timeout=-1) self.assertRaises(TypeError, psutil.wait_procs, procs, callback=1) t = time.time() gone, alive = psutil.wait_procs(procs, timeout=0.01, callback=callback) self.assertLess(time.time() - t, 0.5) self.assertEqual(gone, []) self.assertEqual(len(alive), 3) self.assertEqual(l, []) for p in alive: self.assertFalse(hasattr(p, 'returncode')) @retry_before_failing(30) def test(procs, callback): gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback) self.assertEqual(len(gone), 1) self.assertEqual(len(alive), 2) return gone, alive sproc3.terminate() gone, alive = test(procs, callback) self.assertIn(sproc3.pid, [x.pid for x in gone]) if POSIX: self.assertEqual(gone.pop().returncode, signal.SIGTERM) else: self.assertEqual(gone.pop().returncode, 1) self.assertEqual(l, [sproc3.pid]) for p in alive: self.assertFalse(hasattr(p, 'returncode')) @retry_before_failing(30) def test(procs, callback): gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback) self.assertEqual(len(gone), 3) self.assertEqual(len(alive), 0) return gone, alive sproc1.terminate() sproc2.terminate() gone, alive = test(procs, callback) self.assertEqual(set(l), set([sproc1.pid, sproc2.pid, sproc3.pid])) for p in gone: self.assertTrue(hasattr(p, 'returncode')) def test_wait_procs_no_timeout(self): sproc1 = get_test_subprocess() sproc2 = get_test_subprocess() sproc3 = get_test_subprocess() procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] for p in procs: p.terminate() gone, alive = psutil.wait_procs(procs) def test_boot_time(self): bt = psutil.boot_time() self.assertIsInstance(bt, float) self.assertGreater(bt, 0) self.assertLess(bt, time.time()) @unittest.skipUnless(POSIX, 'posix only') def test_PAGESIZE(self): # pagesize is used internally to perform different calculations # and it's determined by using SC_PAGE_SIZE; make sure # getpagesize() returns the same value. import resource self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize()) def test_virtual_memory(self): mem = psutil.virtual_memory() assert mem.total > 0, mem assert mem.available > 0, mem assert 0 <= mem.percent <= 100, mem assert mem.used > 0, mem assert mem.free >= 0, mem for name in mem._fields: value = getattr(mem, name) if name != 'percent': self.assertIsInstance(value, (int, long)) if name != 'total': if not value >= 0: self.fail("%r < 0 (%s)" % (name, value)) if value > mem.total: self.fail("%r > total (total=%s, %s=%s)" % (name, mem.total, name, value)) def test_swap_memory(self): mem = psutil.swap_memory() assert mem.total >= 0, mem assert mem.used >= 0, mem if mem.total > 0: # likely a system with no swap partition assert mem.free > 0, mem else: assert mem.free == 0, mem assert 0 <= mem.percent <= 100, mem assert mem.sin >= 0, mem assert mem.sout >= 0, mem def test_pid_exists(self): sproc = get_test_subprocess(wait=True) self.assertTrue(psutil.pid_exists(sproc.pid)) p = psutil.Process(sproc.pid) p.kill() p.wait() self.assertFalse(psutil.pid_exists(sproc.pid)) self.assertFalse(psutil.pid_exists(-1)) self.assertEqual(psutil.pid_exists(0), 0 in psutil.pids()) # pid 0 psutil.pid_exists(0) == 0 in psutil.pids() def test_pid_exists_2(self): reap_children() pids = psutil.pids() for pid in pids: try: assert psutil.pid_exists(pid) except AssertionError: # in case the process disappeared in meantime fail only # if it is no longer in psutil.pids() time.sleep(.1) if pid in psutil.pids(): self.fail(pid) pids = range(max(pids) + 5000, max(pids) + 6000) for pid in pids: self.assertFalse(psutil.pid_exists(pid), msg=pid) def test_pids(self): plist = [x.pid for x in psutil.process_iter()] pidlist = psutil.pids() self.assertEqual(plist.sort(), pidlist.sort()) # make sure every pid is unique self.assertEqual(len(pidlist), len(set(pidlist))) def test_test(self): # test for psutil.test() function stdout = sys.stdout sys.stdout = DEVNULL try: psutil.test() finally: sys.stdout = stdout def test_cpu_count(self): logical = psutil.cpu_count() self.assertEqual(logical, len(psutil.cpu_times(percpu=True))) self.assertGreaterEqual(logical, 1) # if os.path.exists("/proc/cpuinfo"): with open("/proc/cpuinfo") as fd: cpuinfo_data = fd.read() if "physical id" not in cpuinfo_data: raise unittest.SkipTest("cpuinfo doesn't include physical id") physical = psutil.cpu_count(logical=False) self.assertGreaterEqual(physical, 1) self.assertGreaterEqual(logical, physical) def test_sys_cpu_times(self): total = 0 times = psutil.cpu_times() sum(times) for cp_time in times: self.assertIsInstance(cp_time, float) self.assertGreaterEqual(cp_time, 0.0) total += cp_time self.assertEqual(total, sum(times)) str(times) # CPU times are always supposed to increase over time # or at least remain the same and that's because time # cannot go backwards. # Surprisingly sometimes this might not be the case (at # least on Windows and Linux), see: # https://github.com/giampaolo/psutil/issues/392 # https://github.com/giampaolo/psutil/issues/645 # if not WINDOWS: # last = psutil.cpu_times() # for x in range(100): # new = psutil.cpu_times() # for field in new._fields: # new_t = getattr(new, field) # last_t = getattr(last, field) # self.assertGreaterEqual(new_t, last_t, # msg="%s %s" % (new_t, last_t)) # last = new def test_sys_cpu_times2(self): t1 = sum(psutil.cpu_times()) time.sleep(0.1) t2 = sum(psutil.cpu_times()) difference = t2 - t1 if not difference >= 0.05: self.fail("difference %s" % difference) def test_sys_per_cpu_times(self): for times in psutil.cpu_times(percpu=True): total = 0 sum(times) for cp_time in times: self.assertIsInstance(cp_time, float) self.assertGreaterEqual(cp_time, 0.0) total += cp_time self.assertEqual(total, sum(times)) str(times) self.assertEqual(len(psutil.cpu_times(percpu=True)[0]), len(psutil.cpu_times(percpu=False))) # Note: in theory CPU times are always supposed to increase over # time or remain the same but never go backwards. In practice # sometimes this is not the case. # This issue seemd to be afflict Windows: # https://github.com/giampaolo/psutil/issues/392 # ...but it turns out also Linux (rarely) behaves the same. # last = psutil.cpu_times(percpu=True) # for x in range(100): # new = psutil.cpu_times(percpu=True) # for index in range(len(new)): # newcpu = new[index] # lastcpu = last[index] # for field in newcpu._fields: # new_t = getattr(newcpu, field) # last_t = getattr(lastcpu, field) # self.assertGreaterEqual( # new_t, last_t, msg="%s %s" % (lastcpu, newcpu)) # last = new def test_sys_per_cpu_times_2(self): tot1 = psutil.cpu_times(percpu=True) stop_at = time.time() + 0.1 while True: if time.time() >= stop_at: break tot2 = psutil.cpu_times(percpu=True) for t1, t2 in zip(tot1, tot2): t1, t2 = sum(t1), sum(t2) difference = t2 - t1 if difference >= 0.05: return self.fail() def _test_cpu_percent(self, percent, last_ret, new_ret): try: self.assertIsInstance(percent, float) self.assertGreaterEqual(percent, 0.0) self.assertIsNot(percent, -0.0) self.assertLessEqual(percent, 100.0 * psutil.cpu_count()) except AssertionError as err: raise AssertionError("\n%s\nlast=%s\nnew=%s" % ( err, pprint.pformat(last_ret), pprint.pformat(new_ret))) def test_sys_cpu_percent(self): last = psutil.cpu_percent(interval=0.001) for x in range(100): new = psutil.cpu_percent(interval=None) self._test_cpu_percent(new, last, new) last = new def test_sys_per_cpu_percent(self): last = psutil.cpu_percent(interval=0.001, percpu=True) self.assertEqual(len(last), psutil.cpu_count()) for x in range(100): new = psutil.cpu_percent(interval=None, percpu=True) for percent in new: self._test_cpu_percent(percent, last, new) last = new def test_sys_cpu_times_percent(self): last = psutil.cpu_times_percent(interval=0.001) for x in range(100): new = psutil.cpu_times_percent(interval=None) for percent in new: self._test_cpu_percent(percent, last, new) self._test_cpu_percent(sum(new), last, new) last = new def test_sys_per_cpu_times_percent(self): last = psutil.cpu_times_percent(interval=0.001, percpu=True) self.assertEqual(len(last), psutil.cpu_count()) for x in range(100): new = psutil.cpu_times_percent(interval=None, percpu=True) for cpu in new: for percent in cpu: self._test_cpu_percent(percent, last, new) self._test_cpu_percent(sum(cpu), last, new) last = new def test_sys_per_cpu_times_percent_negative(self): # see: https://github.com/giampaolo/psutil/issues/645 psutil.cpu_times_percent(percpu=True) zero_times = [x._make([0 for x in range(len(x._fields))]) for x in psutil.cpu_times(percpu=True)] with mock.patch('psutil.cpu_times', return_value=zero_times): for cpu in psutil.cpu_times_percent(percpu=True): for percent in cpu: self._test_cpu_percent(percent, None, None) @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") def test_disk_usage(self): usage = psutil.disk_usage(os.getcwd()) assert usage.total > 0, usage assert usage.used > 0, usage assert usage.free > 0, usage assert usage.total > usage.used, usage assert usage.total > usage.free, usage assert 0 <= usage.percent <= 100, usage.percent if hasattr(shutil, 'disk_usage'): # py >= 3.3, see: http://bugs.python.org/issue12442 shutil_usage = shutil.disk_usage(os.getcwd()) tolerance = 5 * 1024 * 1024 # 5MB self.assertEqual(usage.total, shutil_usage.total) self.assertAlmostEqual(usage.free, shutil_usage.free, delta=tolerance) self.assertAlmostEqual(usage.used, shutil_usage.used, delta=tolerance) # if path does not exist OSError ENOENT is expected across # all platforms fname = tempfile.mktemp() try: psutil.disk_usage(fname) except OSError as err: if err.args[0] != errno.ENOENT: raise else: self.fail("OSError not raised") @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") def test_disk_usage_unicode(self): # see: https://github.com/giampaolo/psutil/issues/416 # XXX this test is not really reliable as it always fails on # Python 3.X (2.X is fine) try: safe_rmdir(TESTFN_UNICODE) os.mkdir(TESTFN_UNICODE) psutil.disk_usage(TESTFN_UNICODE) safe_rmdir(TESTFN_UNICODE) except UnicodeEncodeError: pass @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") def test_disk_partitions(self): # all = False ls = psutil.disk_partitions(all=False) # on travis we get: # self.assertEqual(p.cpu_affinity(), [n]) # AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7,... != [0] self.assertTrue(ls, msg=ls) for disk in ls: if WINDOWS and 'cdrom' in disk.opts: continue if not POSIX: assert os.path.exists(disk.device), disk else: # we cannot make any assumption about this, see: # http://goo.gl/p9c43 disk.device if SUNOS: # on solaris apparently mount points can also be files assert os.path.exists(disk.mountpoint), disk else: assert os.path.isdir(disk.mountpoint), disk assert disk.fstype, disk self.assertIsInstance(disk.opts, str) # all = True ls = psutil.disk_partitions(all=True) self.assertTrue(ls, msg=ls) for disk in psutil.disk_partitions(all=True): if not WINDOWS: try: os.stat(disk.mountpoint) except OSError as err: if TRAVIS and OSX and err.errno == errno.EIO: continue # http://mail.python.org/pipermail/python-dev/ # 2012-June/120787.html if err.errno not in (errno.EPERM, errno.EACCES): raise else: if SUNOS: # on solaris apparently mount points can also be files assert os.path.exists(disk.mountpoint), disk else: assert os.path.isdir(disk.mountpoint), disk self.assertIsInstance(disk.fstype, str) self.assertIsInstance(disk.opts, str) def find_mount_point(path): path = os.path.abspath(path) while not os.path.ismount(path): path = os.path.dirname(path) return path mount = find_mount_point(__file__) mounts = [x.mountpoint for x in psutil.disk_partitions(all=True)] self.assertIn(mount, mounts) psutil.disk_usage(mount) @skip_on_access_denied() def test_net_connections(self): def check(cons, families, types_): for conn in cons: self.assertIn(conn.family, families, msg=conn) if conn.family != getattr(socket, 'AF_UNIX', object()): self.assertIn(conn.type, types_, msg=conn) from psutil._common import conn_tmap for kind, groups in conn_tmap.items(): if SUNOS and kind == 'unix': continue families, types_ = groups cons = psutil.net_connections(kind) self.assertEqual(len(cons), len(set(cons))) check(cons, families, types_) def test_net_io_counters(self): def check_ntuple(nt): self.assertEqual(nt[0], nt.bytes_sent) self.assertEqual(nt[1], nt.bytes_recv) self.assertEqual(nt[2], nt.packets_sent) self.assertEqual(nt[3], nt.packets_recv) self.assertEqual(nt[4], nt.errin) self.assertEqual(nt[5], nt.errout) self.assertEqual(nt[6], nt.dropin) self.assertEqual(nt[7], nt.dropout) assert nt.bytes_sent >= 0, nt assert nt.bytes_recv >= 0, nt assert nt.packets_sent >= 0, nt assert nt.packets_recv >= 0, nt assert nt.errin >= 0, nt assert nt.errout >= 0, nt assert nt.dropin >= 0, nt assert nt.dropout >= 0, nt ret = psutil.net_io_counters(pernic=False) check_ntuple(ret) ret = psutil.net_io_counters(pernic=True) self.assertNotEqual(ret, []) for key in ret: self.assertTrue(key) check_ntuple(ret[key]) def test_net_if_addrs(self): nics = psutil.net_if_addrs() assert nics, nics # Not reliable on all platforms (net_if_addrs() reports more # interfaces). # self.assertEqual(sorted(nics.keys()), # sorted(psutil.net_io_counters(pernic=True).keys())) families = set([socket.AF_INET, AF_INET6, psutil.AF_LINK]) for nic, addrs in nics.items(): self.assertEqual(len(set(addrs)), len(addrs)) for addr in addrs: self.assertIsInstance(addr.family, int) self.assertIsInstance(addr.address, str) self.assertIsInstance(addr.netmask, (str, type(None))) self.assertIsInstance(addr.broadcast, (str, type(None))) self.assertIn(addr.family, families) if sys.version_info >= (3, 4): self.assertIsInstance(addr.family, enum.IntEnum) if addr.family == socket.AF_INET: s = socket.socket(addr.family) with contextlib.closing(s): s.bind((addr.address, 0)) elif addr.family == socket.AF_INET6: info = socket.getaddrinfo( addr.address, 0, socket.AF_INET6, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)[0] af, socktype, proto, canonname, sa = info s = socket.socket(af, socktype, proto) with contextlib.closing(s): s.bind(sa) for ip in (addr.address, addr.netmask, addr.broadcast, addr.ptp): if ip is not None: # TODO: skip AF_INET6 for now because I get: # AddressValueError: Only hex digits permitted in # u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0' if addr.family != AF_INET6: check_ip_address(ip, addr.family) # broadcast and ptp addresses are mutually exclusive if addr.broadcast: self.assertIsNone(addr.ptp) elif addr.ptp: self.assertIsNone(addr.broadcast) if BSD or OSX or SUNOS: if hasattr(socket, "AF_LINK"): self.assertEqual(psutil.AF_LINK, socket.AF_LINK) elif LINUX: self.assertEqual(psutil.AF_LINK, socket.AF_PACKET) elif WINDOWS: self.assertEqual(psutil.AF_LINK, -1) @unittest.skipIf(TRAVIS, "EPERM on travis") def test_net_if_stats(self): nics = psutil.net_if_stats() assert nics, nics all_duplexes = (psutil.NIC_DUPLEX_FULL, psutil.NIC_DUPLEX_HALF, psutil.NIC_DUPLEX_UNKNOWN) for nic, stats in nics.items(): isup, duplex, speed, mtu = stats self.assertIsInstance(isup, bool) self.assertIn(duplex, all_duplexes) self.assertIn(duplex, all_duplexes) self.assertGreaterEqual(speed, 0) self.assertGreaterEqual(mtu, 0) @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'), '/proc/diskstats not available on this linux version') @unittest.skipIf(APPVEYOR, "can't find any physical disk on Appveyor") def test_disk_io_counters(self): def check_ntuple(nt): self.assertEqual(nt[0], nt.read_count) self.assertEqual(nt[1], nt.write_count) self.assertEqual(nt[2], nt.read_bytes) self.assertEqual(nt[3], nt.write_bytes) self.assertEqual(nt[4], nt.read_time) self.assertEqual(nt[5], nt.write_time) assert nt.read_count >= 0, nt assert nt.write_count >= 0, nt assert nt.read_bytes >= 0, nt assert nt.write_bytes >= 0, nt assert nt.read_time >= 0, nt assert nt.write_time >= 0, nt ret = psutil.disk_io_counters(perdisk=False) check_ntuple(ret) ret = psutil.disk_io_counters(perdisk=True) # make sure there are no duplicates self.assertEqual(len(ret), len(set(ret))) for key in ret: assert key, key check_ntuple(ret[key]) if LINUX and key[-1].isdigit(): # if 'sda1' is listed 'sda' shouldn't, see: # https://github.com/giampaolo/psutil/issues/338 while key[-1].isdigit(): key = key[:-1] self.assertNotIn(key, ret.keys()) def test_users(self): users = psutil.users() if not APPVEYOR: self.assertNotEqual(users, []) for user in users: assert user.name, user user.terminal user.host assert user.started > 0.0, user datetime.datetime.fromtimestamp(user.started) # =================================================================== # --- psutil.Process class tests # =================================================================== class TestProcess(unittest.TestCase): """Tests for psutil.Process class.""" def setUp(self): safe_remove(TESTFN) def tearDown(self): reap_children() def test_pid(self): self.assertEqual(psutil.Process().pid, os.getpid()) sproc = get_test_subprocess() self.assertEqual(psutil.Process(sproc.pid).pid, sproc.pid) def test_kill(self): sproc = get_test_subprocess(wait=True) test_pid = sproc.pid p = psutil.Process(test_pid) p.kill() sig = p.wait() self.assertFalse(psutil.pid_exists(test_pid)) if POSIX: self.assertEqual(sig, signal.SIGKILL) def test_terminate(self): sproc = get_test_subprocess(wait=True) test_pid = sproc.pid p = psutil.Process(test_pid) p.terminate() sig = p.wait() self.assertFalse(psutil.pid_exists(test_pid)) if POSIX: self.assertEqual(sig, signal.SIGTERM) def test_send_signal(self): sig = signal.SIGKILL if POSIX else signal.SIGTERM sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.send_signal(sig) exit_sig = p.wait() self.assertFalse(psutil.pid_exists(p.pid)) if POSIX: self.assertEqual(exit_sig, sig) # sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.send_signal(sig) with mock.patch('psutil.os.kill', side_effect=OSError(errno.ESRCH, "")) as fun: with self.assertRaises(psutil.NoSuchProcess): p.send_signal(sig) assert fun.called # sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.send_signal(sig) with mock.patch('psutil.os.kill', side_effect=OSError(errno.EPERM, "")) as fun: with self.assertRaises(psutil.AccessDenied): psutil.Process().send_signal(sig) assert fun.called def test_wait(self): # check exit code signal sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.kill() code = p.wait() if POSIX: self.assertEqual(code, signal.SIGKILL) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.terminate() code = p.wait() if POSIX: self.assertEqual(code, signal.SIGTERM) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) # check sys.exit() code code = "import time, sys; time.sleep(0.01); sys.exit(5);" sproc = get_test_subprocess([PYTHON, "-c", code]) p = psutil.Process(sproc.pid) self.assertEqual(p.wait(), 5) self.assertFalse(p.is_running()) # Test wait() issued twice. # It is not supposed to raise NSP when the process is gone. # On UNIX this should return None, on Windows it should keep # returning the exit code. sproc = get_test_subprocess([PYTHON, "-c", code]) p = psutil.Process(sproc.pid) self.assertEqual(p.wait(), 5) self.assertIn(p.wait(), (5, None)) # test timeout sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.name() self.assertRaises(psutil.TimeoutExpired, p.wait, 0.01) # timeout < 0 not allowed self.assertRaises(ValueError, p.wait, -1) # XXX why is this skipped on Windows? @unittest.skipUnless(POSIX, 'skipped on Windows') def test_wait_non_children(self): # test wait() against processes which are not our children code = "import sys;" code += "from subprocess import Popen, PIPE;" code += "cmd = ['%s', '-c', 'import time; time.sleep(60)'];" % PYTHON code += "sp = Popen(cmd, stdout=PIPE);" code += "sys.stdout.write(str(sp.pid));" sproc = get_test_subprocess([PYTHON, "-c", code], stdout=subprocess.PIPE) grandson_pid = int(sproc.stdout.read()) grandson_proc = psutil.Process(grandson_pid) try: self.assertRaises(psutil.TimeoutExpired, grandson_proc.wait, 0.01) grandson_proc.kill() ret = grandson_proc.wait() self.assertEqual(ret, None) finally: if grandson_proc.is_running(): grandson_proc.kill() grandson_proc.wait() def test_wait_timeout_0(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) self.assertRaises(psutil.TimeoutExpired, p.wait, 0) p.kill() stop_at = time.time() + 2 while True: try: code = p.wait(0) except psutil.TimeoutExpired: if time.time() >= stop_at: raise else: break if POSIX: self.assertEqual(code, signal.SIGKILL) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) def test_cpu_percent(self): p = psutil.Process() p.cpu_percent(interval=0.001) p.cpu_percent(interval=0.001) for x in range(100): percent = p.cpu_percent(interval=None) self.assertIsInstance(percent, float) self.assertGreaterEqual(percent, 0.0) if not POSIX: self.assertLessEqual(percent, 100.0) else: self.assertGreaterEqual(percent, 0.0) def test_cpu_times(self): times = psutil.Process().cpu_times() assert (times.user > 0.0) or (times.system > 0.0), times # make sure returned values can be pretty printed with strftime time.strftime("%H:%M:%S", time.localtime(times.user)) time.strftime("%H:%M:%S", time.localtime(times.system)) # Test Process.cpu_times() against os.times() # os.times() is broken on Python 2.6 # http://bugs.python.org/issue1040026 # XXX fails on OSX: not sure if it's for os.times(). We should # try this with Python 2.7 and re-enable the test. @unittest.skipUnless(sys.version_info > (2, 6, 1) and not OSX, 'os.times() is not reliable on this Python version') def test_cpu_times2(self): user_time, kernel_time = psutil.Process().cpu_times() utime, ktime = os.times()[:2] # Use os.times()[:2] as base values to compare our results # using a tolerance of +/- 0.1 seconds. # It will fail if the difference between the values is > 0.1s. if (max([user_time, utime]) - min([user_time, utime])) > 0.1: self.fail("expected: %s, found: %s" % (utime, user_time)) if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1: self.fail("expected: %s, found: %s" % (ktime, kernel_time)) def test_create_time(self): sproc = get_test_subprocess(wait=True) now = time.time() p = psutil.Process(sproc.pid) create_time = p.create_time() # Use time.time() as base value to compare our result using a # tolerance of +/- 1 second. # It will fail if the difference between the values is > 2s. difference = abs(create_time - now) if difference > 2: self.fail("expected: %s, found: %s, difference: %s" % (now, create_time, difference)) # make sure returned value can be pretty printed with strftime time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time())) @unittest.skipIf(WINDOWS, 'Windows only') def test_terminal(self): terminal = psutil.Process().terminal() if sys.stdin.isatty(): tty = os.path.realpath(sh('tty')) self.assertEqual(terminal, tty) else: assert terminal, repr(terminal) @unittest.skipUnless(LINUX or BSD or WINDOWS, 'not available on this platform') @skip_on_not_implemented(only_if=LINUX) def test_io_counters(self): p = psutil.Process() # test reads io1 = p.io_counters() with open(PYTHON, 'rb') as f: f.read() io2 = p.io_counters() if not BSD: assert io2.read_count > io1.read_count, (io1, io2) self.assertEqual(io2.write_count, io1.write_count) assert io2.read_bytes >= io1.read_bytes, (io1, io2) assert io2.write_bytes >= io1.write_bytes, (io1, io2) # test writes io1 = p.io_counters() with tempfile.TemporaryFile(prefix=TESTFILE_PREFIX) as f: if PY3: f.write(bytes("x" * 1000000, 'ascii')) else: f.write("x" * 1000000) io2 = p.io_counters() assert io2.write_count >= io1.write_count, (io1, io2) assert io2.write_bytes >= io1.write_bytes, (io1, io2) assert io2.read_count >= io1.read_count, (io1, io2) assert io2.read_bytes >= io1.read_bytes, (io1, io2) @unittest.skipUnless(LINUX or (WINDOWS and get_winver() >= WIN_VISTA), 'Linux and Windows Vista only') @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") def test_ionice(self): if LINUX: from psutil import (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE) self.assertEqual(IOPRIO_CLASS_NONE, 0) self.assertEqual(IOPRIO_CLASS_RT, 1) self.assertEqual(IOPRIO_CLASS_BE, 2) self.assertEqual(IOPRIO_CLASS_IDLE, 3) p = psutil.Process() try: p.ionice(2) ioclass, value = p.ionice() if enum is not None: self.assertIsInstance(ioclass, enum.IntEnum) self.assertEqual(ioclass, 2) self.assertEqual(value, 4) # p.ionice(3) ioclass, value = p.ionice() self.assertEqual(ioclass, 3) self.assertEqual(value, 0) # p.ionice(2, 0) ioclass, value = p.ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 0) p.ionice(2, 7) ioclass, value = p.ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 7) # self.assertRaises(ValueError, p.ionice, 2, 10) self.assertRaises(ValueError, p.ionice, 2, -1) self.assertRaises(ValueError, p.ionice, 4) self.assertRaises(TypeError, p.ionice, 2, "foo") self.assertRaisesRegexp( ValueError, "can't specify value with IOPRIO_CLASS_NONE", p.ionice, psutil.IOPRIO_CLASS_NONE, 1) self.assertRaisesRegexp( ValueError, "can't specify value with IOPRIO_CLASS_IDLE", p.ionice, psutil.IOPRIO_CLASS_IDLE, 1) self.assertRaisesRegexp( ValueError, "'ioclass' argument must be specified", p.ionice, value=1) finally: p.ionice(IOPRIO_CLASS_NONE) else: p = psutil.Process() original = p.ionice() self.assertIsInstance(original, int) try: value = 0 # very low if original == value: value = 1 # low p.ionice(value) self.assertEqual(p.ionice(), value) finally: p.ionice(original) # self.assertRaises(ValueError, p.ionice, 3) self.assertRaises(TypeError, p.ionice, 2, 1) @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_get(self): import resource p = psutil.Process(os.getpid()) names = [x for x in dir(psutil) if x.startswith('RLIMIT')] assert names, names for name in names: value = getattr(psutil, name) self.assertGreaterEqual(value, 0) if name in dir(resource): self.assertEqual(value, getattr(resource, name)) self.assertEqual(p.rlimit(value), resource.getrlimit(value)) else: ret = p.rlimit(value) self.assertEqual(len(ret), 2) self.assertGreaterEqual(ret[0], -1) self.assertGreaterEqual(ret[1], -1) @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_set(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) self.assertEqual(p.rlimit(psutil.RLIMIT_NOFILE), (5, 5)) # If pid is 0 prlimit() applies to the calling process and # we don't want that. with self.assertRaises(ValueError): psutil._psplatform.Process(0).rlimit(0) with self.assertRaises(ValueError): p.rlimit(psutil.RLIMIT_NOFILE, (5, 5, 5)) @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit(self): p = psutil.Process() soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) try: p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard)) with open(TESTFN, "wb") as f: f.write(b"X" * 1024) # write() or flush() doesn't always cause the exception # but close() will. with self.assertRaises(IOError) as exc: with open(TESTFN, "wb") as f: f.write(b"X" * 1025) self.assertEqual(exc.exception.errno if PY3 else exc.exception[0], errno.EFBIG) finally: p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard)) @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_infinity(self): # First set a limit, then re-set it by specifying INFINITY # and assume we overridden the previous limit. p = psutil.Process() soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) try: p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard)) p.rlimit(psutil.RLIMIT_FSIZE, (psutil.RLIM_INFINITY, hard)) with open(TESTFN, "wb") as f: f.write(b"X" * 2048) finally: p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard)) @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_infinity_value(self): # RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really # big number on a platform with large file support. On these # platforms we need to test that the get/setrlimit functions # properly convert the number to a C long long and that the # conversion doesn't raise an error. p = psutil.Process() soft, hard = p.rlimit(psutil.RLIMIT_FSIZE) self.assertEqual(psutil.RLIM_INFINITY, hard) p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard)) def test_num_threads(self): # on certain platforms such as Linux we might test for exact # thread number, since we always have with 1 thread per process, # but this does not apply across all platforms (OSX, Windows) p = psutil.Process() if OPENBSD: try: step1 = p.num_threads() except psutil.AccessDenied: raise unittest.SkipTest("on OpenBSD this requires root access") else: step1 = p.num_threads() thread = ThreadTask() thread.start() try: step2 = p.num_threads() self.assertEqual(step2, step1 + 1) thread.stop() finally: if thread._running: thread.stop() @unittest.skipUnless(WINDOWS, 'Windows only') def test_num_handles(self): # a better test is done later into test/_windows.py p = psutil.Process() self.assertGreater(p.num_handles(), 0) def test_threads(self): p = psutil.Process() if OPENBSD: try: step1 = p.threads() except psutil.AccessDenied: raise unittest.SkipTest("on OpenBSD this requires root access") else: step1 = p.threads() thread = ThreadTask() thread.start() try: step2 = p.threads() self.assertEqual(len(step2), len(step1) + 1) # on Linux, first thread id is supposed to be this process if LINUX: self.assertEqual(step2[0].id, os.getpid()) athread = step2[0] # test named tuple self.assertEqual(athread.id, athread[0]) self.assertEqual(athread.user_time, athread[1]) self.assertEqual(athread.system_time, athread[2]) # test num threads thread.stop() finally: if thread._running: thread.stop() def test_threads_2(self): p = psutil.Process() if OPENBSD: try: p.threads() except psutil.AccessDenied: raise unittest.SkipTest( "on OpenBSD this requires root access") self.assertAlmostEqual(p.cpu_times().user, p.threads()[0].user_time, delta=0.1) self.assertAlmostEqual(p.cpu_times().system, p.threads()[0].system_time, delta=0.1) def test_memory_info(self): p = psutil.Process() # step 1 - get a base value to compare our results rss1, vms1 = p.memory_info() percent1 = p.memory_percent() self.assertGreater(rss1, 0) self.assertGreater(vms1, 0) # step 2 - allocate some memory memarr = [None] * 1500000 rss2, vms2 = p.memory_info() percent2 = p.memory_percent() # make sure that the memory usage bumped up self.assertGreater(rss2, rss1) self.assertGreaterEqual(vms2, vms1) # vms might be equal self.assertGreater(percent2, percent1) del memarr # def test_memory_info_ex(self): # # tested later in fetch all test suite @unittest.skipIf(OPENBSD or NETBSD, "not available on this platform") def test_memory_maps(self): p = psutil.Process() maps = p.memory_maps() paths = [x for x in maps] self.assertEqual(len(paths), len(set(paths))) ext_maps = p.memory_maps(grouped=False) for nt in maps: if not nt.path.startswith('['): assert os.path.isabs(nt.path), nt.path if POSIX: assert os.path.exists(nt.path) or \ os.path.islink(nt.path), nt.path else: # XXX - On Windows we have this strange behavior with # 64 bit dlls: they are visible via explorer but cannot # be accessed via os.stat() (wtf?). if '64' not in os.path.basename(nt.path): assert os.path.exists(nt.path), nt.path for nt in ext_maps: for fname in nt._fields: value = getattr(nt, fname) if fname == 'path': continue elif fname in ('addr', 'perms'): assert value, value else: self.assertIsInstance(value, (int, long)) assert value >= 0, value def test_memory_percent(self): p = psutil.Process() self.assertGreater(p.memory_percent(), 0.0) def test_is_running(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) assert p.is_running() assert p.is_running() p.kill() p.wait() assert not p.is_running() assert not p.is_running() def test_exe(self): sproc = get_test_subprocess(wait=True) exe = psutil.Process(sproc.pid).exe() try: self.assertEqual(exe, PYTHON) except AssertionError: if WINDOWS and len(exe) == len(PYTHON): # on Windows we don't care about case sensitivity normcase = os.path.normcase self.assertEqual(normcase(exe), normcase(PYTHON)) else: # certain platforms such as BSD are more accurate returning: # "/usr/local/bin/python2.7" # ...instead of: # "/usr/local/bin/python" # We do not want to consider this difference in accuracy # an error. ver = "%s.%s" % (sys.version_info[0], sys.version_info[1]) self.assertEqual(exe.replace(ver, ''), PYTHON.replace(ver, '')) def test_cmdline(self): cmdline = [PYTHON, "-c", "import time; time.sleep(60)"] sproc = get_test_subprocess(cmdline, wait=True) try: self.assertEqual(' '.join(psutil.Process(sproc.pid).cmdline()), ' '.join(cmdline)) except AssertionError: # XXX - most of the times the underlying sysctl() call on Net # and Open BSD returns a truncated string. # Also /proc/pid/cmdline behaves the same so it looks # like this is a kernel bug. if NETBSD or OPENBSD: self.assertEqual( psutil.Process(sproc.pid).cmdline()[0], PYTHON) else: raise def test_name(self): sproc = get_test_subprocess(PYTHON, wait=True) name = psutil.Process(sproc.pid).name().lower() pyexe = os.path.basename(os.path.realpath(sys.executable)).lower() assert pyexe.startswith(name), (pyexe, name) @unittest.skipIf(SUNOS, "doesn't work on Solaris") def test_prog_w_funky_name(self): # Test that name(), exe() and cmdline() correctly handle programs # with funky chars such as spaces and ")", see: # https://github.com/giampaolo/psutil/issues/628 funky_path = create_temp_executable_file('foo bar )') self.addCleanup(safe_remove, funky_path) sproc = get_test_subprocess( [funky_path, "arg1", "arg2", "", "arg3", ""]) p = psutil.Process(sproc.pid) # ...in order to try to prevent occasional failures on travis wait_for_pid(p.pid) normcase = os.path.normcase self.assertEqual(p.name(), os.path.basename(funky_path)) self.assertEqual(normcase(p.exe()), normcase(funky_path)) self.assertEqual( p.cmdline(), [funky_path, "arg1", "arg2", "", "arg3", ""]) @unittest.skipUnless(POSIX, 'posix only') def test_uids(self): p = psutil.Process() real, effective, saved = p.uids() # os.getuid() refers to "real" uid self.assertEqual(real, os.getuid()) # os.geteuid() refers to "effective" uid self.assertEqual(effective, os.geteuid()) # no such thing as os.getsuid() ("saved" uid), but starting # from python 2.7 we have os.getresuid()[2] if hasattr(os, "getresuid"): self.assertEqual(saved, os.getresuid()[2]) @unittest.skipUnless(POSIX, 'posix only') def test_gids(self): p = psutil.Process() real, effective, saved = p.gids() # os.getuid() refers to "real" uid self.assertEqual(real, os.getgid()) # os.geteuid() refers to "effective" uid self.assertEqual(effective, os.getegid()) # no such thing as os.getsuid() ("saved" uid), but starting # from python 2.7 we have os.getresgid()[2] if hasattr(os, "getresuid"): self.assertEqual(saved, os.getresgid()[2]) def test_nice(self): p = psutil.Process() self.assertRaises(TypeError, p.nice, "str") if WINDOWS: try: init = p.nice() if sys.version_info > (3, 4): self.assertIsInstance(init, enum.IntEnum) else: self.assertIsInstance(init, int) self.assertEqual(init, psutil.NORMAL_PRIORITY_CLASS) p.nice(psutil.HIGH_PRIORITY_CLASS) self.assertEqual(p.nice(), psutil.HIGH_PRIORITY_CLASS) p.nice(psutil.NORMAL_PRIORITY_CLASS) self.assertEqual(p.nice(), psutil.NORMAL_PRIORITY_CLASS) finally: p.nice(psutil.NORMAL_PRIORITY_CLASS) else: try: first_nice = p.nice() p.nice(1) self.assertEqual(p.nice(), 1) # going back to previous nice value raises # AccessDenied on OSX if not OSX: p.nice(0) self.assertEqual(p.nice(), 0) except psutil.AccessDenied: pass finally: try: p.nice(first_nice) except psutil.AccessDenied: pass def test_status(self): p = psutil.Process() self.assertEqual(p.status(), psutil.STATUS_RUNNING) def test_username(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) if POSIX: import pwd self.assertEqual(p.username(), pwd.getpwuid(os.getuid()).pw_name) with mock.patch("psutil.pwd.getpwuid", side_effect=KeyError) as fun: p.username() == str(p.uids().real) assert fun.called elif WINDOWS and 'USERNAME' in os.environ: expected_username = os.environ['USERNAME'] expected_domain = os.environ['USERDOMAIN'] domain, username = p.username().split('\\') self.assertEqual(domain, expected_domain) self.assertEqual(username, expected_username) else: p.username() def test_cwd(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) self.assertEqual(p.cwd(), os.getcwd()) def test_cwd_2(self): cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(60)"] sproc = get_test_subprocess(cmd, wait=True) p = psutil.Process(sproc.pid) call_until(p.cwd, "ret == os.path.dirname(os.getcwd())") @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, 'not available on this platform') @unittest.skipIf(LINUX and TRAVIS, "unknown failure on travis") def test_cpu_affinity(self): p = psutil.Process() initial = p.cpu_affinity() if hasattr(os, "sched_getaffinity"): self.assertEqual(initial, list(os.sched_getaffinity(p.pid))) self.assertEqual(len(initial), len(set(initial))) all_cpus = list(range(len(psutil.cpu_percent(percpu=True)))) # setting on travis doesn't seem to work (always return all # CPUs on get): # AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, ... != [0] for n in all_cpus: p.cpu_affinity([n]) self.assertEqual(p.cpu_affinity(), [n]) if hasattr(os, "sched_getaffinity"): self.assertEqual(p.cpu_affinity(), list(os.sched_getaffinity(p.pid))) # p.cpu_affinity(all_cpus) self.assertEqual(p.cpu_affinity(), all_cpus) if hasattr(os, "sched_getaffinity"): self.assertEqual(p.cpu_affinity(), list(os.sched_getaffinity(p.pid))) # self.assertRaises(TypeError, p.cpu_affinity, 1) p.cpu_affinity(initial) # it should work with all iterables, not only lists p.cpu_affinity(set(all_cpus)) p.cpu_affinity(tuple(all_cpus)) invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10] self.assertRaises(ValueError, p.cpu_affinity, invalid_cpu) self.assertRaises(ValueError, p.cpu_affinity, range(10000, 11000)) self.assertRaises(TypeError, p.cpu_affinity, [0, "1"]) # TODO @unittest.skipIf(BSD, "broken on BSD, see #595") @unittest.skipIf(APPVEYOR, "can't find any process file on Appveyor") def test_open_files(self): # current process p = psutil.Process() files = p.open_files() self.assertFalse(TESTFN in files) with open(TESTFN, 'w'): # give the kernel some time to see the new file call_until(p.open_files, "len(ret) != %i" % len(files)) filenames = [x.path for x in p.open_files()] self.assertIn(TESTFN, filenames) for file in filenames: assert os.path.isfile(file), file # another process cmdline = "import time; f = open(r'%s', 'r'); time.sleep(60);" % TESTFN sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True) p = psutil.Process(sproc.pid) for x in range(100): filenames = [x.path for x in p.open_files()] if TESTFN in filenames: break time.sleep(.01) else: self.assertIn(TESTFN, filenames) for file in filenames: assert os.path.isfile(file), file # TODO @unittest.skipIf(BSD, "broken on BSD, see #595") @unittest.skipIf(APPVEYOR, "can't find any process file on Appveyor") def test_open_files2(self): # test fd and path fields with open(TESTFN, 'w') as fileobj: p = psutil.Process() for path, fd in p.open_files(): if path == fileobj.name or fd == fileobj.fileno(): break else: self.fail("no file found; files=%s" % repr(p.open_files())) self.assertEqual(path, fileobj.name) if WINDOWS: self.assertEqual(fd, -1) else: self.assertEqual(fd, fileobj.fileno()) # test positions ntuple = p.open_files()[0] self.assertEqual(ntuple[0], ntuple.path) self.assertEqual(ntuple[1], ntuple.fd) # test file is gone self.assertTrue(fileobj.name not in p.open_files()) def compare_proc_sys_cons(self, pid, proc_cons): from psutil._common import pconn sys_cons = [] for c in psutil.net_connections(kind='all'): if c.pid == pid: sys_cons.append(pconn(*c[:-1])) if FREEBSD: # on FreeBSD all fds are set to -1 proc_cons = [pconn(*[-1] + list(x[1:])) for x in proc_cons] self.assertEqual(sorted(proc_cons), sorted(sys_cons)) @skip_on_access_denied(only_if=OSX) def test_connections(self): def check_conn(proc, conn, family, type, laddr, raddr, status, kinds): all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6") check_connection_ntuple(conn) self.assertEqual(conn.family, family) self.assertEqual(conn.type, type) self.assertEqual(conn.laddr, laddr) self.assertEqual(conn.raddr, raddr) self.assertEqual(conn.status, status) for kind in all_kinds: cons = proc.connections(kind=kind) if kind in kinds: self.assertNotEqual(cons, []) else: self.assertEqual(cons, []) # compare against system-wide connections # XXX Solaris can't retrieve system-wide UNIX # sockets. if not SUNOS: self.compare_proc_sys_cons(proc.pid, [conn]) tcp_template = textwrap.dedent(""" import socket, time s = socket.socket($family, socket.SOCK_STREAM) s.bind(('$addr', 0)) s.listen(1) with open('$testfn', 'w') as f: f.write(str(s.getsockname()[:2])) time.sleep(60) """) udp_template = textwrap.dedent(""" import socket, time s = socket.socket($family, socket.SOCK_DGRAM) s.bind(('$addr', 0)) with open('$testfn', 'w') as f: f.write(str(s.getsockname()[:2])) time.sleep(60) """) from string import Template testfile = os.path.basename(TESTFN) tcp4_template = Template(tcp_template).substitute( family=int(AF_INET), addr="127.0.0.1", testfn=testfile) udp4_template = Template(udp_template).substitute( family=int(AF_INET), addr="127.0.0.1", testfn=testfile) tcp6_template = Template(tcp_template).substitute( family=int(AF_INET6), addr="::1", testfn=testfile) udp6_template = Template(udp_template).substitute( family=int(AF_INET6), addr="::1", testfn=testfile) # launch various subprocess instantiating a socket of various # families and types to enrich psutil results tcp4_proc = pyrun(tcp4_template) tcp4_addr = eval(wait_for_file(testfile)) udp4_proc = pyrun(udp4_template) udp4_addr = eval(wait_for_file(testfile)) if supports_ipv6(): tcp6_proc = pyrun(tcp6_template) tcp6_addr = eval(wait_for_file(testfile)) udp6_proc = pyrun(udp6_template) udp6_addr = eval(wait_for_file(testfile)) else: tcp6_proc = None udp6_proc = None tcp6_addr = None udp6_addr = None for p in psutil.Process().children(): cons = p.connections() self.assertEqual(len(cons), 1) for conn in cons: # TCP v4 if p.pid == tcp4_proc.pid: check_conn(p, conn, AF_INET, SOCK_STREAM, tcp4_addr, (), psutil.CONN_LISTEN, ("all", "inet", "inet4", "tcp", "tcp4")) # UDP v4 elif p.pid == udp4_proc.pid: check_conn(p, conn, AF_INET, SOCK_DGRAM, udp4_addr, (), psutil.CONN_NONE, ("all", "inet", "inet4", "udp", "udp4")) # TCP v6 elif p.pid == getattr(tcp6_proc, "pid", None): check_conn(p, conn, AF_INET6, SOCK_STREAM, tcp6_addr, (), psutil.CONN_LISTEN, ("all", "inet", "inet6", "tcp", "tcp6")) # UDP v6 elif p.pid == getattr(udp6_proc, "pid", None): check_conn(p, conn, AF_INET6, SOCK_DGRAM, udp6_addr, (), psutil.CONN_NONE, ("all", "inet", "inet6", "udp", "udp6")) @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'AF_UNIX is not supported') @skip_on_access_denied(only_if=OSX) def test_connections_unix(self): def check(type): safe_remove(TESTFN) sock = socket.socket(AF_UNIX, type) with contextlib.closing(sock): sock.bind(TESTFN) cons = psutil.Process().connections(kind='unix') conn = cons[0] check_connection_ntuple(conn) if conn.fd != -1: # != sunos and windows self.assertEqual(conn.fd, sock.fileno()) self.assertEqual(conn.family, AF_UNIX) self.assertEqual(conn.type, type) self.assertEqual(conn.laddr, TESTFN) if not SUNOS: # XXX Solaris can't retrieve system-wide UNIX # sockets. self.compare_proc_sys_cons(os.getpid(), cons) check(SOCK_STREAM) check(SOCK_DGRAM) @unittest.skipUnless(hasattr(socket, "fromfd"), 'socket.fromfd() is not availble') @unittest.skipIf(WINDOWS or SUNOS, 'connection fd not available on this platform') def test_connection_fromfd(self): with contextlib.closing(socket.socket()) as sock: sock.bind(('localhost', 0)) sock.listen(1) p = psutil.Process() for conn in p.connections(): if conn.fd == sock.fileno(): break else: self.fail("couldn't find socket fd") dupsock = socket.fromfd(conn.fd, conn.family, conn.type) with contextlib.closing(dupsock): self.assertEqual(dupsock.getsockname(), conn.laddr) self.assertNotEqual(sock.fileno(), dupsock.fileno()) def test_connection_constants(self): ints = [] strs = [] for name in dir(psutil): if name.startswith('CONN_'): num = getattr(psutil, name) str_ = str(num) assert str_.isupper(), str_ assert str_ not in strs, str_ assert num not in ints, num ints.append(num) strs.append(str_) if SUNOS: psutil.CONN_IDLE psutil.CONN_BOUND if WINDOWS: psutil.CONN_DELETE_TCB @unittest.skipUnless(POSIX, 'posix only') def test_num_fds(self): p = psutil.Process() start = p.num_fds() file = open(TESTFN, 'w') self.addCleanup(file.close) self.assertEqual(p.num_fds(), start + 1) sock = socket.socket() self.addCleanup(sock.close) self.assertEqual(p.num_fds(), start + 2) file.close() sock.close() self.assertEqual(p.num_fds(), start) @skip_on_not_implemented(only_if=LINUX) @unittest.skipIf(OPENBSD or NETBSD, "not reliable on Open/NetBSD") def test_num_ctx_switches(self): p = psutil.Process() before = sum(p.num_ctx_switches()) for x in range(500000): after = sum(p.num_ctx_switches()) if after > before: return self.fail("num ctx switches still the same after 50.000 iterations") def test_parent_ppid(self): this_parent = os.getpid() sproc = get_test_subprocess() p = psutil.Process(sproc.pid) self.assertEqual(p.ppid(), this_parent) self.assertEqual(p.parent().pid, this_parent) # no other process is supposed to have us as parent for p in psutil.process_iter(): if p.pid == sproc.pid: continue self.assertTrue(p.ppid() != this_parent) def test_children(self): p = psutil.Process() self.assertEqual(p.children(), []) self.assertEqual(p.children(recursive=True), []) sproc = get_test_subprocess() children1 = p.children() children2 = p.children(recursive=True) for children in (children1, children2): self.assertEqual(len(children), 1) self.assertEqual(children[0].pid, sproc.pid) self.assertEqual(children[0].ppid(), os.getpid()) def test_children_recursive(self): # here we create a subprocess which creates another one as in: # A (parent) -> B (child) -> C (grandchild) s = "import subprocess, os, sys, time;" s += "PYTHON = os.path.realpath(sys.executable);" s += "cmd = [PYTHON, '-c', 'import time; time.sleep(60);'];" s += "subprocess.Popen(cmd);" s += "time.sleep(60);" get_test_subprocess(cmd=[PYTHON, "-c", s]) p = psutil.Process() self.assertEqual(len(p.children(recursive=False)), 1) # give the grandchild some time to start stop_at = time.time() + GLOBAL_TIMEOUT while time.time() < stop_at: children = p.children(recursive=True) if len(children) > 1: break self.assertEqual(len(children), 2) self.assertEqual(children[0].ppid(), os.getpid()) self.assertEqual(children[1].ppid(), children[0].pid) def test_children_duplicates(self): # find the process which has the highest number of children table = collections.defaultdict(int) for p in psutil.process_iter(): try: table[p.ppid()] += 1 except psutil.Error: pass # this is the one, now let's make sure there are no duplicates pid = sorted(table.items(), key=lambda x: x[1])[-1][0] p = psutil.Process(pid) try: c = p.children(recursive=True) except psutil.AccessDenied: # windows pass else: self.assertEqual(len(c), len(set(c))) def test_suspend_resume(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) p.suspend() for x in range(100): if p.status() == psutil.STATUS_STOPPED: break time.sleep(0.01) p.resume() self.assertNotEqual(p.status(), psutil.STATUS_STOPPED) def test_invalid_pid(self): self.assertRaises(TypeError, psutil.Process, "1") self.assertRaises(ValueError, psutil.Process, -1) def test_as_dict(self): p = psutil.Process() d = p.as_dict(attrs=['exe', 'name']) self.assertEqual(sorted(d.keys()), ['exe', 'name']) p = psutil.Process(min(psutil.pids())) d = p.as_dict(attrs=['connections'], ad_value='foo') if not isinstance(d['connections'], list): self.assertEqual(d['connections'], 'foo') with mock.patch('psutil.getattr', create=True, side_effect=NotImplementedError): # By default APIs raising NotImplementedError are # supposed to be skipped. self.assertEqual(p.as_dict(), {}) # ...unless the user explicitly asked for some attr. with self.assertRaises(NotImplementedError): p.as_dict(attrs=["name"]) def test_halfway_terminated_process(self): # Test that NoSuchProcess exception gets raised in case the # process dies after we create the Process object. # Example: # >>> proc = Process(1234) # >>> time.sleep(2) # time-consuming task, process dies in meantime # >>> proc.name() # Refers to Issue #15 sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.terminate() p.wait() # if WINDOWS: # wait_for_pid(p.pid) self.assertFalse(p.is_running()) # self.assertFalse(p.pid in psutil.pids(), msg="retcode = %s" % # retcode) excluded_names = ['pid', 'is_running', 'wait', 'create_time'] if LINUX and not RLIMIT_SUPPORT: excluded_names.append('rlimit') for name in dir(p): if (name.startswith('_') or name in excluded_names): continue try: meth = getattr(p, name) # get/set methods if name == 'nice': if POSIX: ret = meth(1) else: ret = meth(psutil.NORMAL_PRIORITY_CLASS) elif name == 'ionice': ret = meth() ret = meth(2) elif name == 'rlimit': ret = meth(psutil.RLIMIT_NOFILE) ret = meth(psutil.RLIMIT_NOFILE, (5, 5)) elif name == 'cpu_affinity': ret = meth() ret = meth([0]) elif name == 'send_signal': ret = meth(signal.SIGTERM) else: ret = meth() except psutil.ZombieProcess: self.fail("ZombieProcess for %r was not supposed to happen" % name) except psutil.NoSuchProcess: pass except psutil.AccessDenied: if OPENBSD and name in ('threads', 'num_threads'): pass else: raise except NotImplementedError: pass else: self.fail( "NoSuchProcess exception not raised for %r, retval=%s" % ( name, ret)) @unittest.skipUnless(POSIX, 'posix only') def test_zombie_process(self): def succeed_or_zombie_p_exc(fun, *args, **kwargs): try: fun(*args, **kwargs) except (psutil.ZombieProcess, psutil.AccessDenied): pass # Note: in this test we'll be creating two sub processes. # Both of them are supposed to be freed / killed by # reap_children() as they are attributable to 'us' # (os.getpid()) via children(recursive=True). src = textwrap.dedent("""\ import os, sys, time, socket, contextlib child_pid = os.fork() if child_pid > 0: time.sleep(3000) else: # this is the zombie process s = socket.socket(socket.AF_UNIX) with contextlib.closing(s): s.connect('%s') if sys.version_info < (3, ): pid = str(os.getpid()) else: pid = bytes(str(os.getpid()), 'ascii') s.sendall(pid) """ % TESTFN) with contextlib.closing(socket.socket(socket.AF_UNIX)) as sock: try: sock.settimeout(GLOBAL_TIMEOUT) sock.bind(TESTFN) sock.listen(1) pyrun(src) conn, _ = sock.accept() select.select([conn.fileno()], [], [], GLOBAL_TIMEOUT) zpid = int(conn.recv(1024)) zproc = psutil.Process(zpid) call_until(lambda: zproc.status(), "ret == psutil.STATUS_ZOMBIE") # A zombie process should always be instantiable zproc = psutil.Process(zpid) # ...and at least its status always be querable self.assertEqual(zproc.status(), psutil.STATUS_ZOMBIE) # ...and it should be considered 'running' self.assertTrue(zproc.is_running()) # ...and as_dict() shouldn't crash zproc.as_dict() if hasattr(zproc, "rlimit"): succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE) succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE, (5, 5)) # set methods succeed_or_zombie_p_exc(zproc.parent) if hasattr(zproc, 'cpu_affinity'): succeed_or_zombie_p_exc(zproc.cpu_affinity, [0]) succeed_or_zombie_p_exc(zproc.nice, 0) if hasattr(zproc, 'ionice'): if LINUX: succeed_or_zombie_p_exc(zproc.ionice, 2, 0) else: succeed_or_zombie_p_exc(zproc.ionice, 0) # Windows if hasattr(zproc, 'rlimit'): succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE, (5, 5)) succeed_or_zombie_p_exc(zproc.suspend) succeed_or_zombie_p_exc(zproc.resume) succeed_or_zombie_p_exc(zproc.terminate) succeed_or_zombie_p_exc(zproc.kill) # ...its parent should 'see' it # edit: not true on BSD and OSX # descendants = [x.pid for x in psutil.Process().children( # recursive=True)] # self.assertIn(zpid, descendants) # XXX should we also assume ppid be usable? Note: this # would be an important use case as the only way to get # rid of a zombie is to kill its parent. # self.assertEqual(zpid.ppid(), os.getpid()) # ...and all other APIs should be able to deal with it self.assertTrue(psutil.pid_exists(zpid)) self.assertIn(zpid, psutil.pids()) self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) psutil._pmap = {} self.assertIn(zpid, [x.pid for x in psutil.process_iter()]) finally: reap_children(search_all=True) def test_pid_0(self): # Process(0) is supposed to work on all platforms except Linux if 0 not in psutil.pids() and not OPENBSD: self.assertRaises(psutil.NoSuchProcess, psutil.Process, 0) return p = psutil.Process(0) self.assertTrue(p.name()) if POSIX: try: self.assertEqual(p.uids().real, 0) self.assertEqual(p.gids().real, 0) except psutil.AccessDenied: pass self.assertRaisesRegexp( ValueError, "preventing sending signal to process with PID 0", p.send_signal, signal.SIGTERM) self.assertIn(p.ppid(), (0, 1)) # self.assertEqual(p.exe(), "") p.cmdline() try: p.num_threads() except psutil.AccessDenied: pass try: p.memory_info() except psutil.AccessDenied: pass try: if POSIX: self.assertEqual(p.username(), 'root') elif WINDOWS: self.assertEqual(p.username(), 'NT AUTHORITY\\SYSTEM') else: p.username() except psutil.AccessDenied: pass p.as_dict() if not OPENBSD: self.assertIn(0, psutil.pids()) self.assertTrue(psutil.pid_exists(0)) def test_Popen(self): # Popen class test # XXX this test causes a ResourceWarning on Python 3 because # psutil.__subproc instance doesn't get propertly freed. # Not sure what to do though. cmd = [PYTHON, "-c", "import time; time.sleep(60);"] proc = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: proc.name() proc.stdin self.assertTrue(hasattr(proc, 'name')) self.assertTrue(hasattr(proc, 'stdin')) self.assertTrue(dir(proc)) self.assertRaises(AttributeError, getattr, proc, 'foo') finally: proc.kill() proc.wait() self.assertIsNotNone(proc.returncode) # =================================================================== # --- Featch all processes test # =================================================================== class TestFetchAllProcesses(unittest.TestCase): """Test which iterates over all running processes and performs some sanity checks against Process API's returned values. """ def setUp(self): if POSIX: import pwd pall = pwd.getpwall() self._uids = set([x.pw_uid for x in pall]) self._usernames = set([x.pw_name for x in pall]) def test_fetch_all(self): valid_procs = 0 excluded_names = set([ 'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'as_dict', 'cpu_percent', 'parent', 'children', 'pid']) if LINUX and not RLIMIT_SUPPORT: excluded_names.add('rlimit') attrs = [] for name in dir(psutil.Process): if name.startswith("_"): continue if name in excluded_names: continue attrs.append(name) default = object() failures = [] for name in attrs: for p in psutil.process_iter(): ret = default try: try: args = () attr = getattr(p, name, None) if attr is not None and callable(attr): if name == 'rlimit': args = (psutil.RLIMIT_NOFILE,) ret = attr(*args) else: ret = attr valid_procs += 1 except NotImplementedError: msg = "%r was skipped because not implemented" % ( self.__class__.__name__ + '.test_' + name) warn(msg) except (psutil.NoSuchProcess, psutil.AccessDenied) as err: self.assertEqual(err.pid, p.pid) if err.name: # make sure exception's name attr is set # with the actual process name self.assertEqual(err.name, p.name()) self.assertTrue(str(err)) self.assertTrue(err.msg) else: if ret not in (0, 0.0, [], None, ''): assert ret, ret meth = getattr(self, name) meth(ret, p) except Exception as err: s = '\n' + '=' * 70 + '\n' s += "FAIL: test_%s (proc=%s" % (name, p) if ret != default: s += ", ret=%s)" % repr(ret) s += ')\n' s += '-' * 70 s += "\n%s" % traceback.format_exc() s = "\n".join((" " * 4) + i for i in s.splitlines()) s += '\n' failures.append(s) break if failures: self.fail(''.join(failures)) # we should always have a non-empty list, not including PID 0 etc. # special cases. self.assertTrue(valid_procs > 0) def cmdline(self, ret, proc): pass def exe(self, ret, proc): if not ret: self.assertEqual(ret, '') else: assert os.path.isabs(ret), ret # Note: os.stat() may return False even if the file is there # hence we skip the test, see: # http://stackoverflow.com/questions/3112546/os-path-exists-lies if POSIX and os.path.isfile(ret): if hasattr(os, 'access') and hasattr(os, "X_OK"): # XXX may fail on OSX self.assertTrue(os.access(ret, os.X_OK)) def ppid(self, ret, proc): self.assertTrue(ret >= 0) def name(self, ret, proc): self.assertIsInstance(ret, (str, unicode)) self.assertTrue(ret) def create_time(self, ret, proc): try: self.assertGreaterEqual(ret, 0) except AssertionError: if OPENBSD and proc.status == psutil.STATUS_ZOMBIE: pass else: raise # this can't be taken for granted on all platforms # self.assertGreaterEqual(ret, psutil.boot_time()) # make sure returned value can be pretty printed # with strftime time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret)) def uids(self, ret, proc): for uid in ret: self.assertTrue(uid >= 0) self.assertIn(uid, self._uids) def gids(self, ret, proc): # note: testing all gids as above seems not to be reliable for # gid == 30 (nodoby); not sure why. for gid in ret: self.assertTrue(gid >= 0) # self.assertIn(uid, self.gids def username(self, ret, proc): self.assertTrue(ret) if POSIX: self.assertIn(ret, self._usernames) def status(self, ret, proc): self.assertTrue(ret != "") self.assertTrue(ret != '?') self.assertIn(ret, VALID_PROC_STATUSES) def io_counters(self, ret, proc): for field in ret: if field != -1: self.assertTrue(field >= 0) def ionice(self, ret, proc): if LINUX: self.assertTrue(ret.ioclass >= 0) self.assertTrue(ret.value >= 0) else: self.assertTrue(ret >= 0) self.assertIn(ret, (0, 1, 2)) def num_threads(self, ret, proc): self.assertTrue(ret >= 1) def threads(self, ret, proc): for t in ret: self.assertTrue(t.id >= 0) self.assertTrue(t.user_time >= 0) self.assertTrue(t.system_time >= 0) def cpu_times(self, ret, proc): self.assertTrue(ret.user >= 0) self.assertTrue(ret.system >= 0) def memory_info(self, ret, proc): self.assertTrue(ret.rss >= 0) self.assertTrue(ret.vms >= 0) def memory_info_ex(self, ret, proc): for name in ret._fields: self.assertTrue(getattr(ret, name) >= 0) if POSIX and ret.vms != 0: # VMS is always supposed to be the highest for name in ret._fields: if name != 'vms': value = getattr(ret, name) assert ret.vms > value, ret elif WINDOWS: assert ret.peak_wset >= ret.wset, ret assert ret.peak_paged_pool >= ret.paged_pool, ret assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret assert ret.peak_pagefile >= ret.pagefile, ret def open_files(self, ret, proc): for f in ret: if WINDOWS: assert f.fd == -1, f else: self.assertIsInstance(f.fd, int) if BSD and not f.path: # XXX see: https://github.com/giampaolo/psutil/issues/595 continue assert os.path.isabs(f.path), f assert os.path.isfile(f.path), f def num_fds(self, ret, proc): self.assertTrue(ret >= 0) def connections(self, ret, proc): self.assertEqual(len(ret), len(set(ret))) for conn in ret: check_connection_ntuple(conn) def cwd(self, ret, proc): if ret is not None: # BSD may return None assert os.path.isabs(ret), ret try: st = os.stat(ret) except OSError as err: # directory has been removed in mean time if err.errno != errno.ENOENT: raise else: self.assertTrue(stat.S_ISDIR(st.st_mode)) def memory_percent(self, ret, proc): assert 0 <= ret <= 100, ret def is_running(self, ret, proc): self.assertTrue(ret) def cpu_affinity(self, ret, proc): assert ret != [], ret def terminal(self, ret, proc): if ret is not None: assert os.path.isabs(ret), ret assert os.path.exists(ret), ret def memory_maps(self, ret, proc): for nt in ret: for fname in nt._fields: value = getattr(nt, fname) if fname == 'path': if not value.startswith('['): assert os.path.isabs(nt.path), nt.path # commented as on Linux we might get # '/foo/bar (deleted)' # assert os.path.exists(nt.path), nt.path elif fname in ('addr', 'perms'): self.assertTrue(value) else: self.assertIsInstance(value, (int, long)) assert value >= 0, value def num_handles(self, ret, proc): if WINDOWS: self.assertGreaterEqual(ret, 0) else: self.assertGreaterEqual(ret, 0) def nice(self, ret, proc): if POSIX: assert -20 <= ret <= 20, ret else: priorities = [getattr(psutil, x) for x in dir(psutil) if x.endswith('_PRIORITY_CLASS')] self.assertIn(ret, priorities) def num_ctx_switches(self, ret, proc): self.assertGreaterEqual(ret.voluntary, 0) self.assertGreaterEqual(ret.involuntary, 0) def rlimit(self, ret, proc): self.assertEqual(len(ret), 2) self.assertGreaterEqual(ret[0], -1) self.assertGreaterEqual(ret[1], -1) # =================================================================== # --- Limited user tests # =================================================================== @unittest.skipUnless(POSIX, "UNIX only") @unittest.skipUnless(hasattr(os, 'getuid') and os.getuid() == 0, "super user privileges are required") class LimitedUserTestCase(TestProcess): """Repeat the previous tests by using a limited user. Executed only on UNIX and only if the user who run the test script is root. """ # the uid/gid the test suite runs under if hasattr(os, 'getuid'): PROCESS_UID = os.getuid() PROCESS_GID = os.getgid() def __init__(self, *args, **kwargs): TestProcess.__init__(self, *args, **kwargs) # re-define all existent test methods in order to # ignore AccessDenied exceptions for attr in [x for x in dir(self) if x.startswith('test')]: meth = getattr(self, attr) def test_(self): try: meth() except psutil.AccessDenied: pass setattr(self, attr, types.MethodType(test_, self)) def setUp(self): safe_remove(TESTFN) TestProcess.setUp(self) os.setegid(1000) os.seteuid(1000) def tearDown(self): os.setegid(self.PROCESS_UID) os.seteuid(self.PROCESS_GID) TestProcess.tearDown(self) def test_nice(self): try: psutil.Process().nice(-1) except psutil.AccessDenied: pass else: self.fail("exception not raised") def test_zombie_process(self): # causes problems if test test suite is run as root pass # =================================================================== # --- Misc tests # =================================================================== class TestMisc(unittest.TestCase): """Misc / generic tests.""" def test_process__repr__(self, func=repr): p = psutil.Process() r = func(p) self.assertIn("psutil.Process", r) self.assertIn("pid=%s" % p.pid, r) self.assertIn("name=", r) self.assertIn(p.name(), r) with mock.patch.object(psutil.Process, "name", side_effect=psutil.ZombieProcess(os.getpid())): p = psutil.Process() r = func(p) self.assertIn("pid=%s" % p.pid, r) self.assertIn("zombie", r) self.assertNotIn("name=", r) with mock.patch.object(psutil.Process, "name", side_effect=psutil.NoSuchProcess(os.getpid())): p = psutil.Process() r = func(p) self.assertIn("pid=%s" % p.pid, r) self.assertIn("terminated", r) self.assertNotIn("name=", r) with mock.patch.object(psutil.Process, "name", side_effect=psutil.AccessDenied(os.getpid())): p = psutil.Process() r = func(p) self.assertIn("pid=%s" % p.pid, r) self.assertNotIn("name=", r) def test_process__str__(self): self.test_process__repr__(func=str) def test_no_such_process__repr__(self, func=repr): self.assertEqual( repr(psutil.NoSuchProcess(321)), "psutil.NoSuchProcess process no longer exists (pid=321)") self.assertEqual( repr(psutil.NoSuchProcess(321, name='foo')), "psutil.NoSuchProcess process no longer exists (pid=321, " "name='foo')") self.assertEqual( repr(psutil.NoSuchProcess(321, msg='foo')), "psutil.NoSuchProcess foo") def test_zombie_process__repr__(self, func=repr): self.assertEqual( repr(psutil.ZombieProcess(321)), "psutil.ZombieProcess process still exists but it's a zombie " "(pid=321)") self.assertEqual( repr(psutil.ZombieProcess(321, name='foo')), "psutil.ZombieProcess process still exists but it's a zombie " "(pid=321, name='foo')") self.assertEqual( repr(psutil.ZombieProcess(321, name='foo', ppid=1)), "psutil.ZombieProcess process still exists but it's a zombie " "(pid=321, name='foo', ppid=1)") self.assertEqual( repr(psutil.ZombieProcess(321, msg='foo')), "psutil.ZombieProcess foo") def test_access_denied__repr__(self, func=repr): self.assertEqual( repr(psutil.AccessDenied(321)), "psutil.AccessDenied (pid=321)") self.assertEqual( repr(psutil.AccessDenied(321, name='foo')), "psutil.AccessDenied (pid=321, name='foo')") self.assertEqual( repr(psutil.AccessDenied(321, msg='foo')), "psutil.AccessDenied foo") def test_timeout_expired__repr__(self, func=repr): self.assertEqual( repr(psutil.TimeoutExpired(321)), "psutil.TimeoutExpired timeout after 321 seconds") self.assertEqual( repr(psutil.TimeoutExpired(321, pid=111)), "psutil.TimeoutExpired timeout after 321 seconds (pid=111)") self.assertEqual( repr(psutil.TimeoutExpired(321, pid=111, name='foo')), "psutil.TimeoutExpired timeout after 321 seconds " "(pid=111, name='foo')") def test_process__eq__(self): p1 = psutil.Process() p2 = psutil.Process() self.assertEqual(p1, p2) p2._ident = (0, 0) self.assertNotEqual(p1, p2) self.assertNotEqual(p1, 'foo') def test_process__hash__(self): s = set([psutil.Process(), psutil.Process()]) self.assertEqual(len(s), 1) def test__all__(self): dir_psutil = dir(psutil) for name in dir_psutil: if name in ('callable', 'error', 'namedtuple', 'long', 'test', 'NUM_CPUS', 'BOOT_TIME', 'TOTAL_PHYMEM'): continue if not name.startswith('_'): try: __import__(name) except ImportError: if name not in psutil.__all__: fun = getattr(psutil, name) if fun is None: continue if (fun.__doc__ is not None and 'deprecated' not in fun.__doc__.lower()): self.fail('%r not in psutil.__all__' % name) # Import 'star' will break if __all__ is inconsistent, see: # https://github.com/giampaolo/psutil/issues/656 # Can't do `from psutil import *` as it won't work on python 3 # so we simply iterate over __all__. for name in psutil.__all__: self.assertIn(name, dir_psutil) def test_version(self): self.assertEqual('.'.join([str(x) for x in psutil.version_info]), psutil.__version__) def test_memoize(self): from psutil._common import memoize @memoize def foo(*args, **kwargs): "foo docstring" calls.append(None) return (args, kwargs) calls = [] # no args for x in range(2): ret = foo() expected = ((), {}) self.assertEqual(ret, expected) self.assertEqual(len(calls), 1) # with args for x in range(2): ret = foo(1) expected = ((1, ), {}) self.assertEqual(ret, expected) self.assertEqual(len(calls), 2) # with args + kwargs for x in range(2): ret = foo(1, bar=2) expected = ((1, ), {'bar': 2}) self.assertEqual(ret, expected) self.assertEqual(len(calls), 3) # clear cache foo.cache_clear() ret = foo() expected = ((), {}) self.assertEqual(ret, expected) self.assertEqual(len(calls), 4) # docstring self.assertEqual(foo.__doc__, "foo docstring") def test_supports_ipv6(self): if supports_ipv6(): with mock.patch('psutil._common.socket') as s: s.has_ipv6 = False assert not supports_ipv6() with mock.patch('psutil._common.socket.socket', side_effect=socket.error) as s: assert not supports_ipv6() assert s.called with mock.patch('psutil._common.socket.socket', side_effect=socket.gaierror) as s: assert not supports_ipv6() assert s.called with mock.patch('psutil._common.socket.socket.bind', side_effect=socket.gaierror) as s: assert not supports_ipv6() assert s.called else: if hasattr(socket, 'AF_INET6'): with self.assertRaises(Exception): sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) sock.bind(("::1", 0)) def test_isfile_strict(self): from psutil._common import isfile_strict this_file = os.path.abspath(__file__) assert isfile_strict(this_file) assert not isfile_strict(os.path.dirname(this_file)) with mock.patch('psutil._common.os.stat', side_effect=OSError(errno.EPERM, "foo")): self.assertRaises(OSError, isfile_strict, this_file) with mock.patch('psutil._common.os.stat', side_effect=OSError(errno.EACCES, "foo")): self.assertRaises(OSError, isfile_strict, this_file) with mock.patch('psutil._common.os.stat', side_effect=OSError(errno.EINVAL, "foo")): assert not isfile_strict(this_file) with mock.patch('psutil._common.stat.S_ISREG', return_value=False): assert not isfile_strict(this_file) def test_serialization(self): def check(ret): if json is not None: json.loads(json.dumps(ret)) a = pickle.dumps(ret) b = pickle.loads(a) self.assertEqual(ret, b) check(psutil.Process().as_dict()) check(psutil.virtual_memory()) check(psutil.swap_memory()) check(psutil.cpu_times()) check(psutil.cpu_times_percent(interval=0)) check(psutil.net_io_counters()) if LINUX and not os.path.exists('/proc/diskstats'): pass else: if not APPVEYOR: check(psutil.disk_io_counters()) check(psutil.disk_partitions()) check(psutil.disk_usage(os.getcwd())) check(psutil.users()) def test_setup_script(self): here = os.path.abspath(os.path.dirname(__file__)) setup_py = os.path.realpath(os.path.join(here, '..', 'setup.py')) module = imp.load_source('setup', setup_py) self.assertRaises(SystemExit, module.setup) self.assertEqual(module.get_version(), psutil.__version__) def test_ad_on_process_creation(self): # We are supposed to be able to instantiate Process also in case # of zombie processes or access denied. with mock.patch.object(psutil.Process, 'create_time', side_effect=psutil.AccessDenied) as meth: psutil.Process() assert meth.called with mock.patch.object(psutil.Process, 'create_time', side_effect=psutil.ZombieProcess(1)) as meth: psutil.Process() assert meth.called with mock.patch.object(psutil.Process, 'create_time', side_effect=ValueError) as meth: with self.assertRaises(ValueError): psutil.Process() assert meth.called # =================================================================== # --- Example script tests # =================================================================== class TestExampleScripts(unittest.TestCase): """Tests for scripts in the examples directory.""" def assert_stdout(self, exe, args=None): exe = os.path.join(EXAMPLES_DIR, exe) if args: exe = exe + ' ' + args try: out = sh(sys.executable + ' ' + exe).strip() except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: raise assert out, out return out def assert_syntax(self, exe, args=None): exe = os.path.join(EXAMPLES_DIR, exe) with open(exe, 'r') as f: src = f.read() ast.parse(src) def test_check_presence(self): # make sure all example scripts have a test method defined meths = dir(self) for name in os.listdir(EXAMPLES_DIR): if name.endswith('.py'): if 'test_' + os.path.splitext(name)[0] not in meths: # self.assert_stdout(name) self.fail('no test defined for %r script' % os.path.join(EXAMPLES_DIR, name)) @unittest.skipUnless(POSIX, "UNIX only") def test_executable(self): for name in os.listdir(EXAMPLES_DIR): if name.endswith('.py'): path = os.path.join(EXAMPLES_DIR, name) if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]: self.fail('%r is not executable' % path) def test_disk_usage(self): self.assert_stdout('disk_usage.py') def test_free(self): self.assert_stdout('free.py') def test_meminfo(self): self.assert_stdout('meminfo.py') def test_process_detail(self): self.assert_stdout('process_detail.py') @unittest.skipIf(APPVEYOR, "can't find users on Appveyor") def test_who(self): self.assert_stdout('who.py') def test_ps(self): self.assert_stdout('ps.py') def test_pstree(self): self.assert_stdout('pstree.py') def test_netstat(self): self.assert_stdout('netstat.py') @unittest.skipIf(TRAVIS, "permission denied on travis") def test_ifconfig(self): self.assert_stdout('ifconfig.py') @unittest.skipIf(OPENBSD or NETBSD, "memory maps not supported") def test_pmap(self): self.assert_stdout('pmap.py', args=str(os.getpid())) @unittest.skipIf(ast is None, 'ast module not available on this python version') def test_killall(self): self.assert_syntax('killall.py') @unittest.skipIf(ast is None, 'ast module not available on this python version') def test_nettop(self): self.assert_syntax('nettop.py') @unittest.skipIf(ast is None, 'ast module not available on this python version') def test_top(self): self.assert_syntax('top.py') @unittest.skipIf(ast is None, 'ast module not available on this python version') def test_iotop(self): self.assert_syntax('iotop.py') def test_pidof(self): output = self.assert_stdout('pidof.py %s' % psutil.Process().name()) self.assertIn(str(os.getpid()), output) class TestUnicode(unittest.TestCase): # See: https://github.com/giampaolo/psutil/issues/655 @classmethod def setUpClass(cls): cls.uexe = create_temp_executable_file('è') cls.ubasename = os.path.basename(cls.uexe) assert 'è' in cls.ubasename @classmethod def tearDownClass(cls): if not APPVEYOR: safe_remove(cls.uexe) def setUp(self): reap_children() tearDown = setUp def test_proc_exe(self): subp = get_test_subprocess(cmd=[self.uexe]) p = psutil.Process(subp.pid) self.assertIsInstance(p.name(), str) self.assertEqual(os.path.basename(p.name()), self.ubasename) def test_proc_name(self): subp = get_test_subprocess(cmd=[self.uexe]) if WINDOWS: from psutil._pswindows import py2_strencode name = py2_strencode(psutil._psplatform.cext.proc_name(subp.pid)) else: name = psutil.Process(subp.pid).name() self.assertEqual(name, self.ubasename) def test_proc_cmdline(self): subp = get_test_subprocess(cmd=[self.uexe]) p = psutil.Process(subp.pid) self.assertIsInstance("".join(p.cmdline()), str) self.assertEqual(p.cmdline(), [self.uexe]) def test_proc_cwd(self): tdir = os.path.realpath(tempfile.mkdtemp(prefix="psutil-è-")) self.addCleanup(safe_rmdir, tdir) with chdir(tdir): p = psutil.Process() self.assertIsInstance(p.cwd(), str) self.assertEqual(p.cwd(), tdir) @unittest.skipIf(APPVEYOR, "") def test_proc_open_files(self): p = psutil.Process() start = set(p.open_files()) with open(self.uexe, 'rb'): new = set(p.open_files()) path = (new - start).pop().path if BSD and not path: # XXX # see https://github.com/giampaolo/psutil/issues/595 self.skipTest("open_files on BSD is broken") self.assertIsInstance(path, str) self.assertEqual(os.path.normcase(path), os.path.normcase(self.uexe)) def test_psutil_is_reloadable(self): importlib.reload(psutil) def main(): tests = [] test_suite = unittest.TestSuite() tests.append(TestSystemAPIs) tests.append(TestProcess) tests.append(TestFetchAllProcesses) tests.append(TestMisc) tests.append(TestExampleScripts) tests.append(LimitedUserTestCase) tests.append(TestUnicode) if POSIX: from _posix import PosixSpecificTestCase tests.append(PosixSpecificTestCase) # import the specific platform test suite stc = None if LINUX: from _linux import LinuxSpecificTestCase as stc elif WINDOWS: from _windows import WindowsSpecificTestCase as stc from _windows import TestDualProcessImplementation tests.append(TestDualProcessImplementation) elif OSX: from _osx import OSXSpecificTestCase as stc elif SUNOS: from _sunos import SunOSSpecificTestCase as stc elif BSD: from _bsd import BSDSpecificTestCase as stc if FREEBSD: from _bsd import FreeBSDSpecificTestCase tests.append(FreeBSDSpecificTestCase) elif OPENBSD: from _bsd import OpenBSDSpecificTestCase tests.append(OpenBSDSpecificTestCase) if stc is not None: tests.append(stc) for test_class in tests: test_suite.addTest(unittest.makeSuite(test_class)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_osx.py0000664000175000017500000001430212612744133017310 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """OSX specific tests. These are implicitly run by test_psutil.py.""" import os import re import subprocess import sys import time import psutil from psutil._compat import PY3 from test_psutil import get_test_subprocess from test_psutil import MEMORY_TOLERANCE from test_psutil import OSX from test_psutil import reap_children from test_psutil import retry_before_failing from test_psutil import sh from test_psutil import TRAVIS from test_psutil import unittest PAGESIZE = os.sysconf("SC_PAGE_SIZE") def sysctl(cmdline): """Expects a sysctl command with an argument and parse the result returning only the value of interest. """ p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) result = p.communicate()[0].strip().split()[1] if PY3: result = str(result, sys.stdout.encoding) try: return int(result) except ValueError: return result def vm_stat(field): """Wrapper around 'vm_stat' cmdline utility.""" out = sh('vm_stat') for line in out.split('\n'): if field in line: break else: raise ValueError("line not found") return int(re.search('\d+', line).group(0)) * PAGESIZE # http://code.activestate.com/recipes/578019/ def human2bytes(s): SYMBOLS = { 'customary': ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'), } init = s num = "" while s and s[0:1].isdigit() or s[0:1] == '.': num += s[0] s = s[1:] num = float(num) letter = s.strip() for name, sset in SYMBOLS.items(): if letter in sset: break else: if letter == 'k': sset = SYMBOLS['customary'] letter = letter.upper() else: raise ValueError("can't interpret %r" % init) prefix = {sset[0]: 1} for i, s in enumerate(sset[1:]): prefix[s] = 1 << (i+1)*10 return int(num * prefix[letter]) @unittest.skipUnless(OSX, "not an OSX system") class OSXSpecificTestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.pid = get_test_subprocess().pid @classmethod def tearDownClass(cls): reap_children() def test_process_create_time(self): cmdline = "ps -o lstart -p %s" % self.pid p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) output = p.communicate()[0] if PY3: output = str(output, sys.stdout.encoding) start_ps = output.replace('STARTED', '').strip() start_psutil = psutil.Process(self.pid).create_time() start_psutil = time.strftime("%a %b %e %H:%M:%S %Y", time.localtime(start_psutil)) self.assertEqual(start_ps, start_psutil) def test_disks(self): # test psutil.disk_usage() and psutil.disk_partitions() # against "df -a" def df(path): out = sh('df -k "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total = int(total) * 1024 used = int(used) * 1024 free = int(free) * 1024 return dev, total, used, free for part in psutil.disk_partitions(all=False): usage = psutil.disk_usage(part.mountpoint) dev, total, used, free = df(part.mountpoint) self.assertEqual(part.device, dev) self.assertEqual(usage.total, total) # 10 MB tollerance if abs(usage.free - free) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % usage.free, free) if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % usage.used, used) def test_cpu_count_logical(self): num = sysctl("sysctl hw.logicalcpu") self.assertEqual(num, psutil.cpu_count(logical=True)) def test_cpu_count_physical(self): num = sysctl("sysctl hw.physicalcpu") self.assertEqual(num, psutil.cpu_count(logical=False)) # --- virtual mem def test_vmem_total(self): sysctl_hwphymem = sysctl('sysctl hw.memsize') self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total) @unittest.skipIf(TRAVIS, "") @retry_before_failing() def test_vmem_free(self): num = vm_stat("free") self.assertAlmostEqual(psutil.virtual_memory().free, num, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_active(self): num = vm_stat("active") self.assertAlmostEqual(psutil.virtual_memory().active, num, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_inactive(self): num = vm_stat("inactive") self.assertAlmostEqual(psutil.virtual_memory().inactive, num, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_wired(self): num = vm_stat("wired") self.assertAlmostEqual(psutil.virtual_memory().wired, num, delta=MEMORY_TOLERANCE) # --- swap mem def test_swapmem_sin(self): num = vm_stat("Pageins") self.assertEqual(psutil.swap_memory().sin, num) def test_swapmem_sout(self): num = vm_stat("Pageouts") self.assertEqual(psutil.swap_memory().sout, num) def test_swapmem_total(self): out = sh('sysctl vm.swapusage') out = out.replace('vm.swapusage: ', '') total, used, free = re.findall('\d+.\d+\w', out) psutil_smem = psutil.swap_memory() self.assertEqual(psutil_smem.total, human2bytes(total)) self.assertEqual(psutil_smem.used, human2bytes(used)) self.assertEqual(psutil_smem.free, human2bytes(free)) def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_bsd.py0000664000175000017500000002477212646126646017275 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. # TODO: (FreeBSD) add test for comparing connections with 'sockstat' cmd. """Tests specific to all BSD platforms. These are implicitly run by test_psutil. py.""" import datetime import os import subprocess import sys import time import psutil from psutil._compat import PY3 from test_psutil import BSD from test_psutil import FREEBSD from test_psutil import get_test_subprocess from test_psutil import MEMORY_TOLERANCE from test_psutil import NETBSD from test_psutil import OPENBSD from test_psutil import reap_children from test_psutil import retry_before_failing from test_psutil import sh from test_psutil import unittest from test_psutil import which PAGESIZE = os.sysconf("SC_PAGE_SIZE") if os.getuid() == 0: # muse requires root privileges MUSE_AVAILABLE = which('muse') else: MUSE_AVAILABLE = False def sysctl(cmdline): """Expects a sysctl command with an argument and parse the result returning only the value of interest. """ result = sh("sysctl " + cmdline) if FREEBSD: result = result[result.find(": ") + 2:] elif OPENBSD or NETBSD: result = result[result.find("=") + 1:] try: return int(result) except ValueError: return result def muse(field): """Thin wrapper around 'muse' cmdline utility.""" out = sh('muse') for line in out.split('\n'): if line.startswith(field): break else: raise ValueError("line not found") return int(line.split()[1]) # ===================================================================== # --- All BSD* # ===================================================================== @unittest.skipUnless(BSD, "not a BSD system") class BSDSpecificTestCase(unittest.TestCase): """Generic tests common to all BSD variants.""" @classmethod def setUpClass(cls): cls.pid = get_test_subprocess().pid @classmethod def tearDownClass(cls): reap_children() def test_process_create_time(self): cmdline = "ps -o lstart -p %s" % self.pid p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) output = p.communicate()[0] if PY3: output = str(output, sys.stdout.encoding) start_ps = output.replace('STARTED', '').strip() start_psutil = psutil.Process(self.pid).create_time() start_psutil = time.strftime("%a %b %e %H:%M:%S %Y", time.localtime(start_psutil)) self.assertEqual(start_ps, start_psutil) def test_disks(self): # test psutil.disk_usage() and psutil.disk_partitions() # against "df -a" def df(path): out = sh('df -k "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total = int(total) * 1024 used = int(used) * 1024 free = int(free) * 1024 return dev, total, used, free for part in psutil.disk_partitions(all=False): usage = psutil.disk_usage(part.mountpoint) dev, total, used, free = df(part.mountpoint) self.assertEqual(part.device, dev) self.assertEqual(usage.total, total) # 10 MB tollerance if abs(usage.free - free) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.free, free)) if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.used, used)) def test_cpu_count_logical(self): syst = sysctl("hw.ncpu") self.assertEqual(psutil.cpu_count(logical=True), syst) def test_virtual_memory_total(self): num = sysctl('hw.physmem') self.assertEqual(num, psutil.virtual_memory().total) # ===================================================================== # --- FreeBSD # ===================================================================== @unittest.skipUnless(FREEBSD, "not a FreeBSD system") class FreeBSDSpecificTestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.pid = get_test_subprocess().pid @classmethod def tearDownClass(cls): reap_children() def test_boot_time(self): s = sysctl('sysctl kern.boottime') s = s[s.find(" sec = ") + 7:] s = s[:s.find(',')] btime = int(s) self.assertEqual(btime, psutil.boot_time()) @retry_before_failing() def test_memory_maps(self): out = sh('procstat -v %s' % self.pid) maps = psutil.Process(self.pid).memory_maps(grouped=False) lines = out.split('\n')[1:] while lines: line = lines.pop() fields = line.split() _, start, stop, perms, res = fields[:5] map = maps.pop() self.assertEqual("%s-%s" % (start, stop), map.addr) self.assertEqual(int(res), map.rss) if not map.path.startswith('['): self.assertEqual(fields[10], map.path) def test_exe(self): out = sh('procstat -b %s' % self.pid) self.assertEqual(psutil.Process(self.pid).exe(), out.split('\n')[1].split()[-1]) def test_cmdline(self): out = sh('procstat -c %s' % self.pid) self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()), ' '.join(out.split('\n')[1].split()[2:])) def test_uids_gids(self): out = sh('procstat -s %s' % self.pid) euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8] p = psutil.Process(self.pid) uids = p.uids() gids = p.gids() self.assertEqual(uids.real, int(ruid)) self.assertEqual(uids.effective, int(euid)) self.assertEqual(uids.saved, int(suid)) self.assertEqual(gids.real, int(rgid)) self.assertEqual(gids.effective, int(egid)) self.assertEqual(gids.saved, int(sgid)) # --- virtual_memory(); tests against sysctl @retry_before_failing() def test_vmem_active(self): syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE self.assertAlmostEqual(psutil.virtual_memory().active, syst, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_inactive(self): syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE self.assertAlmostEqual(psutil.virtual_memory().inactive, syst, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_wired(self): syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE self.assertAlmostEqual(psutil.virtual_memory().wired, syst, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_cached(self): syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE self.assertAlmostEqual(psutil.virtual_memory().cached, syst, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_free(self): syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE self.assertAlmostEqual(psutil.virtual_memory().free, syst, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_buffers(self): syst = sysctl("vfs.bufspace") self.assertAlmostEqual(psutil.virtual_memory().buffers, syst, delta=MEMORY_TOLERANCE) # --- virtual_memory(); tests against muse @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") def test_muse_vmem_total(self): num = muse('Total') self.assertEqual(psutil.virtual_memory().total, num) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_active(self): num = muse('Active') self.assertAlmostEqual(psutil.virtual_memory().active, num, delta=MEMORY_TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_inactive(self): num = muse('Inactive') self.assertAlmostEqual(psutil.virtual_memory().inactive, num, delta=MEMORY_TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_wired(self): num = muse('Wired') self.assertAlmostEqual(psutil.virtual_memory().wired, num, delta=MEMORY_TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_cached(self): num = muse('Cache') self.assertAlmostEqual(psutil.virtual_memory().cached, num, delta=MEMORY_TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_free(self): num = muse('Free') self.assertAlmostEqual(psutil.virtual_memory().free, num, delta=MEMORY_TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_muse_vmem_buffers(self): num = muse('Buffer') self.assertAlmostEqual(psutil.virtual_memory().buffers, num, delta=MEMORY_TOLERANCE) # ===================================================================== # --- OpenBSD # ===================================================================== @unittest.skipUnless(OPENBSD, "not an OpenBSD system") class OpenBSDSpecificTestCase(unittest.TestCase): def test_boot_time(self): s = sysctl('kern.boottime') sys_bt = datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y") psutil_bt = datetime.datetime.fromtimestamp(psutil.boot_time()) self.assertEqual(sys_bt, psutil_bt) def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase)) if FREEBSD: test_suite.addTest(unittest.makeSuite(FreeBSDSpecificTestCase)) elif OPENBSD: test_suite.addTest(unittest.makeSuite(OpenBSDSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_posix.py0000664000175000017500000002461712645411704017654 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """POSIX specific tests. These are implicitly run by test_psutil.py.""" import datetime import os import subprocess import sys import time import psutil from psutil._compat import PY3, callable from test_psutil import BSD from test_psutil import get_kernel_version from test_psutil import get_test_subprocess from test_psutil import LINUX from test_psutil import OSX from test_psutil import POSIX from test_psutil import PYTHON from test_psutil import reap_children from test_psutil import retry_before_failing from test_psutil import sh from test_psutil import skip_on_access_denied from test_psutil import SUNOS from test_psutil import TRAVIS from test_psutil import unittest from test_psutil import wait_for_pid def ps(cmd): """Expects a ps command with a -o argument and parse the result returning only the value of interest. """ if not LINUX: cmd = cmd.replace(" --no-headers ", " ") if SUNOS: cmd = cmd.replace("-o command", "-o comm") cmd = cmd.replace("-o start", "-o stime") p = subprocess.Popen(cmd, shell=1, stdout=subprocess.PIPE) output = p.communicate()[0].strip() if PY3: output = str(output, sys.stdout.encoding) if not LINUX: output = output.split('\n')[1].strip() try: return int(output) except ValueError: return output @unittest.skipUnless(POSIX, "not a POSIX system") class PosixSpecificTestCase(unittest.TestCase): """Compare psutil results against 'ps' command line utility.""" @classmethod def setUpClass(cls): cls.pid = get_test_subprocess([PYTHON, "-E", "-O"], stdin=subprocess.PIPE).pid wait_for_pid(cls.pid) @classmethod def tearDownClass(cls): reap_children() # for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps def test_process_parent_pid(self): ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid) ppid_psutil = psutil.Process(self.pid).ppid() self.assertEqual(ppid_ps, ppid_psutil) def test_process_uid(self): uid_ps = ps("ps --no-headers -o uid -p %s" % self.pid) uid_psutil = psutil.Process(self.pid).uids().real self.assertEqual(uid_ps, uid_psutil) def test_process_gid(self): gid_ps = ps("ps --no-headers -o rgid -p %s" % self.pid) gid_psutil = psutil.Process(self.pid).gids().real self.assertEqual(gid_ps, gid_psutil) def test_process_username(self): username_ps = ps("ps --no-headers -o user -p %s" % self.pid) username_psutil = psutil.Process(self.pid).username() self.assertEqual(username_ps, username_psutil) @skip_on_access_denied() @retry_before_failing() def test_process_rss_memory(self): # give python interpreter some time to properly initialize # so that the results are the same time.sleep(0.1) rss_ps = ps("ps --no-headers -o rss -p %s" % self.pid) rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024 self.assertEqual(rss_ps, rss_psutil) @skip_on_access_denied() @retry_before_failing() def test_process_vsz_memory(self): # give python interpreter some time to properly initialize # so that the results are the same time.sleep(0.1) vsz_ps = ps("ps --no-headers -o vsz -p %s" % self.pid) vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024 self.assertEqual(vsz_ps, vsz_psutil) def test_process_name(self): # use command + arg since "comm" keyword not supported on all platforms name_ps = ps("ps --no-headers -o command -p %s" % ( self.pid)).split(' ')[0] # remove path if there is any, from the command name_ps = os.path.basename(name_ps).lower() name_psutil = psutil.Process(self.pid).name().lower() self.assertEqual(name_ps, name_psutil) @unittest.skipIf(OSX or BSD, 'ps -o start not available') def test_process_create_time(self): time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0] time_psutil = psutil.Process(self.pid).create_time() time_psutil_tstamp = datetime.datetime.fromtimestamp( time_psutil).strftime("%H:%M:%S") # sometimes ps shows the time rounded up instead of down, so we check # for both possible values round_time_psutil = round(time_psutil) round_time_psutil_tstamp = datetime.datetime.fromtimestamp( round_time_psutil).strftime("%H:%M:%S") self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp]) def test_process_exe(self): ps_pathname = ps("ps --no-headers -o command -p %s" % self.pid).split(' ')[0] psutil_pathname = psutil.Process(self.pid).exe() try: self.assertEqual(ps_pathname, psutil_pathname) except AssertionError: # certain platforms such as BSD are more accurate returning: # "/usr/local/bin/python2.7" # ...instead of: # "/usr/local/bin/python" # We do not want to consider this difference in accuracy # an error. adjusted_ps_pathname = ps_pathname[:len(ps_pathname)] self.assertEqual(ps_pathname, adjusted_ps_pathname) def test_process_cmdline(self): ps_cmdline = ps("ps --no-headers -o command -p %s" % self.pid) psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline()) if SUNOS: # ps on Solaris only shows the first part of the cmdline psutil_cmdline = psutil_cmdline.split(" ")[0] self.assertEqual(ps_cmdline, psutil_cmdline) def test_process_nice(self): ps_nice = ps("ps --no-headers -o nice -p %s" % self.pid) psutil_nice = psutil.Process().nice() self.assertEqual(ps_nice, psutil_nice) @retry_before_failing() def test_pids(self): # Note: this test might fail if the OS is starting/killing # other processes in the meantime if SUNOS: cmd = ["ps", "-A", "-o", "pid"] else: cmd = ["ps", "ax", "-o", "pid"] p = get_test_subprocess(cmd, stdout=subprocess.PIPE) output = p.communicate()[0].strip() assert p.poll() == 0 if PY3: output = str(output, sys.stdout.encoding) pids_ps = [] for line in output.split('\n')[1:]: if line: pid = int(line.split()[0].strip()) pids_ps.append(pid) # remove ps subprocess pid which is supposed to be dead in meantime pids_ps.remove(p.pid) pids_psutil = psutil.pids() pids_ps.sort() pids_psutil.sort() # on OSX ps doesn't show pid 0 if OSX and 0 not in pids_ps: pids_ps.insert(0, 0) if pids_ps != pids_psutil: difference = [x for x in pids_psutil if x not in pids_ps] + \ [x for x in pids_ps if x not in pids_psutil] self.fail("difference: " + str(difference)) # for some reason ifconfig -a does not report all interfaces # returned by psutil @unittest.skipIf(SUNOS, "test not reliable on SUNOS") @unittest.skipIf(TRAVIS, "test not reliable on Travis") def test_nic_names(self): p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE) output = p.communicate()[0].strip() if PY3: output = str(output, sys.stdout.encoding) for nic in psutil.net_io_counters(pernic=True).keys(): for line in output.split(): if line.startswith(nic): break else: self.fail( "couldn't find %s nic in 'ifconfig -a' output\n%s" % ( nic, output)) @retry_before_failing() def test_users(self): out = sh("who") lines = out.split('\n') users = [x.split()[0] for x in lines] self.assertEqual(len(users), len(psutil.users())) terminals = [x.split()[1] for x in lines] for u in psutil.users(): self.assertTrue(u.name in users, u.name) self.assertTrue(u.terminal in terminals, u.terminal) def test_fds_open(self): # Note: this fails from time to time; I'm keen on thinking # it doesn't mean something is broken def call(p, attr): args = () attr = getattr(p, name, None) if attr is not None and callable(attr): if name == 'rlimit': args = (psutil.RLIMIT_NOFILE,) attr(*args) else: attr p = psutil.Process(os.getpid()) failures = [] ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice', 'send_signal', 'wait', 'children', 'as_dict'] if LINUX and get_kernel_version() < (2, 6, 36): ignored_names.append('rlimit') if LINUX and get_kernel_version() < (2, 6, 23): ignored_names.append('num_ctx_switches') for name in dir(psutil.Process): if (name.startswith('_') or name in ignored_names): continue else: try: num1 = p.num_fds() for x in range(2): call(p, name) num2 = p.num_fds() except psutil.AccessDenied: pass else: if abs(num2 - num1) > 1: fail = "failure while processing Process.%s method " \ "(before=%s, after=%s)" % (name, num1, num2) failures.append(fail) if failures: self.fail('\n' + '\n'.join(failures)) @unittest.skipUnless(os.path.islink("/proc/%s/cwd" % os.getpid()), "/proc fs not available") def test_cwd_proc(self): self.assertEqual(os.readlink("/proc/%s/cwd" % os.getpid()), psutil.Process().cwd()) def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_linux.py0000664000175000017500000006020212645410637017643 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Linux specific tests. These are implicitly run by test_psutil.py.""" from __future__ import division import contextlib import errno import fcntl import io import os import pprint import re import shutil import socket import struct import sys import tempfile import time import warnings try: from unittest import mock # py3 except ImportError: import mock # requires "pip install mock" import psutil import psutil._pslinux from psutil._compat import PY3 from psutil._compat import u from test_psutil import call_until from test_psutil import get_kernel_version from test_psutil import get_test_subprocess from test_psutil import importlib from test_psutil import LINUX from test_psutil import MEMORY_TOLERANCE from test_psutil import POSIX from test_psutil import retry_before_failing from test_psutil import sh from test_psutil import skip_on_not_implemented from test_psutil import TRAVIS from test_psutil import unittest from test_psutil import which HERE = os.path.abspath(os.path.dirname(__file__)) # procps-ng 3.3.10 changed the output format of free # and removed the 'buffers/cache line' OLD_PROCPS_NG_VERSION = 'buffers/cache' in sh('free') SIOCGIFADDR = 0x8915 SIOCGIFCONF = 0x8912 SIOCGIFHWADDR = 0x8927 def get_ipv4_address(ifname): ifname = ifname[:15] if PY3: ifname = bytes(ifname, 'ascii') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) with contextlib.closing(s): return socket.inet_ntoa( fcntl.ioctl(s.fileno(), SIOCGIFADDR, struct.pack('256s', ifname))[20:24]) def get_mac_address(ifname): ifname = ifname[:15] if PY3: ifname = bytes(ifname, 'ascii') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) with contextlib.closing(s): info = fcntl.ioctl( s.fileno(), SIOCGIFHWADDR, struct.pack('256s', ifname)) if PY3: def ord(x): return x else: import __builtin__ ord = __builtin__.ord return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1] @unittest.skipUnless(LINUX, "not a Linux system") class LinuxSpecificTestCase(unittest.TestCase): @unittest.skipIf( POSIX and not hasattr(os, 'statvfs'), reason="os.statvfs() function not available on this platform") @skip_on_not_implemented() def test_disks(self): # test psutil.disk_usage() and psutil.disk_partitions() # against "df -a" def df(path): out = sh('df -P -B 1 "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total, used, free = int(total), int(used), int(free) return dev, total, used, free for part in psutil.disk_partitions(all=False): usage = psutil.disk_usage(part.mountpoint) dev, total, used, free = df(part.mountpoint) self.assertEqual(part.device, dev) self.assertEqual(usage.total, total) # 10 MB tollerance if abs(usage.free - free) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.free, free)) if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.used, used)) def test_memory_maps(self): sproc = get_test_subprocess() time.sleep(1) p = psutil.Process(sproc.pid) maps = p.memory_maps(grouped=False) pmap = sh('pmap -x %s' % p.pid).split('\n') # get rid of header del pmap[0] del pmap[0] while maps and pmap: this = maps.pop(0) other = pmap.pop(0) addr, _, rss, dirty, mode, path = other.split(None, 5) if not path.startswith('[') and not path.endswith(']'): self.assertEqual(path, os.path.basename(this.path)) self.assertEqual(int(rss) * 1024, this.rss) # test only rwx chars, ignore 's' and 'p' self.assertEqual(mode[:3], this.perms[:3]) def test_vmem_total(self): lines = sh('free').split('\n')[1:] total = int(lines[0].split()[1]) * 1024 self.assertEqual(total, psutil.virtual_memory().total) @retry_before_failing() def test_vmem_used(self): lines = sh('free').split('\n')[1:] total = int(lines[0].split()[1]) free = int(lines[0].split()[3]) used = (total - free) * 1024 self.assertAlmostEqual(used, psutil.virtual_memory().used, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_free(self): lines = sh('free').split('\n')[1:] free = int(lines[0].split()[3]) * 1024 self.assertAlmostEqual(free, psutil.virtual_memory().free, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_buffers(self): buffers = int(sh('vmstat').split('\n')[2].split()[4]) * 1024 self.assertAlmostEqual(buffers, psutil.virtual_memory().buffers, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_vmem_cached(self): cached = int(sh('vmstat').split('\n')[2].split()[5]) * 1024 self.assertAlmostEqual(cached, psutil.virtual_memory().cached, delta=MEMORY_TOLERANCE) def test_swapmem_total(self): lines = sh('free').split('\n')[1:] total = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[1]) * 1024 self.assertEqual(total, psutil.swap_memory().total) @retry_before_failing() def test_swapmem_used(self): lines = sh('free').split('\n')[1:] used = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[2]) * 1024 self.assertAlmostEqual(used, psutil.swap_memory().used, delta=MEMORY_TOLERANCE) @retry_before_failing() def test_swapmem_free(self): lines = sh('free').split('\n')[1:] free = int(lines[2 if OLD_PROCPS_NG_VERSION else 1].split()[1]) * 1024 self.assertAlmostEqual(free, psutil.swap_memory().free, delta=MEMORY_TOLERANCE) @unittest.skipIf(TRAVIS, "unknown failure on travis") def test_cpu_times(self): fields = psutil.cpu_times()._fields kernel_ver = re.findall('\d+\.\d+\.\d+', os.uname()[2])[0] kernel_ver_info = tuple(map(int, kernel_ver.split('.'))) if kernel_ver_info >= (2, 6, 11): self.assertIn('steal', fields) else: self.assertNotIn('steal', fields) if kernel_ver_info >= (2, 6, 24): self.assertIn('guest', fields) else: self.assertNotIn('guest', fields) if kernel_ver_info >= (3, 2, 0): self.assertIn('guest_nice', fields) else: self.assertNotIn('guest_nice', fields) def test_net_if_addrs_ips(self): for name, addrs in psutil.net_if_addrs().items(): for addr in addrs: if addr.family == psutil.AF_LINK: self.assertEqual(addr.address, get_mac_address(name)) elif addr.family == socket.AF_INET: self.assertEqual(addr.address, get_ipv4_address(name)) # TODO: test for AF_INET6 family @unittest.skipUnless(which('ip'), "'ip' utility not available") @unittest.skipIf(TRAVIS, "skipped on Travis") def test_net_if_names(self): out = sh("ip addr").strip() nics = [x for x in psutil.net_if_addrs().keys() if ':' not in x] found = 0 for line in out.split('\n'): line = line.strip() if re.search("^\d+:", line): found += 1 name = line.split(':')[1].strip() self.assertIn(name, nics) self.assertEqual(len(nics), found, msg="%s\n---\n%s" % ( pprint.pformat(nics), out)) @unittest.skipUnless(which("nproc"), "nproc utility not available") def test_cpu_count_logical_w_nproc(self): num = int(sh("nproc --all")) self.assertEqual(psutil.cpu_count(logical=True), num) @unittest.skipUnless(which("lscpu"), "lscpu utility not available") def test_cpu_count_logical_w_lscpu(self): out = sh("lscpu -p") num = len([x for x in out.split('\n') if not x.startswith('#')]) self.assertEqual(psutil.cpu_count(logical=True), num) # --- mocked tests def test_virtual_memory_mocked_warnings(self): with mock.patch('psutil._pslinux.open', create=True) as m: with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ret = psutil._pslinux.virtual_memory() assert m.called self.assertEqual(len(ws), 1) w = ws[0] self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) self.assertIn( "'cached', 'active' and 'inactive' memory stats couldn't " "be determined", str(w.message)) self.assertEqual(ret.cached, 0) self.assertEqual(ret.active, 0) self.assertEqual(ret.inactive, 0) def test_swap_memory_mocked_warnings(self): with mock.patch('psutil._pslinux.open', create=True) as m: with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ret = psutil._pslinux.swap_memory() assert m.called self.assertEqual(len(ws), 1) w = ws[0] self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) self.assertIn( "'sin' and 'sout' swap memory stats couldn't " "be determined", str(w.message)) self.assertEqual(ret.sin, 0) self.assertEqual(ret.sout, 0) def test_swap_memory_mocked_no_vmstat(self): # see https://github.com/giampaolo/psutil/issues/722 with mock.patch('psutil._pslinux.open', create=True, side_effect=IOError) as m: with warnings.catch_warnings(record=True) as ws: warnings.simplefilter("always") ret = psutil.swap_memory() assert m.called self.assertEqual(len(ws), 1) w = ws[0] self.assertTrue(w.filename.endswith('psutil/_pslinux.py')) self.assertIn( "'sin' and 'sout' swap memory stats couldn't " "be determined and were set to 0", str(w.message)) self.assertEqual(ret.sin, 0) self.assertEqual(ret.sout, 0) def test_cpu_count_logical_mocked(self): import psutil._pslinux original = psutil._pslinux.cpu_count_logical() # Here we want to mock os.sysconf("SC_NPROCESSORS_ONLN") in # order to cause the parsing of /proc/cpuinfo and /proc/stat. with mock.patch( 'psutil._pslinux.os.sysconf', side_effect=ValueError) as m: self.assertEqual(psutil._pslinux.cpu_count_logical(), original) assert m.called # Let's have open() return emtpy data and make sure None is # returned ('cause we mimick os.cpu_count()). with mock.patch('psutil._pslinux.open', create=True) as m: self.assertIsNone(psutil._pslinux.cpu_count_logical()) self.assertEqual(m.call_count, 2) # /proc/stat should be the last one self.assertEqual(m.call_args[0][0], '/proc/stat') # Let's push this a bit further and make sure /proc/cpuinfo # parsing works as expected. with open('/proc/cpuinfo', 'rb') as f: cpuinfo_data = f.read() fake_file = io.BytesIO(cpuinfo_data) with mock.patch('psutil._pslinux.open', return_value=fake_file, create=True) as m: self.assertEqual(psutil._pslinux.cpu_count_logical(), original) def test_cpu_count_physical_mocked(self): # Have open() return emtpy data and make sure None is returned # ('cause we want to mimick os.cpu_count()) with mock.patch('psutil._pslinux.open', create=True) as m: self.assertIsNone(psutil._pslinux.cpu_count_physical()) assert m.called def test_proc_open_files_file_gone(self): # simulates a file which gets deleted during open_files() # execution p = psutil.Process() files = p.open_files() with tempfile.NamedTemporaryFile(): # give the kernel some time to see the new file call_until(p.open_files, "len(ret) != %i" % len(files)) with mock.patch('psutil._pslinux.os.readlink', side_effect=OSError(errno.ENOENT, "")) as m: files = p.open_files() assert not files assert m.called # also simulate the case where os.readlink() returns EINVAL # in which case psutil is supposed to 'continue' with mock.patch('psutil._pslinux.os.readlink', side_effect=OSError(errno.EINVAL, "")) as m: self.assertEqual(p.open_files(), []) assert m.called def test_proc_terminal_mocked(self): with mock.patch('psutil._pslinux._psposix._get_terminal_map', return_value={}) as m: self.assertIsNone(psutil._pslinux.Process(os.getpid()).terminal()) assert m.called def test_proc_num_ctx_switches_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).num_ctx_switches) assert m.called def test_proc_num_threads_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).num_threads) assert m.called def test_proc_ppid_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).ppid) assert m.called def test_proc_uids_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).uids) assert m.called def test_proc_gids_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).gids) assert m.called def test_proc_cmdline_mocked(self): # see: https://github.com/giampaolo/psutil/issues/639 p = psutil.Process() fake_file = io.StringIO(u('foo\x00bar\x00')) with mock.patch('psutil._pslinux.open', return_value=fake_file, create=True) as m: p.cmdline() == ['foo', 'bar'] assert m.called fake_file = io.StringIO(u('foo\x00bar\x00\x00')) with mock.patch('psutil._pslinux.open', return_value=fake_file, create=True) as m: p.cmdline() == ['foo', 'bar', ''] assert m.called def test_proc_io_counters_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( NotImplementedError, psutil._pslinux.Process(os.getpid()).io_counters) assert m.called def test_boot_time_mocked(self): with mock.patch('psutil._pslinux.open', create=True) as m: self.assertRaises( RuntimeError, psutil._pslinux.boot_time) assert m.called def test_users_mocked(self): # Make sure ':0' and ':0.0' (returned by C ext) are converted # to 'localhost'. with mock.patch('psutil._pslinux.cext.users', return_value=[('giampaolo', 'pts/2', ':0', 1436573184.0, True)]) as m: self.assertEqual(psutil.users()[0].host, 'localhost') assert m.called with mock.patch('psutil._pslinux.cext.users', return_value=[('giampaolo', 'pts/2', ':0.0', 1436573184.0, True)]) as m: self.assertEqual(psutil.users()[0].host, 'localhost') assert m.called # ...otherwise it should be returned as-is with mock.patch('psutil._pslinux.cext.users', return_value=[('giampaolo', 'pts/2', 'foo', 1436573184.0, True)]) as m: self.assertEqual(psutil.users()[0].host, 'foo') assert m.called def test_disk_partitions_mocked(self): # Test that ZFS partitions are returned. with open("/proc/filesystems", "r") as f: data = f.read() if 'zfs' in data: for part in psutil.disk_partitions(): if part.fstype == 'zfs': break else: self.fail("couldn't find any ZFS partition") else: # No ZFS partitions on this system. Let's fake one. fake_file = io.StringIO(u("nodev\tzfs\n")) with mock.patch('psutil._pslinux.open', return_value=fake_file, create=True) as m1: with mock.patch( 'psutil._pslinux.cext.disk_partitions', return_value=[('/dev/sdb3', '/', 'zfs', 'rw')]) as m2: ret = psutil.disk_partitions() assert m1.called assert m2.called assert ret self.assertEqual(ret[0].fstype, 'zfs') @mock.patch('psutil._pslinux.socket.inet_ntop', side_effect=ValueError) @mock.patch('psutil._pslinux.supports_ipv6', return_value=False) def test_connections_ipv6_not_supported(self, supports_ipv6, inet_ntop): # see: https://github.com/giampaolo/psutil/issues/623 try: s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) self.addCleanup(s.close) s.bind(("::1", 0)) except socket.error: pass psutil.net_connections(kind='inet6') def test_procfs_path(self): tdir = tempfile.mkdtemp() try: psutil.PROCFS_PATH = tdir self.assertRaises(IOError, psutil.virtual_memory) self.assertRaises(IOError, psutil.cpu_times) self.assertRaises(IOError, psutil.cpu_times, percpu=True) self.assertRaises(IOError, psutil.boot_time) # self.assertRaises(IOError, psutil.pids) self.assertRaises(IOError, psutil.net_connections) self.assertRaises(IOError, psutil.net_io_counters) self.assertRaises(IOError, psutil.net_if_stats) self.assertRaises(IOError, psutil.disk_io_counters) self.assertRaises(IOError, psutil.disk_partitions) self.assertRaises(psutil.NoSuchProcess, psutil.Process) finally: psutil.PROCFS_PATH = "/proc" os.rmdir(tdir) def test_no_procfs_for_import(self): my_procfs = tempfile.mkdtemp() with open(os.path.join(my_procfs, 'stat'), 'w') as f: f.write('cpu 0 0 0 0 0 0 0 0 0 0\n') f.write('cpu0 0 0 0 0 0 0 0 0 0 0\n') f.write('cpu1 0 0 0 0 0 0 0 0 0 0\n') try: orig_open = open def open_mock(name, *args): if name.startswith('/proc'): raise IOError(errno.ENOENT, 'rejecting access for test') return orig_open(name, *args) patch_point = 'builtins.open' if PY3 else '__builtin__.open' with mock.patch(patch_point, side_effect=open_mock): importlib.reload(psutil) self.assertRaises(IOError, psutil.cpu_times) self.assertRaises(IOError, psutil.cpu_times, percpu=True) self.assertRaises(IOError, psutil.cpu_percent) self.assertRaises(IOError, psutil.cpu_percent, percpu=True) self.assertRaises(IOError, psutil.cpu_times_percent) self.assertRaises( IOError, psutil.cpu_times_percent, percpu=True) psutil.PROCFS_PATH = my_procfs self.assertEqual(psutil.cpu_percent(), 0) self.assertEqual(sum(psutil.cpu_times_percent()), 0) # since we don't know the number of CPUs at import time, # we awkwardly say there are none until the second call per_cpu_percent = psutil.cpu_percent(percpu=True) self.assertEqual(sum(per_cpu_percent), 0) # ditto awkward length per_cpu_times_percent = psutil.cpu_times_percent(percpu=True) self.assertEqual(sum(map(sum, per_cpu_times_percent)), 0) # much user, very busy with open(os.path.join(my_procfs, 'stat'), 'w') as f: f.write('cpu 1 0 0 0 0 0 0 0 0 0\n') f.write('cpu0 1 0 0 0 0 0 0 0 0 0\n') f.write('cpu1 1 0 0 0 0 0 0 0 0 0\n') self.assertNotEqual(psutil.cpu_percent(), 0) self.assertNotEqual( sum(psutil.cpu_percent(percpu=True)), 0) self.assertNotEqual(sum(psutil.cpu_times_percent()), 0) self.assertNotEqual( sum(map(sum, psutil.cpu_times_percent(percpu=True))), 0) finally: shutil.rmtree(my_procfs) importlib.reload(psutil) self.assertEqual(psutil.PROCFS_PATH, '/proc') @unittest.skipUnless( get_kernel_version() >= (2, 6, 36), "prlimit() not available on this Linux kernel version") def test_prlimit_availability(self): # prlimit() should be available starting from kernel 2.6.36 p = psutil.Process(os.getpid()) p.rlimit(psutil.RLIMIT_NOFILE) # if prlimit() is supported *at least* these constants should # be available self.assertTrue(hasattr(psutil, "RLIM_INFINITY")) self.assertTrue(hasattr(psutil, "RLIMIT_AS")) self.assertTrue(hasattr(psutil, "RLIMIT_CORE")) self.assertTrue(hasattr(psutil, "RLIMIT_CPU")) self.assertTrue(hasattr(psutil, "RLIMIT_DATA")) self.assertTrue(hasattr(psutil, "RLIMIT_FSIZE")) self.assertTrue(hasattr(psutil, "RLIMIT_LOCKS")) self.assertTrue(hasattr(psutil, "RLIMIT_MEMLOCK")) self.assertTrue(hasattr(psutil, "RLIMIT_NOFILE")) self.assertTrue(hasattr(psutil, "RLIMIT_NPROC")) self.assertTrue(hasattr(psutil, "RLIMIT_RSS")) self.assertTrue(hasattr(psutil, "RLIMIT_STACK")) @unittest.skipUnless( get_kernel_version() >= (3, 0), "prlimit constants not available on this Linux kernel version") def test_resource_consts_kernel_v(self): # more recent constants self.assertTrue(hasattr(psutil, "RLIMIT_MSGQUEUE")) self.assertTrue(hasattr(psutil, "RLIMIT_NICE")) self.assertTrue(hasattr(psutil, "RLIMIT_RTPRIO")) self.assertTrue(hasattr(psutil, "RLIMIT_RTTIME")) self.assertTrue(hasattr(psutil, "RLIMIT_SIGPENDING")) def test_path_deleted(self): with mock.patch('psutil._pslinux.os.readlink', return_value='/home/foo (deleted)'): self.assertEqual(psutil.Process().exe(), "/home/foo") self.assertEqual(psutil.Process().cwd(), "/home/foo") def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_sunos.py0000664000175000017500000000261612612743627017662 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, 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. """Sun OS specific tests. These are implicitly run by test_psutil.py.""" import sys import os import psutil from test_psutil import sh from test_psutil import SUNOS from test_psutil import unittest @unittest.skipUnless(SUNOS, "not a SunOS system") class SunOSSpecificTestCase(unittest.TestCase): def test_swap_memory(self): out = sh('env PATH=/usr/sbin:/sbin:%s swap -l' % os.environ['PATH']) lines = out.strip().split('\n')[1:] if not lines: raise ValueError('no swap device(s) configured') total = free = 0 for line in lines: line = line.split() t, f = line[-2:] total += int(int(t) * 512) free += int(int(f) * 512) used = total - free psutil_swap = psutil.swap_memory() self.assertEqual(psutil_swap.total, total) self.assertEqual(psutil_swap.used, used) self.assertEqual(psutil_swap.free, free) def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(SunOSSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/test_memory_leaks.py0000664000175000017500000003254712625154727022111 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """ A test script which attempts to detect memory leaks by calling C functions many times and compare process memory usage before and after the calls. It might produce false positives. """ import functools import gc import os import socket import sys import threading import time import psutil import psutil._common from psutil._compat import callable from psutil._compat import xrange from test_psutil import FREEBSD from test_psutil import get_test_subprocess from test_psutil import LINUX from test_psutil import OPENBSD from test_psutil import OSX from test_psutil import POSIX from test_psutil import reap_children from test_psutil import RLIMIT_SUPPORT from test_psutil import safe_remove from test_psutil import SUNOS from test_psutil import supports_ipv6 from test_psutil import TESTFN from test_psutil import TRAVIS from test_psutil import WINDOWS if sys.version_info < (2, 7): import unittest2 as unittest # https://pypi.python.org/pypi/unittest2 else: import unittest LOOPS = 1000 MEMORY_TOLERANCE = 4096 SKIP_PYTHON_IMPL = True def skip_if_linux(): return unittest.skipIf(LINUX and SKIP_PYTHON_IMPL, "not worth being tested on LINUX (pure python)") class Base(unittest.TestCase): proc = psutil.Process() def execute(self, function, *args, **kwargs): def call_many_times(): for x in xrange(LOOPS - 1): self.call(function, *args, **kwargs) del x gc.collect() return self.get_mem() self.call(function, *args, **kwargs) self.assertEqual(gc.garbage, []) self.assertEqual(threading.active_count(), 1) # RSS comparison # step 1 rss1 = call_many_times() # step 2 rss2 = call_many_times() difference = rss2 - rss1 if difference > MEMORY_TOLERANCE: # This doesn't necessarily mean we have a leak yet. # At this point we assume that after having called the # function so many times the memory usage is stabilized # and if there are no leaks it should not increase any # more. # Let's keep calling fun for 3 more seconds and fail if # we notice any difference. stop_at = time.time() + 3 while True: self.call(function, *args, **kwargs) if time.time() >= stop_at: break del stop_at gc.collect() rss3 = self.get_mem() difference = rss3 - rss2 if rss3 > rss2: self.fail("rss2=%s, rss3=%s, difference=%s" % (rss2, rss3, difference)) def execute_w_exc(self, exc, function, *args, **kwargs): kwargs['_exc'] = exc self.execute(function, *args, **kwargs) def get_mem(self): return psutil.Process().memory_info()[0] def call(self, function, *args, **kwargs): raise NotImplementedError("must be implemented in subclass") class TestProcessObjectLeaks(Base): """Test leaks of Process class methods and properties""" def setUp(self): gc.collect() def tearDown(self): reap_children() def call(self, function, *args, **kwargs): if callable(function): if '_exc' in kwargs: exc = kwargs.pop('_exc') self.assertRaises(exc, function, *args, **kwargs) else: try: function(*args, **kwargs) except psutil.Error: pass else: meth = getattr(self.proc, function) if '_exc' in kwargs: exc = kwargs.pop('_exc') self.assertRaises(exc, meth, *args, **kwargs) else: try: meth(*args, **kwargs) except psutil.Error: pass @skip_if_linux() def test_name(self): self.execute('name') @skip_if_linux() def test_cmdline(self): self.execute('cmdline') @skip_if_linux() def test_exe(self): self.execute('exe') @skip_if_linux() def test_ppid(self): self.execute('ppid') @unittest.skipUnless(POSIX, "POSIX only") @skip_if_linux() def test_uids(self): self.execute('uids') @unittest.skipUnless(POSIX, "POSIX only") @skip_if_linux() def test_gids(self): self.execute('gids') @skip_if_linux() def test_status(self): self.execute('status') def test_nice_get(self): self.execute('nice') def test_nice_set(self): niceness = psutil.Process().nice() self.execute('nice', niceness) @unittest.skipUnless(hasattr(psutil.Process, 'ionice'), "Linux and Windows Vista only") def test_ionice_get(self): self.execute('ionice') @unittest.skipUnless(hasattr(psutil.Process, 'ionice'), "Linux and Windows Vista only") def test_ionice_set(self): if WINDOWS: value = psutil.Process().ionice() self.execute('ionice', value) else: from psutil._pslinux import cext self.execute('ionice', psutil.IOPRIO_CLASS_NONE) fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0) self.execute_w_exc(OSError, fun) @unittest.skipIf(OSX or SUNOS, "feature not supported on this platform") @skip_if_linux() def test_io_counters(self): self.execute('io_counters') @unittest.skipUnless(WINDOWS, "not worth being tested on posix") def test_username(self): self.execute('username') @skip_if_linux() def test_create_time(self): self.execute('create_time') @skip_if_linux() def test_num_threads(self): self.execute('num_threads') @unittest.skipUnless(WINDOWS, "Windows only") def test_num_handles(self): self.execute('num_handles') @unittest.skipUnless(POSIX, "POSIX only") @skip_if_linux() def test_num_fds(self): self.execute('num_fds') @skip_if_linux() def test_threads(self): self.execute('threads') @skip_if_linux() def test_cpu_times(self): self.execute('cpu_times') @skip_if_linux() def test_memory_info(self): self.execute('memory_info') @skip_if_linux() def test_memory_info_ex(self): self.execute('memory_info_ex') @unittest.skipUnless(POSIX, "POSIX only") @skip_if_linux() def test_terminal(self): self.execute('terminal') @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, "not worth being tested on POSIX (pure python)") def test_resume(self): self.execute('resume') @skip_if_linux() def test_cwd(self): self.execute('cwd') @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, "Windows or Linux or BSD only") def test_cpu_affinity_get(self): self.execute('cpu_affinity') @unittest.skipUnless(WINDOWS or LINUX or FREEBSD, "Windows or Linux or BSD only") def test_cpu_affinity_set(self): affinity = psutil.Process().cpu_affinity() self.execute('cpu_affinity', affinity) if not TRAVIS: self.execute_w_exc(ValueError, 'cpu_affinity', [-1]) @skip_if_linux() def test_open_files(self): safe_remove(TESTFN) # needed after UNIX socket test has run with open(TESTFN, 'w'): self.execute('open_files') # OSX implementation is unbelievably slow @unittest.skipIf(OSX, "OSX implementation is too slow") @unittest.skipIf(OPENBSD, "not implemented on OpenBSD") @skip_if_linux() def test_memory_maps(self): self.execute('memory_maps') @unittest.skipUnless(LINUX, "Linux only") @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_get(self): self.execute('rlimit', psutil.RLIMIT_NOFILE) @unittest.skipUnless(LINUX, "Linux only") @unittest.skipUnless(LINUX and RLIMIT_SUPPORT, "only available on Linux >= 2.6.36") def test_rlimit_set(self): limit = psutil.Process().rlimit(psutil.RLIMIT_NOFILE) self.execute('rlimit', psutil.RLIMIT_NOFILE, limit) self.execute_w_exc(OSError, 'rlimit', -1) @skip_if_linux() # Windows implementation is based on a single system-wide function @unittest.skipIf(WINDOWS, "tested later") def test_connections(self): def create_socket(family, type): sock = socket.socket(family, type) sock.bind(('', 0)) if type == socket.SOCK_STREAM: sock.listen(1) return sock socks = [] socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM)) socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM)) if supports_ipv6(): socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM)) socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM)) if hasattr(socket, 'AF_UNIX'): safe_remove(TESTFN) s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(TESTFN) s.listen(1) socks.append(s) kind = 'all' # TODO: UNIX sockets are temporarily implemented by parsing # 'pfiles' cmd output; we don't want that part of the code to # be executed. if SUNOS: kind = 'inet' try: self.execute('connections', kind=kind) finally: for s in socks: s.close() p = get_test_subprocess() DEAD_PROC = psutil.Process(p.pid) DEAD_PROC.kill() DEAD_PROC.wait() del p class TestProcessObjectLeaksZombie(TestProcessObjectLeaks): """Same as above but looks for leaks occurring when dealing with zombie processes raising NoSuchProcess exception. """ proc = DEAD_PROC def call(self, *args, **kwargs): try: TestProcessObjectLeaks.call(self, *args, **kwargs) except psutil.NoSuchProcess: pass if not POSIX: def test_kill(self): self.execute('kill') def test_terminate(self): self.execute('terminate') def test_suspend(self): self.execute('suspend') def test_resume(self): self.execute('resume') def test_wait(self): self.execute('wait') class TestModuleFunctionsLeaks(Base): """Test leaks of psutil module functions.""" def setUp(self): gc.collect() def call(self, function, *args, **kwargs): fun = getattr(psutil, function) fun(*args, **kwargs) @skip_if_linux() def test_cpu_count_logical(self): self.execute('cpu_count', logical=True) @skip_if_linux() def test_cpu_count_physical(self): self.execute('cpu_count', logical=False) @skip_if_linux() def test_boot_time(self): self.execute('boot_time') @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, "not worth being tested on POSIX (pure python)") def test_pid_exists(self): self.execute('pid_exists', os.getpid()) def test_virtual_memory(self): self.execute('virtual_memory') # TODO: remove this skip when this gets fixed @unittest.skipIf(SUNOS, "not worth being tested on SUNOS (uses a subprocess)") def test_swap_memory(self): self.execute('swap_memory') @skip_if_linux() def test_cpu_times(self): self.execute('cpu_times') @skip_if_linux() def test_per_cpu_times(self): self.execute('cpu_times', percpu=True) @unittest.skipIf(POSIX and SKIP_PYTHON_IMPL, "not worth being tested on POSIX (pure python)") def test_disk_usage(self): self.execute('disk_usage', '.') def test_disk_partitions(self): self.execute('disk_partitions') @skip_if_linux() def test_net_io_counters(self): self.execute('net_io_counters') @unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'), '/proc/diskstats not available on this Linux version') @skip_if_linux() def test_disk_io_counters(self): self.execute('disk_io_counters') # XXX - on Windows this produces a false positive @unittest.skipIf(WINDOWS, "XXX produces a false positive on Windows") def test_users(self): self.execute('users') @unittest.skipIf(LINUX, "not worth being tested on Linux (pure python)") @unittest.skipIf(OSX and os.getuid() != 0, "need root access") def test_net_connections(self): self.execute('net_connections') def test_net_if_addrs(self): self.execute('net_if_addrs') @unittest.skipIf(TRAVIS, "EPERM on travis") def test_net_if_stats(self): self.execute('net_if_stats') def main(): test_suite = unittest.TestSuite() tests = [TestProcessObjectLeaksZombie, TestProcessObjectLeaks, TestModuleFunctionsLeaks] for test in tests: test_suite.addTest(unittest.makeSuite(test)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/test/_windows.py0000664000175000017500000004444312617432563020210 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # -*- coding: UTF-8 -* # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Windows specific tests. These are implicitly run by test_psutil.py.""" import errno import os import platform import signal import subprocess import sys import time import traceback import mock try: import wmi except ImportError: wmi = None try: import win32api import win32con except ImportError: win32api = win32con = None import psutil from psutil._compat import callable from psutil._compat import long from psutil._compat import PY3 from test_psutil import APPVEYOR from test_psutil import get_test_subprocess from test_psutil import reap_children from test_psutil import retry_before_failing from test_psutil import unittest from test_psutil import WINDOWS cext = psutil._psplatform.cext def wrap_exceptions(fun): def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError as err: from psutil._pswindows import ACCESS_DENIED_SET if err.errno in ACCESS_DENIED_SET: raise psutil.AccessDenied(None, None) if err.errno == errno.ESRCH: raise psutil.NoSuchProcess(None, None) raise return wrapper @unittest.skipUnless(WINDOWS, "not a Windows system") class WindowsSpecificTestCase(unittest.TestCase): @classmethod def setUpClass(cls): cls.pid = get_test_subprocess().pid @classmethod def tearDownClass(cls): reap_children() def test_issue_24(self): p = psutil.Process(0) self.assertRaises(psutil.AccessDenied, p.kill) def test_special_pid(self): p = psutil.Process(4) self.assertEqual(p.name(), 'System') # use __str__ to access all common Process properties to check # that nothing strange happens str(p) p.username() self.assertTrue(p.create_time() >= 0.0) try: rss, vms = p.memory_info() except psutil.AccessDenied: # expected on Windows Vista and Windows 7 if not platform.uname()[1] in ('vista', 'win-7', 'win7'): raise else: self.assertTrue(rss > 0) def test_send_signal(self): p = psutil.Process(self.pid) self.assertRaises(ValueError, p.send_signal, signal.SIGINT) def test_nic_names(self): p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE) out = p.communicate()[0] if PY3: out = str(out, sys.stdout.encoding or sys.getfilesystemencoding()) nics = psutil.net_io_counters(pernic=True).keys() for nic in nics: if "pseudo-interface" in nic.replace(' ', '-').lower(): continue if nic not in out: self.fail( "%r nic wasn't found in 'ipconfig /all' output" % nic) def test_exe(self): for p in psutil.process_iter(): try: self.assertEqual(os.path.basename(p.exe()), p.name()) except psutil.Error: pass # --- Process class tests @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_name(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) self.assertEqual(p.name(), w.Caption) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_exe(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) # Note: wmi reports the exe as a lower case string. # Being Windows paths case-insensitive we ignore that. self.assertEqual(p.exe().lower(), w.ExecutablePath.lower()) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_cmdline(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) self.assertEqual(' '.join(p.cmdline()), w.CommandLine.replace('"', '')) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_username(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) domain, _, username = w.GetOwner() username = "%s\\%s" % (domain, username) self.assertEqual(p.username(), username) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_rss_memory(self): time.sleep(0.1) w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) rss = p.memory_info().rss self.assertEqual(rss, int(w.WorkingSetSize)) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_vms_memory(self): time.sleep(0.1) w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) vms = p.memory_info().vms # http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx # ...claims that PageFileUsage is represented in Kilo # bytes but funnily enough on certain platforms bytes are # returned instead. wmi_usage = int(w.PageFileUsage) if (vms != wmi_usage) and (vms != wmi_usage * 1024): self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms)) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_process_create_time(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) wmic_create = str(w.CreationDate.split('.')[0]) psutil_create = time.strftime("%Y%m%d%H%M%S", time.localtime(p.create_time())) self.assertEqual(wmic_create, psutil_create) # --- psutil namespace functions and constants tests @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ, 'NUMBER_OF_PROCESSORS env var is not available') def test_cpu_count(self): num_cpus = int(os.environ['NUMBER_OF_PROCESSORS']) self.assertEqual(num_cpus, psutil.cpu_count()) @unittest.skipIf(wmi is None, "wmi module is not installed") def test_total_phymem(self): w = wmi.WMI().Win32_ComputerSystem()[0] self.assertEqual(int(w.TotalPhysicalMemory), psutil.virtual_memory().total) # @unittest.skipIf(wmi is None, "wmi module is not installed") # def test__UPTIME(self): # # _UPTIME constant is not public but it is used internally # # as value to return for pid 0 creation time. # # WMI behaves the same. # w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] # p = psutil.Process(0) # wmic_create = str(w.CreationDate.split('.')[0]) # psutil_create = time.strftime("%Y%m%d%H%M%S", # time.localtime(p.create_time())) # # Note: this test is not very reliable @unittest.skipIf(wmi is None, "wmi module is not installed") @unittest.skipIf(APPVEYOR, "test not relieable on appveyor") def test_pids(self): # Note: this test might fail if the OS is starting/killing # other processes in the meantime w = wmi.WMI().Win32_Process() wmi_pids = set([x.ProcessId for x in w]) psutil_pids = set(psutil.pids()) self.assertEqual(wmi_pids, psutil_pids) @unittest.skipIf(wmi is None, "wmi module is not installed") @retry_before_failing() def test_disks(self): ps_parts = psutil.disk_partitions(all=True) wmi_parts = wmi.WMI().Win32_LogicalDisk() for ps_part in ps_parts: for wmi_part in wmi_parts: if ps_part.device.replace('\\', '') == wmi_part.DeviceID: if not ps_part.mountpoint: # this is usually a CD-ROM with no disk inserted break try: usage = psutil.disk_usage(ps_part.mountpoint) except OSError as err: if err.errno == errno.ENOENT: # usually this is the floppy break else: raise self.assertEqual(usage.total, int(wmi_part.Size)) wmi_free = int(wmi_part.FreeSpace) self.assertEqual(usage.free, wmi_free) # 10 MB tollerance if abs(usage.free - wmi_free) > 10 * 1024 * 1024: self.fail("psutil=%s, wmi=%s" % ( usage.free, wmi_free)) break else: self.fail("can't find partition %s" % repr(ps_part)) @unittest.skipIf(win32api is None, "pywin32 module is not installed") def test_num_handles(self): p = psutil.Process(os.getpid()) before = p.num_handles() handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, os.getpid()) after = p.num_handles() self.assertEqual(after, before + 1) win32api.CloseHandle(handle) self.assertEqual(p.num_handles(), before) @unittest.skipIf(win32api is None, "pywin32 module is not installed") def test_num_handles_2(self): # Note: this fails from time to time; I'm keen on thinking # it doesn't mean something is broken def call(p, attr): attr = getattr(p, name, None) if attr is not None and callable(attr): attr() else: attr p = psutil.Process(self.pid) failures = [] for name in dir(psutil.Process): if name.startswith('_') \ or name in ('terminate', 'kill', 'suspend', 'resume', 'nice', 'send_signal', 'wait', 'children', 'as_dict'): continue else: try: call(p, name) num1 = p.num_handles() call(p, name) num2 = p.num_handles() except (psutil.NoSuchProcess, psutil.AccessDenied): pass else: if num2 > num1: fail = \ "failure while processing Process.%s method " \ "(before=%s, after=%s)" % (name, num1, num2) failures.append(fail) if failures: self.fail('\n' + '\n'.join(failures)) def test_name_always_available(self): # On Windows name() is never supposed to raise AccessDenied, # see https://github.com/giampaolo/psutil/issues/627 for p in psutil.process_iter(): try: p.name() except psutil.NoSuchProcess: pass @unittest.skipUnless(sys.version_info >= (2, 7), "CTRL_* signals not supported") def test_ctrl_signals(self): p = psutil.Process(get_test_subprocess().pid) p.send_signal(signal.CTRL_C_EVENT) p.send_signal(signal.CTRL_BREAK_EVENT) p.kill() p.wait() self.assertRaises(psutil.NoSuchProcess, p.send_signal, signal.CTRL_C_EVENT) self.assertRaises(psutil.NoSuchProcess, p.send_signal, signal.CTRL_BREAK_EVENT) @unittest.skipUnless(WINDOWS, "not a Windows system") class TestDualProcessImplementation(unittest.TestCase): """ Certain APIs on Windows have 2 internal implementations, one based on documented Windows APIs, another one based NtQuerySystemInformation() which gets called as fallback in case the first fails because of limited permission error. Here we test that the two methods return the exact same value, see: https://github.com/giampaolo/psutil/issues/304 """ fun_names = [ # function name, tolerance ('proc_cpu_times', 0.2), ('proc_create_time', 0.5), ('proc_num_handles', 1), # 1 because impl #1 opens a handle ('proc_memory_info', 1024), # KB ('proc_io_counters', 0), ] def test_compare_values(self): def assert_ge_0(obj): if isinstance(obj, tuple): for value in obj: self.assertGreaterEqual(value, 0, msg=obj) elif isinstance(obj, (int, long, float)): self.assertGreaterEqual(obj, 0) else: assert 0 # case not handled which needs to be fixed def compare_with_tolerance(ret1, ret2, tolerance): if ret1 == ret2: return else: if isinstance(ret2, (int, long, float)): diff = abs(ret1 - ret2) self.assertLessEqual(diff, tolerance) elif isinstance(ret2, tuple): for a, b in zip(ret1, ret2): diff = abs(a - b) self.assertLessEqual(diff, tolerance) from psutil._pswindows import ntpinfo failures = [] for p in psutil.process_iter(): try: nt = ntpinfo(*cext.proc_info(p.pid)) except psutil.NoSuchProcess: continue assert_ge_0(nt) for name, tolerance in self.fun_names: if name == 'proc_memory_info' and p.pid == os.getpid(): continue if name == 'proc_create_time' and p.pid in (0, 4): continue meth = wrap_exceptions(getattr(cext, name)) try: ret = meth(p.pid) except (psutil.NoSuchProcess, psutil.AccessDenied): continue # compare values try: if name == 'proc_cpu_times': compare_with_tolerance(ret[0], nt.user_time, tolerance) compare_with_tolerance(ret[1], nt.kernel_time, tolerance) elif name == 'proc_create_time': compare_with_tolerance(ret, nt.create_time, tolerance) elif name == 'proc_num_handles': compare_with_tolerance(ret, nt.num_handles, tolerance) elif name == 'proc_io_counters': compare_with_tolerance(ret[0], nt.io_rcount, tolerance) compare_with_tolerance(ret[1], nt.io_wcount, tolerance) compare_with_tolerance(ret[2], nt.io_rbytes, tolerance) compare_with_tolerance(ret[3], nt.io_wbytes, tolerance) elif name == 'proc_memory_info': try: rawtupl = cext.proc_memory_info_2(p.pid) except psutil.NoSuchProcess: continue compare_with_tolerance(ret, rawtupl, tolerance) except AssertionError: trace = traceback.format_exc() msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % ( trace, p.pid, name, ret, nt) failures.append(msg) break if failures: self.fail('\n\n'.join(failures)) # --- # same tests as above but mimicks the AccessDenied failure of # the first (fast) method failing with AD. # TODO: currently does not take tolerance into account. def test_name(self): name = psutil.Process().name() with mock.patch("psutil._psplatform.cext.proc_exe", side_effect=psutil.AccessDenied(os.getpid())) as fun: psutil.Process().name() == name assert fun.called def test_memory_info(self): mem = psutil.Process().memory_info() with mock.patch("psutil._psplatform.cext.proc_memory_info", side_effect=OSError(errno.EPERM, "msg")) as fun: psutil.Process().memory_info() == mem assert fun.called def test_create_time(self): ctime = psutil.Process().create_time() with mock.patch("psutil._psplatform.cext.proc_create_time", side_effect=OSError(errno.EPERM, "msg")) as fun: psutil.Process().create_time() == ctime assert fun.called def test_cpu_times(self): cpu_times = psutil.Process().cpu_times() with mock.patch("psutil._psplatform.cext.proc_cpu_times", side_effect=OSError(errno.EPERM, "msg")) as fun: psutil.Process().cpu_times() == cpu_times assert fun.called def test_io_counters(self): io_counters = psutil.Process().io_counters() with mock.patch("psutil._psplatform.cext.proc_io_counters", side_effect=OSError(errno.EPERM, "msg")) as fun: psutil.Process().io_counters() == io_counters assert fun.called def test_num_handles(self): io_counters = psutil.Process().io_counters() with mock.patch("psutil._psplatform.cext.proc_io_counters", side_effect=OSError(errno.EPERM, "msg")) as fun: psutil.Process().io_counters() == io_counters assert fun.called # --- other tests def test_compare_name_exe(self): for p in psutil.process_iter(): try: a = os.path.basename(p.exe()) b = p.name() except (psutil.NoSuchProcess, psutil.AccessDenied): pass else: self.assertEqual(a, b) def test_zombies(self): # test that NPS is raised by the 2nd implementation in case a # process no longer exists ZOMBIE_PID = max(psutil.pids()) + 5000 for name, _ in self.fun_names: meth = wrap_exceptions(getattr(cext, name)) self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID) def main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase)) test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not main(): sys.exit(1) psutil-3.4.2/Makefile0000664000175000017500000000701412572074510016451 0ustar giampaologiampaolo00000000000000# Shortcuts for various tasks (UNIX only). # To use a specific Python version run: # $ make install PYTHON=python3.3 # You can set these variables from the command line. PYTHON = python TSCRIPT = test/test_psutil.py all: test clean: rm -f `find . -type f -name \*.py[co]` rm -f `find . -type f -name \*.so` rm -f `find . -type f -name .\*~` rm -f `find . -type f -name \*.orig` rm -f `find . -type f -name \*.bak` rm -f `find . -type f -name \*.rej` rm -rf `find . -type d -name __pycache__` rm -rf *.core rm -rf *.egg-info rm -rf *\$testfile* rm -rf .coverage rm -rf .tox rm -rf build rm -rf dist rm -rf docs/_build rm -rf htmlcov build: clean $(PYTHON) setup.py build @# copies *.so files in ./psutil directory in order to allow @# "import psutil" when using the interactive interpreter from within @# this directory. $(PYTHON) setup.py build_ext -i # useful deps which are nice to have while developing / testing setup-dev-env: install-git-hooks python -c "import urllib2, ssl; \ context = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \ kw = dict(context=context) if context else {}; \ r = urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py', **kw); \ open('/tmp/get-pip.py', 'w').write(r.read());" $(PYTHON) /tmp/get-pip.py --user rm /tmp/get-pip.py $(PYTHON) -m pip install --user --upgrade pip $(PYTHON) -m pip install --user --upgrade \ coverage \ flake8 \ ipaddress \ ipdb \ mock==1.0.1 \ nose \ pep8 \ pyflakes \ sphinx \ sphinx-pypi-upload \ unittest2 \ install: build $(PYTHON) setup.py install --user uninstall: cd ..; $(PYTHON) -m pip uninstall -y -v psutil test: install $(PYTHON) $(TSCRIPT) test-process: install $(PYTHON) -m unittest -v test.test_psutil.TestProcess test-system: install $(PYTHON) -m unittest -v test.test_psutil.TestSystemAPIs test-memleaks: install $(PYTHON) test/test_memory_leaks.py # Run a specific test by name; e.g. "make test-by-name disk_" will run # all test methods containing "disk_" in their name. # Requires "pip install nose". test-by-name: install @$(PYTHON) -m nose test/test_psutil.py test/_* --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS)) # Same as above but for test_memory_leaks.py script. test-memleaks-by-name: install @$(PYTHON) -m nose test/test_memory_leaks.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS)) coverage: install # Note: coverage options are controlled by .coveragerc file rm -rf .coverage htmlcov $(PYTHON) -m coverage run $(TSCRIPT) $(PYTHON) -m coverage report @echo "writing results to htmlcov/index.html" $(PYTHON) -m coverage html $(PYTHON) -m webbrowser -t htmlcov/index.html pep8: @git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8 pyflakes: @export PYFLAKES_NODOCTEST=1 && \ git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes flake8: @git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8 # Upload source tarball on https://pypi.python.org/pypi/psutil. upload-src: clean $(PYTHON) setup.py sdist upload # Build and upload doc on https://pythonhosted.org/psutil/. # Requires "pip install sphinx-pypi-upload". upload-doc: cd docs; make html $(PYTHON) setup.py upload_sphinx --upload-dir=docs/_build/html # git-tag a new release git-tag-release: git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD` git push --follow-tags # install GIT pre-commit hook install-git-hooks: ln -sf ../../.git-pre-commit .git/hooks/pre-commit chmod +x .git/hooks/pre-commit psutil-3.4.2/docs/0000775000175000017500000000000012647732502015744 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/README0000664000175000017500000000060412572074510016617 0ustar giampaologiampaolo00000000000000About ===== This directory contains the reStructuredText (reST) sources to the psutil documentation. You don't need to build them yourself, prebuilt versions are available at https://pythonhosted.org/psutil/. In case you want, you need to install sphinx first: $ pip install sphinx Then run: $ make html You'll then have an HTML version of the doc at _build/html/index.html.psutil-3.4.2/docs/_themes/0000775000175000017500000000000012647732502017370 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/_themes/pydoctheme/0000775000175000017500000000000012647732502021531 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/_themes/pydoctheme/static/0000775000175000017500000000000012647732502023020 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/_themes/pydoctheme/static/pydoctheme.css0000664000175000017500000000553512572074510025676 0ustar giampaologiampaolo00000000000000@import url("default.css"); body { background-color: white; margin-left: 1em; margin-right: 1em; } div.related { margin-bottom: 1.2em; padding: 0.5em 0; border-top: 1px solid #ccc; margin-top: 0.5em; } div.related a:hover { color: #0095C4; } div.related:first-child { border-top: 0; padding-top: 0; border-bottom: 1px solid #ccc; } div.sphinxsidebar { background-color: #eeeeee; border-radius: 5px; line-height: 130%; font-size: smaller; } div.sphinxsidebar h3, div.sphinxsidebar h4 { margin-top: 1.5em; } div.sphinxsidebarwrapper > h3:first-child { margin-top: 0.2em; } div.sphinxsidebarwrapper > ul > li > ul > li { margin-bottom: 0.4em; } div.sphinxsidebar a:hover { color: #0095C4; } div.sphinxsidebar input { font-family: 'Lucida Grande','Lucida Sans','DejaVu Sans',Arial,sans-serif; border: 1px solid #999999; font-size: smaller; border-radius: 3px; } div.sphinxsidebar input[type=text] { max-width: 150px; } div.body { padding: 0 0 0 1.2em; } div.body p { line-height: 140%; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { margin: 0; border: 0; padding: 0.3em 0; } div.body hr { border: 0; background-color: #ccc; height: 1px; } div.body pre { border-radius: 3px; border: 1px solid #ac9; } div.body div.admonition, div.body div.impl-detail { border-radius: 3px; } div.body div.impl-detail > p { margin: 0; } div.body div.seealso { border: 1px solid #dddd66; } div.body a { color: #00608f; } div.body a:visited { color: #30306f; } div.body a:hover { color: #00B0E4; } tt, pre { font-family: monospace, sans-serif; font-size: 96.5%; } div.body tt { border-radius: 3px; } div.body tt.descname { font-size: 120%; } div.body tt.xref, div.body a tt { font-weight: normal; } p.deprecated { border-radius: 3px; } table.docutils { border: 1px solid #ddd; min-width: 20%; border-radius: 3px; margin-top: 10px; margin-bottom: 10px; } table.docutils td, table.docutils th { border: 1px solid #ddd !important; border-radius: 3px; } table p, table li { text-align: left !important; } table.docutils th { background-color: #eee; padding: 0.3em 0.5em; } table.docutils td { background-color: white; padding: 0.3em 0.5em; } table.footnote, table.footnote td { border: 0 !important; } div.footer { line-height: 150%; margin-top: -2em; text-align: right; width: auto; margin-right: 10px; } div.footer a:hover { color: #0095C4; } div.body h1, div.body h2, div.body h3 { background-color: #EAEAEA; border-bottom: 1px solid #CCC; padding-top: 2px; padding-bottom: 2px; padding-left: 5px; margin-top: 5px; margin-bottom: 5px; } div.body h2 { padding-left:10px; } psutil-3.4.2/docs/_themes/pydoctheme/theme.conf0000664000175000017500000000111712572074510023475 0ustar giampaologiampaolo00000000000000[theme] inherit = default stylesheet = pydoctheme.css pygments_style = sphinx [options] bodyfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif headfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif footerbgcolor = white footertextcolor = #555555 relbarbgcolor = white relbartextcolor = #666666 relbarlinkcolor = #444444 sidebarbgcolor = white sidebartextcolor = #444444 sidebarlinkcolor = #444444 bgcolor = white textcolor = #222222 linkcolor = #0090c0 visitedlinkcolor = #00608f headtextcolor = #1a1a1a headbgcolor = white headlinkcolor = #aaaaaa psutil-3.4.2/docs/_template/0000775000175000017500000000000012647732502017716 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/_template/indexsidebar.html0000664000175000017500000000066712572074510023251 0ustar giampaologiampaolo00000000000000

Useful links

psutil-3.4.2/docs/_template/indexcontent.html0000664000175000017500000000010112572074510023271 0ustar giampaologiampaolo00000000000000{% extends "defindex.html" %} {% block tables %} {% endblock %} psutil-3.4.2/docs/_template/page.html0000664000175000017500000000440512572074510021516 0ustar giampaologiampaolo00000000000000{% extends "!page.html" %} {% block extrahead %} {{ super() }} {% if not embedded %}{% endif %} {% endblock %} {% block rootrellink %}
  • Project Homepage{{ reldelim1 }}
  • {{ shorttitle }}{{ reldelim1 }}
  • {% endblock %} {% block footer %} {% endblock %}psutil-3.4.2/docs/_template/globaltoc.html0000664000175000017500000000050412572074510022544 0ustar giampaologiampaolo00000000000000{# basic/globaltoc.html ~~~~~~~~~~~~~~~~~~~~ Sphinx sidebar template: global table of contents. :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #}

    {{ _('Manual') }}

    {{ toctree() }} Back to Welcome psutil-3.4.2/docs/make.bat0000664000175000017500000001447312572074510017355 0ustar giampaologiampaolo00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\psutil.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\psutil.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end psutil-3.4.2/docs/Makefile0000664000175000017500000001515012572074510017401 0ustar giampaologiampaolo00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR) html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/psutil.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/psutil.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/psutil" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/psutil" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." psutil-3.4.2/docs/index.rst0000664000175000017500000016347612647732362017632 0ustar giampaologiampaolo00000000000000.. module:: psutil :synopsis: psutil module .. moduleauthor:: Giampaolo Rodola' .. note:: This documentation refers to new 3.X version of psutil. Instructions on how to port existing 1.2.1 code are `here `__. Old 1.2.1 documentation is still available `here `__. .. versionchanged:: 3.3.0 added support for OpenBSD .. versionchanged:: 3.4.1 added support for NetBSD psutil documentation ==================== Quick links ----------- * `Home page `__ * `Blog `__ * `Forum `__ * `Download `__ * `Installation `_ * `Development guide `_ * `What's new `__ About ----- From project's home page: psutil (python system and process utilities) is a cross-platform library for retrieving information on running **processes** and **system utilization** (CPU, memory, disks, network) in **Python**. It is useful mainly for **system monitoring**, **profiling** and **limiting process resources** and **management of running processes**. It implements many functionalities offered by command line tools such as: *ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap*. It currently supports **Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD** and **NetBSD**, both **32-bit** and **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of Python 2.4 and 2.5 may use `2.1.3 `__ version). `PyPy `__ is also known to work. The psutil documentation you're reading is distributed as a single HTML page. System related functions ======================== CPU --- .. function:: cpu_times(percpu=False) Return system CPU times as a namedtuple. Every attribute represents the seconds the CPU has spent in the given mode. The attributes availability varies depending on the platform: - **user** - **system** - **idle** - **nice** *(UNIX)* - **iowait** *(Linux)* - **irq** *(Linux, BSD)* - **softirq** *(Linux)* - **steal** *(Linux 2.6.11+)* - **guest** *(Linux 2.6.24+)* - **guest_nice** *(Linux 3.2.0+)* When *percpu* is ``True`` return a list of namedtuples for each logical CPU on the system. 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. Example output on Linux: >>> import psutil >>> psutil.cpu_times() scputimes(user=17411.7, nice=77.99, system=3797.02, idle=51266.57, iowait=732.58, irq=0.01, softirq=142.43, steal=0.0, guest=0.0, guest_nice=0.0) .. function:: cpu_percent(interval=None, 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. That means the first time this is called it will return a meaningless ``0.0`` value which you are supposed to ignore. 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. >>> import psutil >>> # blocking >>> psutil.cpu_percent(interval=1) 2.0 >>> # non-blocking (percentage since last call) >>> psutil.cpu_percent(interval=None) 2.9 >>> # blocking, per-cpu >>> psutil.cpu_percent(interval=1, percpu=True) [2.0, 1.0] >>> .. warning:: the first time this function is called with *interval* = ``0.0`` or ``None`` it will return a meaningless ``0.0`` value which you are supposed to ignore. .. function:: cpu_times_percent(interval=None, percpu=False) Same as :func:`cpu_percent()` but provides utilization percentages for each specific CPU time as is returned by :func:`psutil.cpu_times(percpu=True)`. *interval* and *percpu* arguments have the same meaning as in :func:`cpu_percent()`. .. warning:: the first time this function is called with *interval* = ``0.0`` or ``None`` it will return a meaningless ``0.0`` value which you are supposed to ignore. .. function:: cpu_count(logical=True) Return the number of logical CPUs in the system (same as `os.cpu_count() `__ in Python 3.4). If *logical* is ``False`` return the number of physical cores only (hyper thread CPUs are excluded). Return ``None`` if undetermined. >>> import psutil >>> psutil.cpu_count() 4 >>> psutil.cpu_count(logical=False) 2 >>> Memory ------ .. function:: 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. - **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**: (Linux, BSD): cache for things like file system metadata. - **cached**: (Linux, BSD): cache for various things. - **wired**: (BSD, OSX): 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. See `examples/meminfo.py `__ script providing an example on how to convert bytes in a human readable form. >>> import psutil >>> mem = psutil.virtual_memory() >>> mem svmem(total=8374149120L, available=1247768576L, percent=85.1, used=8246628352L, free=127520768L, active=3208777728, inactive=1133408256, buffers=342413312L, cached=777834496) >>> >>> THRESHOLD = 100 * 1024 * 1024 # 100MB >>> if mem.available <= THRESHOLD: ... print("warning") ... >>> .. function:: swap_memory() Return system swap memory statistics as a namedtuple including the following fields: * **total**: total swap memory in bytes * **used**: used swap memory in bytes * **free**: free swap memory in bytes * **percent**: the percentage usage calculated as ``(total - available) / total * 100`` * **sin**: the number of bytes the system has swapped in from disk (cumulative) * **sout**: the number of bytes the system has swapped out from disk (cumulative) **sin** and **sout** on Windows are always set to ``0``. See `examples/meminfo.py `__ script providing an example on how to convert bytes in a human readable form. >>> import psutil >>> psutil.swap_memory() sswap(total=2097147904L, used=886620160L, free=1210527744L, percent=42.3, sin=1050411008, sout=1906720768) Disks ----- .. function:: disk_partitions(all=False) Return all mounted disk partitions as a list of namedtuples including device, mount point and filesystem type, similarly to "df" command on UNIX. If *all* parameter is ``False`` return physical devices only (e.g. hard disks, cd-rom drives, USB keys) and ignore all others (e.g. memory partitions such as `/dev/shm `__). Namedtuple's **fstype** field is a string which varies depending on the platform. On Linux it can be one of the values found in /proc/filesystems (e.g. ``'ext3'`` for an ext3 hard drive o ``'iso9660'`` for the CD-ROM drive). On Windows it is determined via `GetDriveType `__ and can be either ``"removable"``, ``"fixed"``, ``"remote"``, ``"cdrom"``, ``"unmounted"`` or ``"ramdisk"``. On OSX and BSD it is retrieved via `getfsstat(2) `__. See `disk_usage.py `__ script providing an example usage. >>> import psutil >>> psutil.disk_partitions() [sdiskpart(device='/dev/sda3', mountpoint='/', fstype='ext4', opts='rw,errors=remount-ro'), sdiskpart(device='/dev/sda7', mountpoint='/home', fstype='ext4', opts='rw')] .. function:: 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. `OSError `__ is raised if *path* does not exist. See `examples/disk_usage.py `__ script providing an example usage. Starting from `Python 3.3 `__ this is also available as `shutil.disk_usage() `__. See `disk_usage.py `__ script providing an example usage. >>> import psutil >>> psutil.disk_usage('/') sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) .. function:: disk_io_counters(perdisk=False) Return system-wide disk I/O statistics as a namedtuple including the following fields: - **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 namedtuple described above as the values. See `examples/iotop.py `__ for an example application. >>> import psutil >>> psutil.disk_io_counters() sdiskio(read_count=8141, write_count=2431, read_bytes=290203, write_bytes=537676, read_time=5868, write_time=94922) >>> >>> psutil.disk_io_counters(perdisk=True) {'sda1': sdiskio(read_count=920, write_count=1, read_bytes=2933248, write_bytes=512, read_time=6016, write_time=4), 'sda2': sdiskio(read_count=18707, write_count=8830, read_bytes=6060, write_bytes=3443, read_time=24585, write_time=1572), 'sdb1': sdiskio(read_count=161, write_count=0, read_bytes=786432, write_bytes=0, read_time=44, write_time=0)} Network ------- .. function:: net_io_counters(pernic=False) Return system-wide 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. See `examples/nettop.py `__ for an example application. >>> import psutil >>> psutil.net_io_counters() snetio(bytes_sent=14508483, bytes_recv=62749361, packets_sent=84311, packets_recv=94888, errin=0, errout=0, dropin=0, dropout=0) >>> >>> psutil.net_io_counters(pernic=True) {'lo': snetio(bytes_sent=547971, bytes_recv=547971, packets_sent=5075, packets_recv=5075, errin=0, errout=0, dropin=0, dropout=0), 'wlan0': snetio(bytes_sent=13921765, bytes_recv=62162574, packets_sent=79097, packets_recv=89648, errin=0, errout=0, dropin=0, dropout=0)} .. function:: net_connections(kind='inet') Return system-wide socket connections as a list of namedtuples. Every namedtuple provides 7 attributes: - **fd**: the socket file descriptor, if retrievable, else ``-1``. If the connection refers to the current process this may be passed to `socket.fromfd() `__ to obtain a usable socket object. - **family**: the address family, either `AF_INET `__, `AF_INET6 `__ or `AF_UNIX `__. - **type**: the address type, either `SOCK_STREAM `__ or `SOCK_DGRAM `__. - **laddr**: the local address as a ``(ip, port)`` tuple or a ``path`` in case of AF_UNIX sockets. - **raddr**: the remote address as a ``(ip, port)`` tuple or an absolute ``path`` in case of UNIX sockets. When the remote endpoint is not connected you'll get an empty tuple (AF_INET*) or ``None`` (AF_UNIX). On Linux AF_UNIX sockets will always have this set to ``None``. - **status**: represents the status of a TCP connection. The return value is one of the :data:`psutil.CONN_* ` constants (a string). For UDP and UNIX sockets this is always going to be :const:`psutil.CONN_NONE`. - **pid**: the PID of the process which opened the socket, if retrievable, else ``None``. On some platforms (e.g. Linux) the availability of this field changes depending on process privileges (root is needed). The *kind* parameter is a string which filters for connections that fit the following criteria: .. table:: +----------------+-----------------------------------------------------+ | **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 | +----------------+-----------------------------------------------------+ On OSX this function requires root privileges. To get per-process connections use :meth:`Process.connections`. Also, see `netstat.py sample script `__. Example: >>> import psutil >>> psutil.net_connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] .. note:: (OSX) :class:`psutil.AccessDenied` is always raised unless running as root (lsof does the same). .. note:: (Solaris) UNIX sockets are not supported. .. versionadded:: 2.1.0 .. function:: net_if_addrs() Return the addresses associated to each NIC (network interface card) installed on the system as a dictionary whose keys are the NIC names and value is a list of namedtuples for each address assigned to the NIC. Each namedtuple includes 5 fields: - **family** - **address** - **netmask** - **broadcast** - **ptp** *family* can be either `AF_INET `__, `AF_INET6 `__ or :const:`psutil.AF_LINK`, which refers to a MAC address. *address* is the primary address and it is always set. *netmask*, *broadcast* and *ptp* may be ``None``. *ptp* stands for "point to point" and references the destination address on a point to point interface (tipically a VPN). *broadcast* and *ptp* are mutually exclusive. *netmask*, *broadcast* and *ptp* are not supported on Windows and are set to ``None``. Example:: >>> import psutil >>> psutil.net_if_addrs() {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None), snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None), snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)], 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None), snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None), snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]} >>> See also `examples/ifconfig.py `__ for an example application. .. note:: if you're interested in others families (e.g. AF_BLUETOOTH) you can use the more powerful `netifaces `__ extension. .. note:: you can have more than one address of the same family associated with each interface (that's why dict values are lists). .. note:: *netmask*, *broadcast* and *ptp* are not supported on Windows and are set to ``None``. .. versionadded:: 3.0.0 .. versionchanged:: 3.2.0 *ptp* field was added. .. function:: net_if_stats() Return information about each NIC (network interface card) installed on the system as a dictionary whose keys are the NIC names and value is a namedtuple with the following fields: - **isup** - **duplex** - **speed** - **mtu** *isup* is a boolean indicating whether the NIC is up and running, *duplex* can be either :const:`NIC_DUPLEX_FULL`, :const:`NIC_DUPLEX_HALF` or :const:`NIC_DUPLEX_UNKNOWN`, *speed* is the NIC speed expressed in mega bits (MB), if it can't be determined (e.g. 'localhost') it will be set to ``0``, *mtu* is the maximum transmission unit expressed in bytes. See also `examples/ifconfig.py `__ for an example application. Example: >>> import psutil >>> psutil.net_if_stats() {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} .. versionadded:: 3.0.0 Other system info ----------------- .. function:: boot_time() Return the system boot time expressed in seconds since the epoch. Example: .. code-block:: python >>> import psutil, datetime >>> psutil.boot_time() 1389563460.0 >>> datetime.datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S") '2014-01-12 22:51:00' .. function:: users() Return users currently connected on the system as a list of namedtuples including the following fields: - **user**: the name of the user. - **terminal**: the tty or pseudo-tty associated with the user, if any, else ``None``. - **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. Example:: >>> import psutil >>> psutil.users() [suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] Processes ========= Functions --------- .. function:: pids() Return a list of current running PIDs. To iterate over all processes :func:`process_iter()` should be preferred. .. function:: pid_exists(pid) Check whether the given PID exists in the current process list. This is faster than doing ``"pid in psutil.pids()"`` and should be preferred. .. function:: process_iter() Return an iterator yielding a :class:`Process` class instance for all running processes on the local machine. Every instance is only created once and then cached into an internal table which is updated every time an element is yielded. Cached :class:`Process` instances are checked for identity so that you're safe in case a PID has been reused by another process, in which case the cached instance is updated. This is should be preferred over :func:`psutil.pids()` for iterating over processes. Sorting order in which processes are returned is based on their PID. Example usage:: import psutil for proc in psutil.process_iter(): try: pinfo = proc.as_dict(attrs=['pid', 'name']) except psutil.NoSuchProcess: pass else: print(pinfo) .. function:: wait_procs(procs, timeout=None, callback=None) Convenience function which waits for a list of :class:`Process` instances to terminate. Return a ``(gone, alive)`` tuple indicating which processes are gone and which ones are still alive. The *gone* ones will have a new *returncode* attribute indicating process exit status (it may be ``None``). ``callback`` is a function which gets called every time a process terminates (a :class:`Process` instance is passed as callback argument). Function will return as soon as all processes terminate or when timeout occurs. Tipical use case is: - send SIGTERM to a list of processes - give them some time to terminate - send SIGKILL to those ones which are still alive Example:: import psutil def on_terminate(proc): print("process {} terminated with exit code {}".format(proc, proc.returncode)) procs = [...] # a list of Process instances for p in procs: p.terminate() gone, alive = wait_procs(procs, timeout=3, callback=on_terminate) for p in alive: p.kill() Exceptions ---------- .. class:: Error() Base exception class. All other exceptions inherit from this one. .. class:: NoSuchProcess(pid, name=None, msg=None) Raised by :class:`Process` class methods when no process with the given *pid* is found in the current process list or when a process no longer exists. "name" is the name the process had before disappearing and gets set only if :meth:`Process.name()` was previosly called. .. class:: ZombieProcess(pid, name=None, ppid=None, msg=None) This may be raised by :class:`Process` class methods when querying a zombie process on UNIX (Windows doesn't have zombie processes). Depending on the method called the OS may be able to succeed in retrieving the process information or not. Note: this is a subclass of :class:`NoSuchProcess` so if you're not interested in retrieving zombies (e.g. when using :func:`process_iter()`) you can ignore this exception and just catch :class:`NoSuchProcess`. .. versionadded:: 3.0.0 .. class:: AccessDenied(pid=None, name=None, msg=None) Raised by :class:`Process` class methods when permission to perform an action is denied. "name" is the name of the process (may be ``None``). .. class:: TimeoutExpired(seconds, pid=None, name=None, msg=None) Raised by :meth:`Process.wait` if timeout expires and process is still alive. Process class ------------- .. class:: Process(pid=None) Represents an OS process with the given *pid*. If *pid* is omitted current process *pid* (`os.getpid() `__) is used. Raise :class:`NoSuchProcess` if *pid* does not exist. When accessing methods of this class always be prepared to catch :class:`NoSuchProcess`, :class:`ZombieProcess` and :class:`AccessDenied` exceptions. `hash() `__ builtin can be used against instances of this class in order to identify a process univocally over time (the hash is determined by mixing process PID and creation time). As such it can also be used with `set()s `__. .. warning:: the way this class is bound to a process is via its **PID**. That means that if the :class:`Process` instance is old enough and the PID has been reused in the meantime you might end up interacting with another process. The only exceptions for which process identity is pre-emptively checked (via PID + creation time) and guaranteed are for :meth:`nice` (set), :meth:`ionice` (set), :meth:`cpu_affinity` (set), :meth:`rlimit` (set), :meth:`children`, :meth:`parent`, :meth:`suspend` :meth:`resume`, :meth:`send_signal`, :meth:`terminate`, and :meth:`kill` methods. To prevent this problem for all other methods you can use :meth:`is_running()` before querying the process or use :func:`process_iter()` in case you're iterating over all processes. .. attribute:: pid The process PID. .. method:: ppid() The process parent pid. On Windows the return value is cached after first call. .. method:: name() The process name. .. method:: exe() The process executable as an absolute path. On some systems this may also be an empty string. The return value is cached after first call. .. method:: cmdline() The command line this process has been called with. .. method:: create_time() The process creation time as a floating point number expressed in seconds since the epoch, in `UTC `__. The return value is cached after first call. >>> import psutil, datetime >>> p = psutil.Process() >>> p.create_time() 1307289803.47 >>> datetime.datetime.fromtimestamp(p.create_time()).strftime("%Y-%m-%d %H:%M:%S") '2011-03-05 18:03:52' .. method:: as_dict(attrs=None, ad_value=None) Utility method retrieving multiple process information as a dictionary. If *attrs* is specified it must be a list of strings reflecting available :class:`Process` class's attribute names (e.g. ``['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 :class:`AccessDenied` or :class:`ZombieProcess` exception is raised when retrieving that particular process information. >>> import psutil >>> p = psutil.Process() >>> p.as_dict(attrs=['pid', 'name', 'username']) {'username': 'giampaolo', 'pid': 12366, 'name': 'python'} .. versionchanged:: 3.0.0 *ad_value* is used also when incurring into :class:`ZombieProcess` exception, not only :class:`AccessDenied` .. method:: parent() Utility method which returns the parent process as a :class:`Process` object pre-emptively checking whether PID has been reused. If no parent PID is known return ``None``. .. method:: status() The current process status as a string. The returned string is one of the :data:`psutil.STATUS_*` constants. .. method:: cwd() The process current working directory as an absolute path. .. method:: username() The name of the user that owns the process. On UNIX this is calculated by using real process uid. .. method:: uids() The **real**, **effective** and **saved** user ids of this process as a namedtuple. This is the same as `os.getresuid() `__ but can be used for any process PID. Availability: UNIX .. method:: gids() The **real**, **effective** and **saved** group ids of this process as a namedtuple. This is the same as `os.getresgid() `__ but can be used for any process PID. Availability: UNIX .. method:: terminal() The terminal associated with this process, if any, else ``None``. This is similar to "tty" command but can be used for any process PID. Availability: UNIX .. method:: nice(value=None) Get or set process `niceness `__ (priority). On UNIX this is a number which usually goes from ``-20`` to ``20``. The higher the nice value, the lower the priority of the process. >>> import psutil >>> p = psutil.Process() >>> p.nice(10) # set >>> p.nice() # get 10 >>> Starting from `Python 3.3 `__ this functionality is also available as `os.getpriority() `__ and `os.setpriority() `__ (UNIX only). On Windows this is implemented via `GetPriorityClass `__ and `SetPriorityClass `__ Windows APIs and *value* is one of the :data:`psutil.*_PRIORITY_CLASS ` constants reflecting the MSDN documentation. Example which increases process priority on Windows: >>> p.nice(psutil.HIGH_PRIORITY_CLASS) .. method:: ionice(ioclass=None, value=None) Get or set `process I/O niceness `__ (priority). On Linux *ioclass* is one of the :data:`psutil.IOPRIO_CLASS_*` constants. *value* is a number which goes from ``0`` to ``7``. The higher the value, the lower the I/O priority of the process. On Windows only *ioclass* is used and it can be set to ``2`` (normal), ``1`` (low) or ``0`` (very low). The example below sets IDLE priority class for the current process, meaning it will only get I/O time when no other process needs the disk: >>> import psutil >>> p = psutil.Process() >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # set >>> p.ionice() # get pionice(ioclass=, value=0) >>> On Windows only *ioclass* is used and it can be set to ``2`` (normal), ``1`` (low) or ``0`` (very low). Availability: Linux and Windows > Vista .. versionchanged:: 3.0.0 on >= Python 3.4 the returned ``ioclass`` constant is an `enum `__ instead of a plain integer. .. method:: rlimit(resource, limits=None) Get or set process resource limits (see `man prlimit `__). *resource* is one of the :data:`psutil.RLIMIT_* ` constants. *limits* is a ``(soft, hard)`` tuple. This is the same as `resource.getrlimit() `__ and `resource.setrlimit() `__ but can be used for any process PID, not only `os.getpid() `__. Example: >>> import psutil >>> p = psutil.Process() >>> # process may open no more than 128 file descriptors >>> p.rlimit(psutil.RLIMIT_NOFILE, (128, 128)) >>> # process may create files no bigger than 1024 bytes >>> p.rlimit(psutil.RLIMIT_FSIZE, (1024, 1024)) >>> # get >>> p.rlimit(psutil.RLIMIT_FSIZE) (1024, 1024) >>> Availability: Linux .. method:: io_counters() Return process I/O statistics as a namedtuple including the number of read and write operations performed by the process and the amount of bytes read and written. For Linux refer to `/proc filesysem documentation `__. On BSD there's apparently no way to retrieve bytes counters, hence ``-1`` is returned for **read_bytes** and **write_bytes** fields. OSX is not supported. >>> import psutil >>> p = psutil.Process() >>> p.io_counters() pio(read_count=454556, write_count=3456, read_bytes=110592, write_bytes=0) Availability: all platforms except OSX and Solaris .. method:: num_ctx_switches() The number voluntary and involuntary context switches performed by this process. .. method:: num_fds() The number of file descriptors used by this process. Availability: UNIX .. method:: num_handles() The number of handles used by this process. Availability: Windows .. method:: num_threads() The number of threads used by this process. .. method:: threads() Return threads opened by process as a list of namedtuples including thread id and thread CPU times (user/system). On OpenBSD this method requires root access. .. method:: cpu_times() Return a tuple whose values are process CPU **user** and **system** times which means the amount of time expressed in seconds that a process has spent in `user / system mode `__. This is similar to `os.times() `__ but can be used for any process PID. .. method:: cpu_percent(interval=None) Return a float representing the 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. That means the first time this is called it will return a meaningless ``0.0`` value which you are supposed to ignore. In this case is recommended for accuracy that this function be called a second time with at least ``0.1`` seconds between calls. Example: >>> import psutil >>> p = psutil.Process() >>> >>> # blocking >>> p.cpu_percent(interval=1) 2.0 >>> # non-blocking (percentage since last call) >>> p.cpu_percent(interval=None) 2.9 >>> .. note:: a percentage > 100 is legitimate as it can result from a process with multiple threads running on different CPU cores. .. warning:: the first time this method is called with interval = ``0.0`` or ``None`` it will return a meaningless ``0.0`` value which you are supposed to ignore. .. method:: cpu_affinity(cpus=None) Get or set process current `CPU affinity `__. CPU affinity consists in telling the OS to run a certain process on a limited set of CPUs only. The number of eligible CPUs can be obtained with ``list(range(psutil.cpu_count()))``. ``ValueError`` will be raise on set in case an invalid CPU number is specified. >>> import psutil >>> psutil.cpu_count() 4 >>> p = psutil.Process() >>> p.cpu_affinity() # get [0, 1, 2, 3] >>> p.cpu_affinity([0]) # set; from now on, process will run on CPU #0 only >>> p.cpu_affinity() [0] >>> >>> # reset affinity against all CPUs >>> all_cpus = list(range(psutil.cpu_count())) >>> p.cpu_affinity(all_cpus) >>> Availability: Linux, Windows, FreeBSD .. versionchanged:: 2.2.0 added support for FreeBSD .. method:: memory_info() 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. For more detailed memory stats use :meth:`memory_info_ex`. .. method:: memory_info_ex() Return a namedtuple with variable fields depending on the platform representing extended memory information about the process. All numbers are expressed in bytes. +--------+---------+-------+---------+--------------------+ | Linux | OSX | BSD | Solaris | Windows | +========+=========+=======+=========+====================+ | rss | rss | rss | rss | num_page_faults | +--------+---------+-------+---------+--------------------+ | vms | vms | vms | vms | peak_wset | +--------+---------+-------+---------+--------------------+ | shared | pfaults | text | | wset | +--------+---------+-------+---------+--------------------+ | text | pageins | data | | peak_paged_pool | +--------+---------+-------+---------+--------------------+ | lib | | stack | | paged_pool | +--------+---------+-------+---------+--------------------+ | data | | | | peak_nonpaged_pool | +--------+---------+-------+---------+--------------------+ | dirty | | | | nonpaged_pool | +--------+---------+-------+---------+--------------------+ | | | | | pagefile | +--------+---------+-------+---------+--------------------+ | | | | | peak_pagefile | +--------+---------+-------+---------+--------------------+ | | | | | private | +--------+---------+-------+---------+--------------------+ Windows metrics are extracted from `PROCESS_MEMORY_COUNTERS_EX `__ structure. Example on Linux: >>> import psutil >>> p = psutil.Process() >>> p.memory_info_ex() pextmem(rss=15491072, vms=84025344, shared=5206016, text=2555904, lib=0, data=9891840, dirty=0) .. method:: memory_percent() Compare physical system memory to process resident memory (RSS) and calculate process memory utilization as a percentage. .. method:: memory_maps(grouped=True) Return process's mapped memory regions as a list of namedtuples whose fields are variable depending on the platform. As such, portable applications should rely on namedtuple's `path` and `rss` fields only. This method is useful to obtain a detailed representation of process memory usage as explained `here `__. 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*). See `examples/pmap.py `__ for an example application. >>> import psutil >>> p = psutil.Process() >>> p.memory_maps() [pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, anonymous=1245, swap=0), pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0), pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> Availability: All platforms except OpenBSD and NetBSD. .. method:: children(recursive=False) Return the children of this process as a list of :Class:`Process` objects, pre-emptively checking whether PID has been reused. If recursive is `True` return all the parent descendants. Example assuming *A == this process*: :: A ─┠│ ├─ B (child) ─┠│ └─ X (grandchild) ─┠│ └─ Y (great grandchild) ├─ C (child) └─ D (child) >>> p.children() B, C, D >>> p.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. .. method:: open_files() Return regular files opened by process as a list of namedtuples including the absolute file name and the file descriptor number (on Windows this is always ``-1``). Example: >>> import psutil >>> f = open('file.ext', 'w') >>> p = psutil.Process() >>> p.open_files() [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)] .. warning:: on Windows this is not fully reliable as due to some limitations of the Windows API the underlying implementation may hang when retrieving certain file handles. In order to work around that psutil on Windows Vista (and higher) spawns a thread and kills it if it's not responding after 100ms. That implies that on Windows this method is not guaranteed to enumerate all regular file handles (see full discusion `here `_). .. warning:: on BSD this method can return files with a 'null' path due to a kernel bug hence it's not reliable (see `issue 595 `_). .. versionchanged:: 3.1.0 no longer hangs on Windows. .. method:: connections(kind="inet") Return socket connections opened by process as a list of namedtuples. To get system-wide connections use :func:`psutil.net_connections()`. Every namedtuple provides 6 attributes: - **fd**: the socket file descriptor. This can be passed to `socket.fromfd() `__ to obtain a usable socket object. This is only available on UNIX; on Windows ``-1`` is always returned. - **family**: the address family, either `AF_INET `__, `AF_INET6 `__ or `AF_UNIX `__. - **type**: the address type, either `SOCK_STREAM `__ or `SOCK_DGRAM `__. - **laddr**: the local address as a ``(ip, port)`` tuple or a ``path`` in case of AF_UNIX sockets. - **raddr**: the remote address as a ``(ip, port)`` tuple or an absolute ``path`` in case of UNIX sockets. When the remote endpoint is not connected you'll get an empty tuple (AF_INET) or ``None`` (AF_UNIX). On Linux AF_UNIX sockets will always have this set to ``None``. - **status**: represents the status of a TCP connection. The return value is one of the :data:`psutil.CONN_* ` constants. For UDP and UNIX sockets this is always going to be :const:`psutil.CONN_NONE`. The *kind* parameter is a string which filters for connections that fit the following criteria: .. table:: +----------------+-----------------------------------------------------+ | **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 | +----------------+-----------------------------------------------------+ Example: >>> import psutil >>> p = psutil.Process(1694) >>> p.name() 'firefox' >>> p.connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] .. method:: is_running() Return whether the current process is running in the current process list. This is reliable also in case the process is gone and its PID reused by another process, therefore it must be preferred over doing ``psutil.pid_exists(p.pid)``. .. note:: this will return ``True`` also if the process is a zombie (``p.status() == psutil.STATUS_ZOMBIE``). .. method:: send_signal(signal) Send a signal to process (see `signal module `__ constants) pre-emptively checking whether PID has been reused. On UNIX this is the same as ``os.kill(pid, sig)``. On Windows only **SIGTERM**, **CTRL_C_EVENT** and **CTRL_BREAK_EVENT** signals are supported and **SIGTERM** is treated as an alias for :meth:`kill()`. .. versionchanged:: 3.2.0 support for CTRL_C_EVENT and CTRL_BREAK_EVENT signals on Windows was added. .. method:: suspend() Suspend process execution with **SIGSTOP** signal pre-emptively checking whether PID has been reused. On UNIX this is the same as ``os.kill(pid, signal.SIGSTOP)``. On Windows this is done by suspending all process threads execution. .. method:: resume() Resume process execution with **SIGCONT** signal pre-emptively checking whether PID has been reused. On UNIX this is the same as ``os.kill(pid, signal.SIGCONT)``. On Windows this is done by resuming all process threads execution. .. method:: terminate() Terminate the process with **SIGTERM** signal pre-emptively checking whether PID has been reused. On UNIX this is the same as ``os.kill(pid, signal.SIGTERM)``. On Windows this is an alias for :meth:`kill`. .. method:: kill() Kill the current process by using **SIGKILL** signal pre-emptively checking whether PID has been reused. On UNIX this is the same as ``os.kill(pid, signal.SIGKILL)``. On Windows this is done by using `TerminateProcess `__. .. method:: wait(timeout=None) Wait for process termination and if the process is a children of the current one also return the exit code, else ``None``. On Windows there's no such limitation (exit code is always returned). If the process is already terminated immediately return ``None`` instead of raising :class:`NoSuchProcess`. If *timeout* is specified and process is still alive raise :class:`TimeoutExpired` exception. It can also be used in a non-blocking fashion by specifying ``timeout=0`` in which case it will either return immediately or raise :class:`TimeoutExpired`. To wait for multiple processes use :func:`psutil.wait_procs()`. Popen class ----------- .. class:: Popen(*args, **kwargs) A more convenient interface to stdlib `subprocess.Popen `__. It starts a sub process and deals with it exactly as when using `subprocess.Popen `__ but in addition it also provides all the methods of :class:`psutil.Process` class in a single interface. For method names common to both classes such as :meth:`send_signal() `, :meth:`terminate() ` and :meth:`kill() ` :class:`psutil.Process` implementation takes precedence. For a complete documentation refer to `subprocess module documentation `__. .. note:: Unlike `subprocess.Popen `__ this class pre-emptively checks wheter PID has been reused on :meth:`send_signal() `, :meth:`terminate() ` and :meth:`kill() ` so that you can't accidentally terminate another process, fixing http://bugs.python.org/issue6973. >>> import psutil >>> from subprocess import PIPE >>> >>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE) >>> p.name() 'python' >>> p.username() 'giampaolo' >>> p.communicate() ('hello\n', None) >>> p.wait(timeout=2) 0 >>> Constants ========= .. _const-pstatus: .. data:: PROCFS_PATH The path of the /proc filesystem on Linux and Solaris (defaults to "/proc"). You may want to re-set this constant right after importing psutil in case your /proc filesystem is mounted elsewhere. Availability: Linux, Solaris .. versionadded:: 3.2.3 .. versionchanged:: 3.4.2 also available on Solaris. .. _const-pstatus: .. data:: STATUS_RUNNING STATUS_SLEEPING STATUS_DISK_SLEEP STATUS_STOPPED STATUS_TRACING_STOP STATUS_ZOMBIE STATUS_DEAD STATUS_WAKE_KILL STATUS_WAKING STATUS_IDLE (OSX, FreeBSD) STATUS_LOCKED (FreeBSD) STATUS_WAITING (FreeBSD) STATUS_SUSPENDED (NetBSD) A set of strings representing the status of a process. Returned by :meth:`psutil.Process.status()`. .. versionadded:: 3.4.1 STATUS_SUSPENDED (NetBSD) .. _const-conn: .. data:: CONN_ESTABLISHED CONN_SYN_SENT CONN_SYN_RECV CONN_FIN_WAIT1 CONN_FIN_WAIT2 CONN_TIME_WAIT CONN_CLOSE CONN_CLOSE_WAIT CONN_LAST_ACK CONN_LISTEN CONN_CLOSING CONN_NONE CONN_DELETE_TCB (Windows) CONN_IDLE (Solaris) CONN_BOUND (Solaris) A set of strings representing the status of a TCP connection. Returned by :meth:`psutil.Process.connections()` (`status` field). .. _const-prio: .. data:: ABOVE_NORMAL_PRIORITY_CLASS BELOW_NORMAL_PRIORITY_CLASS HIGH_PRIORITY_CLASS IDLE_PRIORITY_CLASS NORMAL_PRIORITY_CLASS REALTIME_PRIORITY_CLASS A set of integers representing the priority of a process on Windows (see `MSDN documentation `__). They can be used in conjunction with :meth:`psutil.Process.nice()` to get or set process priority. Availability: Windows .. versionchanged:: 3.0.0 on Python >= 3.4 these constants are `enums `__ instead of a plain integer. .. _const-ioprio: .. data:: IOPRIO_CLASS_NONE IOPRIO_CLASS_RT IOPRIO_CLASS_BE IOPRIO_CLASS_IDLE A set of integers representing the I/O priority of a process on Linux. They can be used in conjunction with :meth:`psutil.Process.ionice()` to get or set process I/O priority. *IOPRIO_CLASS_NONE* and *IOPRIO_CLASS_BE* (best effort) is the default for any process that hasn't set a specific I/O priority. *IOPRIO_CLASS_RT* (real time) means the process is given first access to the disk, regardless of what else is going on in the system. *IOPRIO_CLASS_IDLE* means the process will get I/O time when no-one else needs the disk. For further information refer to manuals of `ionice `__ command line utility or `ioprio_get `__ system call. Availability: Linux .. versionchanged:: 3.0.0 on Python >= 3.4 thse constants are `enums `__ instead of a plain integer. .. _const-rlimit: .. data:: RLIMIT_INFINITY RLIMIT_AS RLIMIT_CORE RLIMIT_CPU RLIMIT_DATA RLIMIT_FSIZE RLIMIT_LOCKS RLIMIT_MEMLOCK RLIMIT_MSGQUEUE RLIMIT_NICE RLIMIT_NOFILE RLIMIT_NPROC RLIMIT_RSS RLIMIT_RTPRIO RLIMIT_RTTIME RLIMIT_RTPRIO RLIMIT_SIGPENDING RLIMIT_STACK Constants used for getting and setting process resource limits to be used in conjunction with :meth:`psutil.Process.rlimit()`. See `man prlimit `__ for futher information. Availability: Linux .. _const-aflink: .. data:: AF_LINK Constant which identifies a MAC address associated with a network interface. To be used in conjunction with :func:`psutil.net_if_addrs()`. .. versionadded:: 3.0.0 .. _const-duplex: .. data:: NIC_DUPLEX_FULL NIC_DUPLEX_HALF NIC_DUPLEX_UNKNOWN Constants which identifies whether a NIC (network interface card) has full or half mode speed. NIC_DUPLEX_FULL means the NIC is able to send and receive data (files) simultaneously, NIC_DUPLEX_FULL means the NIC can either send or receive data at a time. To be used in conjunction with :func:`psutil.net_if_stats()`. .. versionadded:: 3.0.0 Development guide ================= If you plan on hacking on psutil (e.g. want to add a new feature or fix a bug) take a look at the `development guide `_. psutil-3.4.2/docs/_static/0000775000175000017500000000000012647732502017372 5ustar giampaologiampaolo00000000000000psutil-3.4.2/docs/_static/copybutton.js0000664000175000017500000000467712572074510022147 0ustar giampaologiampaolo00000000000000$(document).ready(function() { /* Add a [>>>] button on the top-right corner of code samples to hide * the >>> and ... prompts and the output and thus make the code * copyable. */ var div = $('.highlight-python .highlight,' + '.highlight-python3 .highlight') var pre = div.find('pre'); // get the styles from the current theme pre.parent().parent().css('position', 'relative'); var hide_text = 'Hide the prompts and output'; var show_text = 'Show the prompts and output'; var border_width = pre.css('border-top-width'); var border_style = pre.css('border-top-style'); var border_color = pre.css('border-top-color'); var button_styles = { 'cursor':'pointer', 'position': 'absolute', 'top': '0', 'right': '0', 'border-color': border_color, 'border-style': border_style, 'border-width': border_width, 'color': border_color, 'text-size': '75%', 'font-family': 'monospace', 'padding-left': '0.2em', 'padding-right': '0.2em', 'border-radius': '0 3px 0 0' } // create and add the button to all the code blocks that contain >>> div.each(function(index) { var jthis = $(this); if (jthis.find('.gp').length > 0) { var button = $('>>>'); button.css(button_styles) button.attr('title', hide_text); jthis.prepend(button); } // tracebacks (.gt) contain bare text elements that need to be // wrapped in a span to work with .nextUntil() (see later) jthis.find('pre:has(.gt)').contents().filter(function() { return ((this.nodeType == 3) && (this.data.trim().length > 0)); }).wrap(''); }); // define the behavior of the button when it's clicked $('.copybutton').toggle( function() { var button = $(this); button.parent().find('.go, .gp, .gt').hide(); button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden'); button.css('text-decoration', 'line-through'); button.attr('title', show_text); }, function() { var button = $(this); button.parent().find('.go, .gp, .gt').show(); button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible'); button.css('text-decoration', 'none'); button.attr('title', hide_text); }); }); psutil-3.4.2/docs/_static/logo.png0000664000175000017500000001147212572074510021040 0ustar giampaologiampaolo00000000000000‰PNG  IHDR77¨ÛÒFsBIT|dˆñIDAThÅšÉ$IVÆfæî±o¹geVvvWUï-f §§!˜fæ€8pà4œù¸ qã‚ø+æˆÃÀ$àˆYZ½ÍtWwí•U™‘«/fö8ø’‘YUÕÓH¸dòHÏwÿì{ï{ï™=%"BqˆJ)–.ý¿"‚Öï}u><<¬ÞQDØÜÜD)P~¿zy½|³òü´á½æÿþ¯‡÷¥išr||Œ÷­5Óé”8ŽY[[cmm8Ž™ÏçÕ$ŒÇãs¤JæÊxïɲŒ$IX,çf²œ±r¦¾À¿¥@Q U¼‡1ç“ɤb$Š"¼÷DQD·ÛED˜N§dYF³ÙÄ{Ï|>§ÕjÉêê*Zë3p%sÞ{¦Ó)“É„f³Iš¦h­_¼€üAå¿FP¨âŸ˜€‹×K0K“¥Dª pÞspp@·ÛemmÃÃCD„n·K£Ñ¨ÌÔÃt:e>ŸEív›ÓÓS ‚€ ‚‹f©”ÂZËb±`°²Bf-JL ÐÚ‚VëQh¥Éq¨ê>Zës~¡µÆ‹ Jö &u”¨÷ž08±ÖÒét8==¥ßïqsÿþýÊEŒ1 z½ÖZNOO8<'( ¥°Îá¬åñ£G8çh·ÛL&¢(¢V«1™LȲ ­5ZkšÍ&Y–U ’$‘íím®\¹òtŸ+M4—U€k3ŒÑ$I‚sŽF£Áññ1­V c £ÑˆF£Ah IšÒlµq"ÌÆZÍÞ (ò‚RR PŦRÜ»s'Ÿ¥¨×ëÄqŒR ç'§§ô{=®\¹‚Œ†C”RÄqL­V£Ûí2™L&ç}®dcdàʱ?úè#VVV899¡ÙhÕjÄqŒ1†«X›r2<ï™Í¦lon°µ½³…D4ž<àŠ£ÑˆZ­FEdY†1k-Yš²³³C’¦ ÂÕÝ]nߺU‘Q«Õ*±I’ä¼Ï- KAÝ9¹.ã`½^çÆlmn&§ ƒ$Y }Ìã£>¹?a´°ÌSÇüÓ»DcBíéÔZQ@¿ðê•>WÖW ¬aƒµ­u%å3­µxçðÎê[‚ÐZÓëõ‚€4MqΑ¦é“àžª*[›µõõ\D0Fc=ø4æ‹GCþîý!wO,±ñ†Ô ™ó¤é)ºÚ{Bõà.¿s½ÏÿæuÖÖVY[[c>Ÿ‘$ ÆjµY–FØÚÞF‰pûömêõz®ŒA€ˆTÂÒh4žï}%(Wvv*G]Y–U²î"?ÿìóï9MÍPƒxÆ‹ƒ€ø–wx/8ïqÖ#âˆSË÷_ðg?ø5+”(nß¾ÅÁÁ½^­uÅsŽ(ŠPZã# ÃÊ|½÷œžžÊ7¸zõêYnùTæÊQ84Pׯj§ £“Ó ïßó` ¿¾Ûà¯ÿä5þ⯳Õðâñ"Xë°Îç÷r…C!´k†pÈÿüòÚ;ÂZÄÚêjÅDÉÜd2a2™0›Í*`Æ:AàŠk«««9 —™¥¡E|ðÁÌçsúƒ'Ã!ï½÷|ø!GGGì\¹Âg7¿àhÜ"M3~c¯Ïþz‡Gâ›{]þñýG„êɤÜû2IÎ3–î ùíod4Ã\/šY¯×C)E†U(‚ òÑÒ¢NOOi6›_¥*ú××Ö˜ÎftÚmövw±ÎÑ/V«×¹zõ*ÿ=R 4ÿùÅ ×7Œç?¹•û™xÉsJï9?<ùÿŽÇ ¼’8æáÃÚí6(ET0´œçĦLÇÂ0äáÇçs˧"‚)ëÕ½=‚ ÿz–eXçØÙÝeWi”Öyiòþˆz ùÙî ç8ç881*÷±Š5ÿô2G+]$m®]{‰;wîÐhÔ+†‹E%÷e¨²EFTöŠw½Ô,E)´RUžy÷î]¶¶¶9‰3Ö×Ö G(­ÉÒç‘‚û' ”xB ÎIÎ’/Î…IJñ2BOÆœžŽISK’dôz}=:àúµÑ&Ä9Çññ1F£ iš²¿¿OÜ¿Ÿ^xµµ5DäpEZTŠùàÁ\s4qðø˜õ †Ã!ÚVç‡üV˜a´æÚë/á,X爢ný’ŸêÜL„’à=8Á#‹ù‚_üò#³¼*èv{´Ú]‰pøøÆÒ4£^¯#"ŒÇcD„4Mév»¼ñÆUH¸TPÊšK+… ˆÀw¾ýÝ:à“¹ç‹´Áé§)Þ¯àŃoA˜ç™Ÿ|š!…/y7#W˜X0bñyLXªºÁYG¯¿ÊË{–îç8'(m8™(>ºE½I(¥±ÖÐh4HÓ´2Dz"/‘/g.ÿ&¢âÁ& þõý/øÑ3†±ÂäRÞç>å}þ ŸÇ5/¹¯á="!ˆqK¾VA‘צ'´jLjhžN]¸ºzŸ{“€,úÛ[+$išÍ&7oÞ¤ÕjQ¯×Ÿxÿ/sE9¢$ÙOïñ·?3µ†f åÑâQ’Ÿ5ƒ`ph%hñòëZ\Å–Qù ÷£yøà!ÇÇCD…Ù Îz¼‡µà?xx÷¿Ð&"L%ý••å"Õqy(P (\óoŸ°-ŽÔy(™YŠ[²ÀW±¬ g"R2§ªå ¡ÛíÐhÄ(±y€ µ eí³yB£¦ð¢8KîÏÆó3W‘¢ÓÙŒO3²ÌÕzQATæå+Eô…/ÉÒð.7Ùå!ÞãªÜT¸qu“­U—¢ÄØ|8‡’”np‹é,&ªE„aôT¶ž\^%ƒÁsw8g’Ø¢ô¹øòRùZy]AnšÕàl0ZS3Ö õÀÆÇ´ÌýÜ/}L•Ÿqh?dvò9ãñŒ$É«ñ/xyœ#÷»ƒqF’y4,;‹_”©¹™¦ÖâœÇûœi¿ç\Î2J!ÞѨ¼»Ûç­Í›´kGyeîàÂWók3²ùM‹évÌSMñ¹Á-Áyf©Åú<œùÍÙÙI,µ‚"cµåk‡…Tûâ}5qFAF¼½×à÷_Ÿóúö ÎÀ)”d %6Oн%0°>¬®Ù“Kˆ_•¹ÒáSë ñPE¡xÞÇ”™Öêžo]érµŸ°·.D¡F¼.Ö¸…BiHÓŒF¤ÙêÆ´£û ’‚Ó(ÒBll®°Þ£”G9‹µ#fó˜n ‚0üf¹´W4ZÊÛœ!9â-Ê;Äe$~ÝxÈóÓ˘»<ΣÑjñÆfÅY]ÖeÖ ý†fw»ƒò µÊ ò… z’å *0Y>Äæÿ«ÎÅÀž IñŒäÛ´ÑùŠbiüJÌ)¥£¿ûÆÝ8/„†Üpåiµ[DaD®ˆr–ax[d‡÷gÏâÞYÖ’§_^$¿æï\þ]J9ÙBºïѨiœ;¿_ø¬xw)sH¾:ŒÒ¼²¿ÍßÝ¡¡'ó + +Šyâ˜Íæ…æ+Z¥©åYF΢•Å„)ZÍÑÌÐzŽfŽfš™¢ƒ4¿®L˜a³XóÑÉP¦Çd|JǤiR{{ÏU¬*)b^Xãûï¼ÂV¿ÉÏïŒøÉÇ_0[,ØÞ»‚Ÿ?ÆWf§ sʳ ç¤Ü?hpû Íîv„̦cja¾Ùb´Fá éu:ÄéœáhB³÷"·®ÐÙ|‹Mãy|8bk{kmU´>+q¾4œ…ŠÅ &ï¾uo½îyðÍ«(ý~ŸñøþCÁT ®s/ ™lãë/3u%pxÜ ßë… 'hîQé5ˆj„.cuÇ£M·®ÕÈÒ JÖ76È2‹ÖÅ~†:;/o\ÎÜÒlˆTêè ÚóÂÞÕj‰ÍhÈùÜǤLŸÄˆƒT±¿òû+Ÿ#0ç“@ d£ô{øæÛ´ZmœËï“'Í‚«u«w2&§a± ²¼ô¾ÌÞåf™£* Apøø1Ÿ~öûûûP«ÕÐz~M‹x ø¥ÊÛU:O¥ø”D¿b ²›˜ Ø¾JR²(_ïw.‰"àœ%Ëò%¼0 ÇÌf3¶··©ÕjgÖ¶.7KžT!7Åf³I«ÙDƒB¬Éã’hDÒ"/= ȹ ¸”8x…ÅÚŸã‰hýìŸb½%ެµ¤iZí¨j­©ÕjAÀpxÌb±`gg‡~¿OEÕ~Fi]—3ÇYòì‹…"çÛÛÛìììà½g}}€ù"argÅOñæ´äq./ƒÊD”$¤ú5š­U¬jŽ¿A3ý±_'-ÇÇ÷8<­V‹·¿õmÏxú&ߦÿ˜–ú†1ÚÏ0d(åQ8 ðt±Rgl¯s¤ÿ€Úà5ÂÀ“eŽV³•¯.‡L§SÆã1Óé”Á`Àúúz¬œüg5=w((ÿN’„(ÊgFÕí“3¬éuë´Zo3ž|ƒÇ“{Ù/0öÊÑ>ÅI„Ó}b®’×»¬ÖóÌf6OI2ËîÕU&“ Óé”ÓÓSÆã1½^ÍÍM:N% _ì¹À•-?ùéO©E“É­5aÒjµØÛÛ«6'ÊÆ€00¬€Á5¬»Af™õXç1â •§©\^q{Gš9² â$„V«Åh4:lkk«–eE\â'À-çhål8ï󎜢c'Ë2œsôz½sÌ•óß(qD@™$ ÎåægÂyÇ?ñ$ñ‚A¿OÇœœœ0™Lè÷ûO0ö¼ýgÏlÕXnm²ÖòÂÞ^þ­Ï5¨•ÙyùÛ`™®)e(š’pÞ"âñâòn1U$åäý/Y–1 FL&ƒt:sŒ]¶êõ¸òÅžVF”}·jÌçs ŒÇã¼sÈ9f³¯¾ú*£ÑˆñxŒ1†ÅbÁõë׫L¦ßïã\žu.Jéªi>Ÿ3›ÍX__?'MñyØ;×o¹œ]—ÝDå` ¨÷ž?þ¸j¶¹}û6Óé´jglµZloo³±±ˆT›†N‡$IªÝPç\õ¹Ü°ŸÍflll°±±A»Ý>'_\è·,ápÈp8äå—_Î[‘н9Ež<—ÛFOÛY¹xœœœÐétªý½‹“æœÃZËÑÑÇÇǬ¯¯³²²’ïiûÝ%¨e¾ä¨òý–å¦Þp8¤ÓéTb±|ÓeŸ¼(ÇËæC1ËÅäÅâ²ãñ˜f³Y¥Te«^ôù{\)e÷MÙPú4p_å¸Xc=íš1†v»]µ–fø+>÷ÙÌ•@—åýiyZ¢ú´cÙœ.‚¾h Ƙ¥P"¿*À'Á-ßpÙD¿,ø:ÇÅû>«¢þ:Ìý/Ù3ƒ‰(?ÞIEND®B`‚psutil-3.4.2/docs/_static/sidebar.js0000664000175000017500000001205412572074510021336 0ustar giampaologiampaolo00000000000000/* * sidebar.js * ~~~~~~~~~~ * * This script makes the Sphinx sidebar collapsible. * * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds in * .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton used to * collapse and expand the sidebar. * * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden and the * width of the sidebar and the margin-left of the document are decreased. * When the sidebar is expanded the opposite happens. This script saves a * per-browser/per-session cookie used to remember the position of the sidebar * among the pages. Once the browser is closed the cookie is deleted and the * position reset to the default (expanded). * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ $(function() { // global elements used by the functions. // the 'sidebarbutton' element is defined as global after its // creation, in the add_sidebar_button function var bodywrapper = $('.bodywrapper'); var sidebar = $('.sphinxsidebar'); var sidebarwrapper = $('.sphinxsidebarwrapper'); // original margin-left of the bodywrapper and width of the sidebar // with the sidebar expanded var bw_margin_expanded = bodywrapper.css('margin-left'); var ssb_width_expanded = sidebar.width(); // margin-left of the bodywrapper and width of the sidebar // with the sidebar collapsed var bw_margin_collapsed = '.8em'; var ssb_width_collapsed = '.8em'; // colors used by the current theme var dark_color = '#AAAAAA'; var light_color = '#CCCCCC'; function sidebar_is_collapsed() { return sidebarwrapper.is(':not(:visible)'); } function toggle_sidebar() { if (sidebar_is_collapsed()) expand_sidebar(); else collapse_sidebar(); } function collapse_sidebar() { sidebarwrapper.hide(); sidebar.css('width', ssb_width_collapsed); bodywrapper.css('margin-left', bw_margin_collapsed); sidebarbutton.css({ 'margin-left': '0', //'height': bodywrapper.height(), 'height': sidebar.height(), 'border-radius': '5px' }); sidebarbutton.find('span').text('»'); sidebarbutton.attr('title', _('Expand sidebar')); document.cookie = 'sidebar=collapsed'; } function expand_sidebar() { bodywrapper.css('margin-left', bw_margin_expanded); sidebar.css('width', ssb_width_expanded); sidebarwrapper.show(); sidebarbutton.css({ 'margin-left': ssb_width_expanded-12, //'height': bodywrapper.height(), 'height': sidebar.height(), 'border-radius': '0 5px 5px 0' }); sidebarbutton.find('span').text('«'); sidebarbutton.attr('title', _('Collapse sidebar')); //sidebarwrapper.css({'padding-top': // Math.max(window.pageYOffset - sidebarwrapper.offset().top, 10)}); document.cookie = 'sidebar=expanded'; } function add_sidebar_button() { sidebarwrapper.css({ 'float': 'left', 'margin-right': '0', 'width': ssb_width_expanded - 28 }); // create the button sidebar.append( '
    «
    ' ); var sidebarbutton = $('#sidebarbutton'); // find the height of the viewport to center the '<<' in the page var viewport_height; if (window.innerHeight) viewport_height = window.innerHeight; else viewport_height = $(window).height(); var sidebar_offset = sidebar.offset().top; var sidebar_height = sidebar.height(); //var sidebar_height = Math.max(bodywrapper.height(), sidebar.height()); sidebarbutton.find('span').css({ 'display': 'block', 'margin-top': sidebar_height/2 - 10 //'margin-top': (viewport_height - sidebar.position().top - 20) / 2 //'position': 'fixed', //'top': Math.min(viewport_height/2, sidebar_height/2 + sidebar_offset) - 10 }); sidebarbutton.click(toggle_sidebar); sidebarbutton.attr('title', _('Collapse sidebar')); sidebarbutton.css({ 'border-radius': '0 5px 5px 0', 'color': '#444444', 'background-color': '#CCCCCC', 'font-size': '1.2em', 'cursor': 'pointer', 'height': sidebar_height, 'padding-top': '1px', 'padding-left': '1px', 'margin-left': ssb_width_expanded - 12 }); sidebarbutton.hover( function () { $(this).css('background-color', dark_color); }, function () { $(this).css('background-color', light_color); } ); } function set_position_from_cookie() { if (!document.cookie) return; var items = document.cookie.split(';'); for(var k=0; kÿœp;ÿ–j7ÿ”i6ÿ’h5÷‡`2¶OEÎìˆBÚÿÿ7Öÿÿ-Óÿÿ=ÃPÿ¼‰Lÿµ„Hÿ¯Eÿ¨yAÿ¡t=ÿ›o:ÿ”i6ÿ”i6ÿ”i6ÿ‡`2¶CKÞÿÿAÚÿÿ6Õýí$Æ‘R½ÁOÿ»ˆKÿ´ƒHÿ­}Dÿ¦x@ÿ s=ÿ™m9ÿ”i6ÿ”i6ÿ”i6ÿHUâÿÿJÝý÷>Õù‚ ÄN~¿ŠL ¶…H¡­}C£¡t=§–l9ªf6ª—l8ÿ”i6ÿ”i6ÿH·…Iÿ±€Fÿª{Bÿ£u>ÿp;ÿ–j7ÿ”i6ÿA¼ŠLÿÿÿÿÿ¯Eÿ¨yAÿ¢t>ÿ›o:ÿ”i6ÿ( ÀN¯º†Jí´ƒHÿ­~Dÿ§x@ÿžq<÷–h7’ ððð€ððð( @ € %1:AD@9.!%0¸Ü~1Åîµ.ËöØ(Ëùí&ËûÿÆ÷ãÂõØ´äª †­nK<#  BËëvAÖúí>Öüÿ9Ôüÿ4Òüÿ/Ðûÿ*Íûÿ%Ëûÿ ÉûÿÇúÿÅúÿÁøí¹|D!OÙ÷MÝýÿHÚýÿCØüÿ>Öüÿ9Ôüÿ4Òüÿ/Ðûÿ*Íûÿ%ËûÿsÝüÿâøþÿ{ÞüÿÃúÿ’¼z3 WßüíRßýÿMÜýÿHÚýÿCØüÿ>Öüÿ9Ôüÿ4Òüÿ/Ïûÿ*ÍûÿÿÿÿÿÿÿÿÿÿÿÿÿÅúÿ»ñÍ:[ãþÿVáýÿRßýÿMÜýÿHÚýÿCØüÿ=Öüÿ9Ôüÿ4Òüÿ/Ïûÿ¢éýÿÿÿÿÿäýÿÇúÿÀõØ;`åþÿ[ãþÿVáýÿQÞýÿMÜýÿHÚýÿCØüÿ=Öüÿ8Ôüÿ3Ñüÿ/Ïûÿ*Íûÿ%Ëûÿ ÉûÿÃõØ, eçþÿ`åþÿ[ãþÿVáýÿQÞýÿLÜýÿGÚýÿCØüÿ=Öüÿ8Ôüÿ3Ñüÿ.Ïûÿ)Íûÿ%ËûÿÆ÷Ø'$7AF6jéþÿeçþÿ`åþÿ[ãþÿVàýÿQÞýÿLÜýÿZNHHHHHHHHHFA6!  ¢v>vªzBبy@í§xAÿ¤v?ÿHoëÿÿjéþÿeçþÿ`åþÿ[ãþÿVàýÿQÞýÿLÜýÿGÚýÿBØüÿ=Öüÿ8Óüÿ3Ñüÿ.Ïûÿ)Íûÿ$ËûÿÉûÿÆúÿÂøí¾õØ‘º{C!®}D‚±Fÿ¯Eÿ¬|Cÿ©zBÿ¦x@ÿHtíÿÿoëÿÿjéþÿdçþÿ_åþÿ[ãþÿVàýÿQÞýÿLÜýÿGÚýÿBØüÿ=Öüÿ8Óüÿ3Ñüÿ.Ïûÿ)Íûÿ$ËûÿÉûÿÆúÿÄúÿÂúÿº{9£H´„H÷´‚Gÿ±€Fÿ®~Dÿ«|Cÿ¨yAÿIuîÿÿsíÿÿoëÿÿjéþÿdçþÿ_åþÿZâþÿUàýÿQÞýÿLÜýÿGÚýÿBØüÿ=Õüÿ8Óüÿ3Ñüÿ.Ïûÿ)Íûÿ$ËûÿÈûÿÆúÿÄúÿ¾ôØH·…I€¹†Jÿ¶„Iÿ³‚Gÿ°€Fÿ­}Dÿª{BÿMuîÿÿuîÿÿsíÿÿnëÿÿiéþÿdçþÿ_åþÿZâþÿUàýÿPÞýÿLÜýÿGÚýÿBØüÿ=Õüÿ8Óüÿ2Ñüÿ.Ïûÿ)Íûÿ$ËûÿÈûÿÆúÿÄúÿu–d-¹ˆK°ºˆKÿ¸†JÿµƒHÿ²Gÿ¯Eÿ¬}CÿuR+otìýíuîÿÿuîÿÿsíÿÿnëÿÿiéþÿdçþÿ_äþÿZâþÿUàýÿPÞýÿKÜýÿFÚýÿBØüÿ=Õüÿ8Óüÿ2Ñüÿ-Ïûÿ(Íûÿ$ËûÿÈûÿÆúÿ²äª8¾ŠM×¼ŠLÿº‡Kÿ·…Iÿ´ƒHÿ±Fÿ¯~Eÿœp=ªaÈØƒuîÿÿuîÿÿuîÿÿsíÿÿnëÿÿiéþÿdçþÿ_äþÿZâþÿUàýÿPÞýÿKÜýÿFÚýÿA×üÿ<Õüÿ8Óüÿ2Ñüÿ-Ïûÿ(Íûÿ#ÊûÿÈûÿÁõØ<ÁŽOÿ¿‹Nÿ¼‰Lÿ¹‡Jÿ¶…Iÿ³‚Gÿ°€Fÿ®~DÿqO*saÈØƒrëüãuîÿÿuîÿÿsíÿÿnëÿÿiéþÿdçþÿ_äþÿZâþÿUàýÿPÞýÿKÜýÿFÚýÿA×üÿ<Õüÿ7Óüÿ2Ñüÿ-Ïûÿ(Íûÿ#ÊûÿÂöØ>ÃPÿÁOÿ¾‹Mÿ»ˆKÿ¸†Jÿµ„Hÿ²‚Gÿ°Eÿ­}Dÿšp:ªbF#eLIHHHHHHHG¿ÙMÚùØKÜýÿFÙýÿA×üÿ<Õüÿ7Óüÿ2Ñüÿ-Ïûÿ(Ìûÿ"Èùí<Å‘QÿÃPÿÀŒNÿ½ŠMÿºˆKÿ·†JÿµƒHÿ²Fÿ¯Eÿ¬|Cÿ©zBÿ¦x@ÿ¤v?ÿ¡s=ÿžq<ÿ›o:ÿ˜m8ÿ–j7ÿ”i6ÿ”i6ÿd4ÍdF"pKÓð´KÜýÿFÙýÿA×üÿ<Õüÿ7Óüÿ2Ñüÿ-Ïûÿ%ÇöØ6Å’PãÅQÿÂŽOÿ¿ŒNÿ¼‰Lÿ¹‡Kÿ·…Iÿ´ƒHÿ±€Fÿ®~Eÿ«|Cÿ¨zAÿ¦w@ÿ£u>ÿ s=ÿp;ÿ›n:ÿ˜l8ÿ•j6ÿ”i6ÿ”i6ÿ’h5÷dF$pMÚùØKÜýÿFÙýÿA×üÿ<Õüÿ7Óüÿ2Ñüÿ*ÈóÍ.Ç“S½Ç’RÿÄPÿÁOÿ¾‹Mÿ»‰Lÿ¹‡Jÿ¶„Iÿ³‚Gÿ°€Fÿ­~Dÿ«{Bÿ¨yAÿ¥w?ÿ¢t>ÿŸr<ÿœp;ÿšn9ÿ—k8ÿ”i6ÿ”i6ÿ”i6ÿf3ØG¿×OÞýÿJÛýÿEÙýÿA×üÿ<Õüÿ7Óüÿ-Âé¨#É•UÉ”SÿÆ‘RÿÃPÿÀOÿ¾ŠMÿ»ˆKÿ¸†Jÿµ„Hÿ²Gÿ¯Eÿ­}Dÿª{Bÿ§x@ÿ¤v?ÿ¡t=ÿŸq<ÿœo:ÿ™m9ÿ–k7ÿ”i6ÿ”i6ÿ”i6ÿHTàýÿOÞýÿJÛýÿEÙýÿ@×üÿ;Õüÿ-°ÑqÇ›XÊ“R÷È“SÿÅ‘QÿÂŽPÿÀŒNÿ½ŠLÿº‡Kÿ·…Iÿ´ƒHÿ±Fÿ¯Eÿ¬|Cÿ©zBÿ¦x@ÿ¤u?ÿ¡s=ÿžq;ÿ›o:ÿ˜l8ÿ•j7ÿ”i6ÿ”i6ÿHYâþÿTàýÿOÝýÿJÛýÿEÙýÿ>Õú÷* Ì“U~Ê•TÿÇ’RÿÄQÿÂŽOÿ¿ŒNÿ¼‰Lÿ¹‡Jÿ¶…Iÿ´‚Gÿ±€Fÿ®~Dÿ«|Cÿ¨yAÿ¥w@ÿ£u>ÿ s=ÿp;ÿšn9ÿ—l8ÿ•i6ÿ”i6ÿH^äþÿYâþÿTàýÿOÝýÿJÛýÿAÏñ•Ì–SkÇ“RãÆ’RÿÄPÿÁOÿ¾‹Mÿ»‰Lÿ¸†Jÿ¶„Iÿ³‚Gÿ°Eÿ­}Dÿª{Bÿ§yAÿ¥w?ÿ¢t>ÿŸr<ÿœp:ÿšm9ÿ—k7ÿ”i6ÿHcæþÿ^äþÿYâþÿRÞû÷M×÷¢ 6HHHHHH§x@ÿ¤v?ÿ¡t=ÿžq<ÿ›o:ÿ™m9ÿ–j7ÿH¿ŒNÿ¼ŠLÿº‡Kÿ·…Iÿ´ƒHÿ±Fÿ®~Eÿ¬|Cÿ©zAÿ¦w@ÿ£u>ÿ s=ÿq;ÿ›o:ÿ˜l8ÿHÁOÿ¿‹Nÿ¼‰Lÿ¹‡Jÿ¶…Iÿ³‚Gÿ°€Fÿ®~Dÿ«{Cÿ¨yAÿ¥w?ÿ¢u>ÿ r<ÿp;ÿšn9ÿGÃPÿÁOÿçÓ¼ÿÿÿÿÿàʯÿµ„Hÿ²‚Gÿ°Eÿ­}Dÿª{Bÿ§xAÿ¤v?ÿ¢t>ÿŸr<ÿœo:ÿ@Å‘QÿÃŽPÿÿÿÿÿÿÿÿÿÿÿÿÿ·…IÿµƒHÿ²Fÿ¯Eÿ¬|Cÿ©zBÿ¦x@ÿ¤v?ÿ¡s=ÿœo;÷, Å’PãÅQÿáǧÿÿÿÿÿÕµÿ¹‡Kÿ·…Iÿ´ƒHÿ±€Fÿ®~Dÿ«|Cÿ¨zAÿ¦w@ÿ£u>ÿ™m9¥ÉOCÆP÷ÄPÿÁOÿ¾‹Mÿ»‰Lÿ¹†Jÿ¶„Iÿ³‚Gÿ°€Fÿ­~Dÿ«{Bÿ¨yAÿ t=¿Ç›XÄRÁOË¿ŒMؾŠMÿ»ˆKÿ¸†Jÿµ„Hÿ°€F÷­~CتzB¿¦w?\ÿ€ÿÿÿÿÿÿÿÀ€€€Àÿÿÿÿÿÿÿÿÿ€ÿ(0` €% #.6:=BEA=:3+!  3,¬Ðs.Áè©,ÅïÂ+ËõÙ&ÇõÙ%Ëùí#ÊûÿÅ÷äÃôÙÁôٷ鶬ݞ ‡®oL@. 9¾ØC<ÏóÁ<Ôú÷:Ôüÿ7Óüÿ3Ñüÿ0Ðûÿ-Îûÿ)Íûÿ&Ìûÿ#Êûÿ ÉûÿÇúÿÆúÿÄúÿÃúÿÀøí¬â«`|Z>BÌëPFØû÷CØüÿ@×üÿ=Öüÿ:Ôüÿ7Óüÿ3Ñüÿ0Ðûÿ-Îûÿ)Íûÿ&Ìûÿ#Êûÿ ÉûÿÇúÿÆúÿÄúÿÃúÿÂúÿ ¾øí¥r>K×ð3LÛû÷JÛýÿGÚýÿCØüÿ@×üÿ=Öüÿ9Ôüÿ6Óüÿ3Ñüÿ0Ðûÿ-Îûÿ)Íûÿ&Ìûÿ"ÊûÿÉûÿÇúÿCÑûÿ$ÇúÿÃúÿÂúÿ ¾øía~Y+ RÝù°PÞýÿMÝýÿJÛýÿGÚýÿCØüÿ@×üÿ=Õüÿ9Ôüÿ6Óüÿ3Ñüÿ0Ðûÿ-Îûÿ)Íûÿ&Ëûÿ"ÊûÿÇñþÿÿÿÿÿñûÿÿ^ÖüÿÃúÿÁúÿ©Ýž9VßûØTßýÿPÞýÿMÝýÿJÛýÿGÚýÿCØüÿ@×üÿ=Õüÿ9Ôüÿ6Óüÿ3Ñüÿ0Ðûÿ,Îûÿ)ÍûÿiÛüÿÿÿÿÿÿÿÿÿÿÿÿÿÅñþÿÄúÿÃúÿ¼ôÙAZâþÿWáýÿTßýÿPÞýÿMÝýÿJÛýÿFÚýÿCØüÿ@×üÿ=Õüÿ9Ôüÿ6Óüÿ3Ñüÿ/Ðûÿ,Îûÿ^Ùüÿÿÿÿÿÿÿÿÿÿÿÿÿ¸íýÿÆúÿÄúÿÀôäG]äþÿZâþÿWáýÿTßýÿPÞýÿMÜýÿIÛýÿFÚýÿCØüÿ@×üÿ=Õüÿ9Ôüÿ6Òüÿ2Ñüÿ/Ðûÿ,Îûÿ¢éýÿÿÿÿÿãøþÿIÒüÿÇúÿÆúÿÄúÿI`åþÿ]äþÿZâþÿWáýÿTßýÿPÞýÿMÜýÿIÛýÿFÚýÿCØüÿ@×üÿ=Õüÿ9Ôüÿ6Òüÿ2Ñüÿ/Ðûÿ,Îûÿ)Íûÿ&Ëûÿ"ÊûÿÈûÿÇúÿÆúÿIdæþÿ`åþÿ]äþÿZâþÿVáýÿSßýÿPÞýÿMÜýÿIÛýÿFÚýÿCØüÿ?×üÿ<Õüÿ9Ôüÿ6Òüÿ2Ñüÿ/Ðûÿ,Îûÿ(Íûÿ%Ëûÿ"ÊûÿÈûÿÇúÿ7 gèþÿdæþÿ`åþÿ]ãþÿYâþÿVáýÿSßýÿPÞýÿMÜýÿIÛýÿFÚýÿCØüÿ?×üÿ<Õüÿ9Ôüÿ6Òüÿ2Ñüÿ/Ðûÿ,Îûÿ(Íûÿ%Ëûÿ"ÊûÿÈûÿ+-?GIII7jéþÿgèþÿdæþÿ`åþÿ]ãþÿYâþÿVáýÿSßýÿPÞýÿMÜýÿIÛýÿ\PIIIIIIIIIIIIIIIIF;'”j;+£u>§ªzBí©zBÿ§yAÿ¦w@ÿ¤v?ÿ¢t>ÿImëÿÿjéþÿfèþÿcæþÿ`åþÿ]ãþÿYâþÿVáýÿSßýÿOÞýÿLÜýÿIÛýÿFÙýÿCØüÿ?×üÿ<Õüÿ9Ôüÿ5Òüÿ2Ñüÿ/Ïûÿ,Îûÿ(Íûÿ%Ëûÿ"ÊûÿÈûÿÇúÿÅúÿÄúÿÃúÿ ¼ôÙ¡Ó“L2žnD%®}Dã®~Eÿ¬}Cÿ«{Bÿ©zAÿ§x@ÿ¥w?ÿ£u>ÿIpìÿÿmëÿÿjéþÿfèþÿcæþÿ`åþÿ]ãþÿYâþÿVáýÿSßýÿOÞýÿLÜýÿIÛýÿFÙýÿCØüÿ?×üÿ<Õüÿ8Ôüÿ5Òüÿ2Ñüÿ/Ïûÿ,Îûÿ(Íûÿ%Ëûÿ!ÊûÿÈûÿÇúÿÅúÿÄúÿÃúÿÁúÿ µìÂO+ ±€EرFÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¥v?ÿItíÿÿpìÿÿmêÿÿjéþÿfèþÿcæþÿ`åþÿ]ãþÿYâþÿVàýÿSßýÿOÞýÿLÜýÿIÛýÿFÙýÿBØüÿ?Öüÿ<Õüÿ8Ôüÿ5Òüÿ2Ñüÿ/Ïûÿ+Îûÿ(Ìûÿ%Ëûÿ!ÊûÿÈûÿÇúÿÅúÿÄúÿÂúÿÁúÿ¦ÚŸC°€DoµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|CÿªzBÿ¨yAÿ¦w@ÿIuîÿÿsíÿÿpìÿÿmêÿÿjéþÿfèþÿcæþÿ`åþÿ\ãþÿYâþÿVàýÿSßýÿOÞýÿLÜýÿIÛýÿEÙýÿBØüÿ?Öüÿ<Õüÿ8Ôüÿ5Òüÿ2Ñüÿ.Ïûÿ+Îûÿ(Ìûÿ%Ëûÿ!ÊûÿÈûÿÇúÿÅúÿÄúÿÂúÿ Àø÷a~Y+ µ„Iض„Iÿ´ƒHÿ²Gÿ°€Fÿ¯~Eÿ­}Dÿ«{Cÿ©zBÿ§xAÿIuîÿÿuîÿÿsíÿÿpìÿÿmêÿÿjéþÿfèþÿcæþÿ_åþÿ\ãþÿYâþÿVàýÿSßýÿOÞýÿLÜýÿHÛýÿEÙýÿBØüÿ?Öüÿ<Õüÿ8Ôüÿ5Òüÿ2Ñüÿ.Ïûÿ+Îûÿ(Ìûÿ%Ëûÿ!ÊûÿÈûÿÇúÿÅúÿÄúÿÂúÿ £Ó“=³„K¹‡Kÿ·†Jÿ¶„Iÿ´‚Gÿ²Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨zAÿKsíÿ÷uîÿÿuîÿÿsíÿÿpìÿÿmêÿÿjéþÿfçþÿcæþÿ_åþÿ\ãþÿYâþÿVàýÿSßýÿOÝýÿLÜýÿHÛýÿEÙýÿBØüÿ?Öüÿ<Õüÿ8Óüÿ5Òüÿ2Ñüÿ.Ïûÿ+Îûÿ(Ìûÿ%Ëûÿ!ÉûÿÈûÿÇúÿÅúÿÄúÿ¾ôäJ¸…Hm»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ³‚Gÿ±Fÿ°Eÿ®~Dÿ¬|Cÿª{BÿS<YrêüØuîÿÿuîÿÿuîÿÿsíÿÿpìÿÿlêÿÿiéþÿfçþÿcæþÿ_åþÿ\ãþÿYâþÿUàýÿRßýÿOÝýÿLÜýÿHÛýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ5Òüÿ2Ñüÿ.Ïûÿ+Îûÿ'Ìûÿ$Ëûÿ!ÉûÿÈûÿÇúÿÅúÿÄúÿ yšc)º‰L¡¼‰LÿºˆKÿ¸†Jÿ¶…IÿµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|Cÿ‡_4ˆjÜî™uîÿÿuîÿÿuîÿÿuîÿÿsíÿÿoìÿÿlêÿÿiéþÿfçþÿcæþÿ_åþÿ\ãþÿYâþÿUàýÿRßýÿOÝýÿLÜýÿHÛýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ5Òüÿ2Ñüÿ.Ïûÿ+Îûÿ'Ìûÿ$Ëûÿ!ÉûÿÈûÿÇúÿÅúÿ§Õ’2¾ŠLؽŠMÿ»‰Lÿº‡Kÿ¸†Jÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ¯~Eÿ­}Dÿ¦wAÙPríýãuîÿÿuîÿÿuîÿÿuîÿÿsíÿÿoìÿÿlêÿÿiéþÿfçþÿcæþÿ_äþÿ\ãþÿYâþÿUàýÿRßýÿOÝýÿLÜýÿHÚýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ5Òüÿ1Ðüÿ.Ïûÿ+Îûÿ'Ìûÿ$Ëûÿ!ÉûÿÈûÿÆúÿ·é¶:½ŒNã¿‹Nÿ½ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ´‚Gÿ²Fÿ°Eÿ®~Dÿ¬|Cÿe7”Jœ§`ríýãuîÿÿuîÿÿuîÿÿuîÿÿsíÿÿoìÿÿlêÿÿiéþÿeçþÿbæþÿ_äþÿ\ãþÿYâþÿUàýÿRßýÿOÝýÿKÜýÿHÚýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ4Òüÿ1Ðüÿ.Ïûÿ+Îûÿ'Ìûÿ$Ëûÿ!ÉûÿÈûÿÁôÙ<ÂŽOÿÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¹†Jÿ·…IÿµƒHÿ³‚Gÿ±Fÿ¯Eÿ­~Dÿ¬|Cÿe7”<{†YjÚë›ríýãuîÿÿuîÿÿuîÿÿsíÿÿoìÿÿlêÿÿiéþÿeçþÿbæþÿ_äþÿ\ãþÿYâþÿUàýÿRßýÿNÝýÿKÜýÿHÚýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ4Òüÿ1Ðüÿ.Ïûÿ+Îûÿ'Ìûÿ$Ëûÿ!ÉûÿÃõÙ<ÃPÿÁOÿ¿ŒNÿ¾ŠMÿ¼‰Lÿº‡Kÿ¸†Jÿ¶…Iÿ´ƒHÿ²‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|Cÿ¤v?Ù…_4ˆQKIIIIIIIIIIIG9 ±YLÒî§MÛû÷KÜýÿHÚýÿEÙýÿBØüÿ>Öüÿ;Õüÿ8Óüÿ4Òüÿ1Ðüÿ.Ïûÿ+Îûÿ'Ìûÿ$ËûÿÄõÙ<ÅQÿÃŽPÿÁOÿ¿ŒNÿ½ŠMÿ»‰Lÿ¹‡Kÿ·†Jÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ®~Eÿ¬}Cÿ«{Bÿ©zAÿ§x@ÿ¥w?ÿ£u>ÿ¡t=ÿ r<ÿžq;ÿœo:ÿšn9ÿ˜l8ÿ–k7ÿ•i6ÿ”i6ÿ”i6ÿ‘f4äf4ÍuS)‡)vˆVLØøÌKÜýÿHÚýÿDÙýÿA×üÿ>Öüÿ;Õüÿ8Óüÿ4Òüÿ1Ðüÿ-Ïûÿ*Íûÿ'Ìûÿ"ÆõÙ9ÅP÷ÄQÿÂŽPÿÀOÿ¿‹Nÿ½ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ³‚Gÿ±Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¥v?ÿ£u>ÿ¡s=ÿŸr<ÿp;ÿ›o:ÿšm9ÿ˜l8ÿ–j7ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿŽe3ÎF2[JÕõÀKÜýÿHÚýÿDÙýÿA×üÿ>Öüÿ;Õüÿ8Óüÿ4Òüÿ1Ðûÿ-Ïûÿ*Íûÿ%ÆõÙ1Æ‘QØÅ‘QÿÄPÿÂŽOÿÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¹†Jÿ·…IÿµƒHÿ³‚Gÿ±Fÿ¯Eÿ­~Dÿ¬|Cÿª{Bÿ¨yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿŸq<ÿp;ÿ›o:ÿ™m9ÿ—l8ÿ•j7ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿŒc1Â-|ŽTMÛû÷KÜýÿHÚýÿDÙýÿA×üÿ>Öüÿ;Õüÿ7Óüÿ4Òüÿ1Ðûÿ-Ïûÿ%¾è©)Ç‘Q¯Ç’RÿÅQÿÃPÿÁOÿ¿ŒNÿ¾ŠMÿ¼‰Lÿº‡Kÿ¸†Jÿ¶…Iÿ´ƒHÿ²‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|Cÿ©zBÿ§yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿžq<ÿœp;ÿ›n:ÿ˜m8ÿ—k7ÿ•j6ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿmL'{KÐî˜NÝýÿKÜýÿHÚýÿDÙýÿA×üÿ=Öüÿ:Ôüÿ7Óüÿ4Òüÿ1Ðûÿ%µÛ!É”Q}È“SÿÆ‘RÿÄQÿÃŽPÿÁOÿ¿ŒNÿ½ŠMÿ»‰Lÿ¹‡Kÿ·†Jÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ®~Eÿ¬}Cÿ«{Bÿ©zAÿ§x@ÿ¥w?ÿ£u>ÿ¡t=ÿ r<ÿžq;ÿœo:ÿšn9ÿ˜l8ÿ–k7ÿ•i6ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿŒc1Â:¤µWQÞýÿNÝýÿKÜýÿHÚýÿDÙýÿA×üÿ=Öüÿ:Ôüÿ7Óüÿ4Òüÿ% ÃgÇM.É”SÿÇ“RÿÆ‘QÿÄPÿÂŽOÿÀNÿ¾‹Mÿ¼ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ³‚Gÿ±Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¥v?ÿ£u>ÿ¡s=ÿŸr<ÿp;ÿ›o:ÿšm9ÿ˜l8ÿ–j7ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿf3ÙFTàýÿQÞýÿNÝýÿKÜýÿGÚýÿDÙüÿA×üÿ=Öüÿ:Ôüÿ6Ñú÷6Ê“SãÉ”SÿÇ’RÿÅ‘QÿÃPÿÁŽOÿÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¸†Jÿ¶…IÿµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|CÿªzBÿ¨yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿŸq<ÿp;ÿ›o:ÿ™m9ÿ—l8ÿ•j7ÿ”i6ÿ”i6ÿ”i6ÿ”i6ÿIXáýÿTàýÿQÞýÿNÝýÿJÛýÿGÚýÿDÙüÿA×üÿ=Öüÿ7ËñÁ$Ì”S}Ê•TÿÈ“SÿÆ’RÿÅQÿÃPÿÁOÿ¿ŒNÿ½ŠMÿ»‰Lÿº‡Kÿ¸†Jÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ¯~Eÿ­}Dÿ«{Cÿ©zBÿ§xAÿ¥w@ÿ¤u?ÿ¢t>ÿ s=ÿžq<ÿœp:ÿšn9ÿ˜m8ÿ—k7ÿ•j6ÿ”i6ÿ”i6ÿ”i6ÿI[ãþÿXáýÿTàýÿQÞýÿNÝýÿJÛýÿGÚýÿDÙüÿA×üÿ3¹ÙnË•U½Ê”TÿÈ“SÿÆ‘RÿÄQÿÂŽPÿÀOÿ¿‹Nÿ½ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ´‚Gÿ²Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨zAÿ§x@ÿ¥w?ÿ£u>ÿ¡t=ÿŸr<ÿq;ÿœo:ÿšn9ÿ˜l8ÿ–k7ÿ”i6ÿ”i6ÿ”i6ÿI^äþÿ[ãþÿXáýÿTàýÿQÞýÿNÝýÿJÛýÿGÚýÿBÕ÷ØÊ”S½É”SÿÇ“RÿÆ‘QÿÄPÿÂŽOÿÀNÿ¾‹Mÿ¼ŠLÿ»ˆKÿ¹‡Jÿ·…IÿµƒHÿ³‚Gÿ±Fÿ¯Eÿ­~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¤v?ÿ¢u>ÿ¡s=ÿŸr<ÿp;ÿ›o:ÿ™m9ÿ—l8ÿ–j7ÿ”i6ÿ”i6ÿIaåþÿ^äþÿZâþÿWáýÿTàýÿQÞýÿNÝýÿIØûã;½Û+Å’SYÈ“RÌÆP÷Å‘QÿÃPÿÁŽOÿÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¸†Jÿ¶…IÿµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|Cÿ©zBÿ§yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿžq<ÿœp;ÿ›n:ÿ™m9ÿ—k8ÿ•j7ÿ”i6ÿIdçþÿaåþÿ^äþÿZâþÿWáýÿRÞü÷OÚù±EÈç!7IIIIIIIIII§xAÿ¥w@ÿ¤u?ÿ¢t>ÿ s=ÿžq<ÿœo:ÿšn9ÿ˜l8ÿ–k7ÿ•i6ÿI¿‹Nÿ½ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ´‚Gÿ²Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨zAÿ§x@ÿ¥w?ÿ£u>ÿ¡t=ÿŸr<ÿq;ÿœo:ÿšn9ÿ˜l8ÿ–k7ÿIÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¹†Jÿ·…IÿµƒHÿ³‚Gÿ±Fÿ¯Eÿ­~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¤v?ÿ¢u>ÿ¡s=ÿŸr<ÿp;ÿ›o:ÿ™m9ÿ—l8ÿIÁOÿ¿ŒNÿ¾ŠMÿ¼‰Lÿº‡Kÿ¸†Jÿ¶…Iÿ´ƒHÿ²‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|Cÿ©zBÿ§yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿžq<ÿœp;ÿ›n:ÿ™m9ÿIÃŽPÿÁOÿ¿ŒNÿŘcÿá˰ÿåÒ»ÿÀ•`ÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ®~Eÿ¬}Cÿ«{Bÿ©zAÿ§x@ÿ¥w?ÿ£u>ÿ¡t=ÿ r<ÿžq;ÿœo:ÿšn9ÿGÄPÿÂŽOÿÀNÿ÷ðéÿÿÿÿÿÿÿÿÿöðèÿ·…Iÿµ„Hÿ³‚Gÿ±Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¥v?ÿ£u>ÿ¡s=ÿŸr<ÿp;ÿ›o:ÿ?ÄO÷ÄPÿÂŽOÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁ•aÿ¶…IÿµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|CÿªzBÿ¨yAÿ¦w@ÿ¤v?ÿ¢t>ÿ s=ÿŸq<ÿ›n9ã2 Ç‘Q×ÅQÿÃPÿïâÓÿÿÿÿÿÿÿÿÿòéÝÿº‡Kÿ¸†Jÿ¶…Iÿ´ƒHÿ²‚Gÿ±€Fÿ¯Eÿ­}Dÿ«{Cÿ©zBÿ§xAÿ¥w@ÿ¤u?ÿ¢t>ÿ s=ÿ—l8ÁÇRÆ‘RÿÄQÿÇ•[ÿÜ¿œÿ߯§ÿÁ‘Xÿ»‰Lÿ¹‡Kÿ·†Jÿ¶„Iÿ´ƒHÿ²Gÿ°€Fÿ®~Eÿ¬}Cÿ«{Bÿ©zAÿ§x@ÿ¥w?ÿ£u>ÿ r<÷†^3F Ç›XÅ’PãÆ‘QÿÄPÿÂŽOÿÀNÿ¾‹Mÿ¼ŠLÿ»ˆKÿ¹‡Jÿ·…Iÿµ„Hÿ³‚Gÿ±Fÿ°Eÿ®~Dÿ¬|Cÿª{Bÿ¨yAÿ¦x@ÿ¤t>÷”j7e Ç›XÅ‘Q ÄO÷ÃPÿÁŽOÿÀŒNÿ¾‹Mÿ¼‰LÿºˆKÿ¸†Jÿ¶…IÿµƒHÿ³‚Gÿ±€Fÿ¯Eÿ­}Dÿ«|CÿªzBÿ¥w?Øn v documentation". html_title = "{project} {version} documentation".format(**locals()) # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = 'logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '_static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { 'index': 'indexsidebar.html', '**': ['globaltoc.html', 'relations.html', 'sourcelink.html', 'searchbox.html'] } # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = { # 'index': 'indexcontent.html', # } # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = '%s-doc' % PROJECT_NAME # -- Options for LaTeX output ------------------------------------------------ # The paper size ('letter' or 'a4'). # latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). # latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ('index', '%s.tex' % PROJECT_NAME, '%s documentation' % PROJECT_NAME, AUTHOR), ] # The name of an image file (relative to this directory) to place at # the top of the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Additional stuff for the LaTeX preamble. # latex_preamble = '' # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', PROJECT_NAME, '%s documentation' % PROJECT_NAME, [AUTHOR], 1) ] # If true, show URL addresses after external links. # man_show_urls = False psutil-3.4.2/.travis.yml0000664000175000017500000000106212600236266017117 0ustar giampaologiampaolo00000000000000sudo: false language: python matrix: include: - python: 2.6 - python: 2.7 - python: 3.3 - python: 3.4 - language: generic os: osx env: PYVER=py26 - language: generic os: osx env: PYVER=py27 - language: generic os: osx env: PYVER=py33 - language: generic os: osx env: PYVER=py34 install: - ./.ci/travis/install.sh script: - ./.ci/travis/run.sh after_success: - coveralls # upload reports to coveralls.io psutil-3.4.2/INSTALL.rst0000664000175000017500000000625612572074510016660 0ustar giampaologiampaolo00000000000000============================ Installing using pip on UNIX ============================ The easiest way to install psutil on UNIX is by using pip (but first you might need to install python header files; see later). First install pip:: $ wget https://bootstrap.pypa.io/get-pip.py $ python get-pip.py ...then run:: $ pip install psutil You may need to install gcc and python header files first (see later). ===================== Installing on Windows ===================== Just get the right installer for your Python version and architecture from: https://pypi.python.org/pypi/psutil/#downloads Since wheels installers are also available you may also use pip. ======================================== Compiling on Windows using Visual Studio ======================================== In order to compile psutil on Windows you'll need Visual Studio (Mingw32 is no longer supported). You must have the same version of Visual Studio used to compile your installation of Python, that is:: * Python 2.6: VS 2008 (download it from `here `_) * Python 2.7: VS 2008 (download it from `here `_) * Python 3.3, 3.4: VS 2010 (you can download it from `MS website `_) * Python 3.5: `VS 2015 UP `_ ...then run:: setup.py build ...or:: make.bat build Compiling 64 bit versions of Python 2.6 and 2.7 with VS 2008 requires Windows SDK and .NET Framework 3.5 SP1 to be installed first. Once you have those run vcvars64.bat, then compile: http://stackoverflow.com/questions/11072521/ =================== 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 Debian and Ubuntu:: $ sudo apt-get install gcc python-dev ...on Redhat and CentOS:: $ sudo yum install gcc python-devel Once done, you can build/install psutil with:: $ python setup.py install ================== 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 ===================== 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 ======== Makefile ======== A makefile is available for both UNIX and Windows (make.bat). It provides some automations for the tasks described above and might be preferred over using setup.py. With it you can:: $ make install # just install (in --user mode) $ make uninstall # uninstall (needs pip) $ make test # run tests $ make clean # remove installation files psutil-3.4.2/psutil.egg-info/0000775000175000017500000000000012647732502020026 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil.egg-info/PKG-INFO0000664000175000017500000005577512647732502021146 0ustar giampaologiampaolo00000000000000Metadata-Version: 1.1 Name: psutil Version: 3.4.2 Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python. Home-page: https://github.com/giampaolo/psutil Author: Giampaolo Rodola Author-email: g.rodola gmail com License: BSD Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg :target: https://pypi.python.org/pypi/psutil#downloads :alt: Downloads this month .. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master :target: https://travis-ci.org/giampaolo/psutil :alt: Linux tests (Travis) .. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true :target: https://ci.appveyor.com/project/giampaolo/psutil :alt: Windows tests (Appveyor) .. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github :target: https://coveralls.io/github/giampaolo/psutil?branch=master :alt: Test coverage (coverall.io) .. image:: https://img.shields.io/pypi/v/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: Latest version .. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg :target: https://github.com/giampaolo/psutil/ :alt: Github stars .. image:: https://img.shields.io/pypi/l/psutil.svg :target: https://pypi.python.org/pypi/psutil/ :alt: License =========== Quick links =========== - `Home page `_ - `Documentation `_ - `Installation `_ - `Download `_ - `Forum `_ - `Blog `_ - `Development guide `_ - `What's new `_ ======= Summary ======= psutil (python system and process utilities) is a cross-platform library for retrieving information on **running processes** and **system utilization** (CPU, memory, disks, network) in Python. It is useful mainly for **system monitoring**, **profiling and limiting process resources** and **management of running processes**. It implements many functionalities offered by command line tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports **Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD** and **NetBSD**, both **32-bit** and **64-bit** architectures, with Python versions from **2.6 to 3.5** (users of Python 2.4 and 2.5 may use `2.1.3 `__ version). `PyPy `__ is also known to work. ==================== Example applications ==================== .. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/top.png :alt: top .. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/nettop.png :alt: nettop .. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png :target: http://psutil.googlecode.com/svn/wiki/images/iotop.png :alt: iotop See also: * https://github.com/nicolargo/glances * https://github.com/google/grr * https://github.com/Jahaja/psdash ============== Example usages ============== CPU === .. code-block:: python >>> import psutil >>> psutil.cpu_times() scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0) >>> >>> 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, 3.7, 9.2] [7.0, 8.5, 2.4, 2.1] [1.2, 9.0, 9.9, 7.2] >>> >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) >>> >>> psutil.cpu_count() 4 >>> psutil.cpu_count(logical=False) 2 >>> Memory ====== .. code-block:: python >>> psutil.virtual_memory() svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336) >>> psutil.swap_memory() sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== .. code-block:: python >>> psutil.disk_partitions() [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= .. code-block:: python >>> psutil.net_io_counters(pernic=True) {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> >>> psutil.net_connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None), pconn(fd=-1, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None) ...] >>> >>> psutil.net_if_addrs() {'lo': [snic(family=, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None), snic(family=, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None), snic(family=, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)], 'wlan0': [snic(family=, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None), snic(family=, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None), snic(family=, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]} >>> >>> psutil.net_if_stats() {'eth0': snicstats(isup=True, duplex=, speed=100, mtu=1500), 'lo': snicstats(isup=True, duplex=, speed=0, mtu=65536)} Other system info ================= .. code-block:: python >>> psutil.users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.boot_time() 1365519115.0 >>> Process management ================== .. code-block:: python >>> import psutil >>> psutil.pids() [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.cwd() '/home/giampaolo' >>> p.cmdline() ['/usr/bin/python', 'main.py'] >>> >>> p.status() 'running' >>> p.username() 'giampaolo' >>> p.create_time() 1267551141.5019531 >>> p.terminal() '/dev/pts/0' >>> >>> p.uids() puids(real=1000, effective=1000, saved=1000) >>> p.gids() pgids(real=1000, effective=1000, saved=1000) >>> >>> p.cpu_times() pcputimes(user=1.02, system=0.31) >>> p.cpu_percent(interval=1.0) 12.1 >>> p.cpu_affinity() [0, 1, 2, 3] >>> p.cpu_affinity([0]) # set >>> >>> p.memory_percent() 0.63423 >>> >>> p.memory_info() pmem(rss=7471104, vms=68513792) >>> p.memory_info_ex() extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.memory_maps() [pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0), pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.io_counters() pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.open_files() [popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.connections() [pconn(fd=115, family=, type=, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), pconn(fd=117, family=, type=, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), pconn(fd=119, family=, type=, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), pconn(fd=123, family=, type=, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.num_threads() 4 >>> p.num_fds() 8 >>> p.threads() [pthread(id=5234, user_time=22.5, system_time=9.2891), pthread(id=5235, user_time=0.0, system_time=0.0), pthread(id=5236, user_time=0.0, system_time=0.0), pthread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.num_ctx_switches() pctxsw(voluntary=78, involuntary=19) >>> >>> p.nice() 0 >>> p.nice(10) # set >>> >>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only) >>> p.ionice() pionice(ioclass=, value=0) >>> >>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only) >>> p.rlimit(psutil.RLIMIT_NOFILE) (5, 5) >>> >>> 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 >>> Further process APIs ==================== .. code-block:: python >>> for p in psutil.process_iter(): ... print(p) ... psutil.Process(pid=1, name='init') psutil.Process(pid=2, name='kthreadd') psutil.Process(pid=3, name='ksoftirqd/0') ... >>> >>> def on_terminate(proc): ... print("process {} terminated".format(proc)) ... >>> # waits for multiple processes to terminate >>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate) >>> ====== Donate ====== A lot of time and effort went into making psutil as it is right now. If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' `_) some money. I only ask for a small donation, but of course I appreciate any amount. .. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif :target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8 :alt: Donate via PayPal Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin `_. ============ Mailing list ============ http://groups.google.com/group/psutil/ ======== Timeline ======== - 2016-01-20: `psutil-3.4.2.tar.gz `_ - 2016-01-15: `psutil-3.4.1.tar.gz `_ - 2015-11-25: `psutil-3.3.0.tar.gz `_ - 2015-10-04: `psutil-3.2.2.tar.gz `_ - 2015-09-03: `psutil-3.2.1.tar.gz `_ - 2015-09-02: `psutil-3.2.0.tar.gz `_ - 2015-07-15: `psutil-3.1.1.tar.gz `_ - 2015-07-15: `psutil-3.1.0.tar.gz `_ - 2015-06-18: `psutil-3.0.1.tar.gz `_ - 2015-06-13: `psutil-3.0.0.tar.gz `_ - 2015-02-02: `psutil-2.2.1.tar.gz `_ - 2015-01-06: `psutil-2.2.0.tar.gz `_ - 2014-09-26: `psutil-2.1.3.tar.gz `_ - 2014-09-21: `psutil-2.1.2.tar.gz `_ - 2014-04-30: `psutil-2.1.1.tar.gz `_ - 2014-04-08: `psutil-2.1.0.tar.gz `_ - 2014-03-10: `psutil-2.0.0.tar.gz `_ - 2013-11-25: `psutil-1.2.1.tar.gz `_ - 2013-11-20: `psutil-1.2.0.tar.gz `_ - 2013-11-07: `psutil-1.1.3.tar.gz `_ - 2013-10-22: `psutil-1.1.2.tar.gz `_ - 2013-10-08: `psutil-1.1.1.tar.gz `_ - 2013-09-28: `psutil-1.1.0.tar.gz `_ - 2013-07-12: `psutil-1.0.1.tar.gz `_ - 2013-07-10: `psutil-1.0.0.tar.gz `_ - 2013-05-03: `psutil-0.7.1.tar.gz `_ - 2013-04-12: `psutil-0.7.0.tar.gz `_ - 2012-08-16: `psutil-0.6.1.tar.gz `_ - 2012-08-13: `psutil-0.6.0.tar.gz `_ - 2012-06-29: `psutil-0.5.1.tar.gz `_ - 2012-06-27: `psutil-0.5.0.tar.gz `_ - 2011-12-14: `psutil-0.4.1.tar.gz `_ - 2011-10-29: `psutil-0.4.0.tar.gz `_ - 2011-07-08: `psutil-0.3.0.tar.gz `_ - 2011-03-20: `psutil-0.2.1.tar.gz `_ - 2010-11-13: `psutil-0.2.0.tar.gz `_ - 2010-03-02: `psutil-0.1.3.tar.gz `_ - 2009-05-06: `psutil-0.1.2.tar.gz `_ - 2009-03-06: `psutil-0.1.1.tar.gz `_ - 2009-01-27: `psutil-0.1.0.tar.gz `_ Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit Platform: Platform Independent Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Environment :: Win32 (MS Windows) Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000 Classifier: Operating System :: Microsoft Classifier: Operating System :: OS Independent Classifier: Operating System :: POSIX :: BSD :: FreeBSD Classifier: Operating System :: POSIX :: BSD :: NetBSD Classifier: Operating System :: POSIX :: BSD :: OpenBSD Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: SunOS/Solaris Classifier: Operating System :: POSIX Classifier: Programming Language :: C Classifier: Programming Language :: Python :: 2 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: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: System :: Benchmark Classifier: Topic :: System :: Hardware Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking :: Monitoring Classifier: Topic :: System :: Networking Classifier: Topic :: System :: Operating System Classifier: Topic :: System :: Systems Administration Classifier: Topic :: Utilities psutil-3.4.2/psutil.egg-info/SOURCES.txt0000664000175000017500000000465712647732502021726 0ustar giampaologiampaolo00000000000000.coveragerc .git-pre-commit .gitignore .travis.yml CREDITS DEVNOTES.rst HISTORY.rst INSTALL.rst LICENSE MANIFEST.in Makefile README.rst TODO appveyor.yml make.bat setup.py tox.ini .ci/README .ci/appveyor/README .ci/appveyor/install.ps1 .ci/appveyor/run_with_compiler.cmd .ci/travis/README .ci/travis/install.sh .ci/travis/run.sh docs/Makefile docs/README docs/conf.py docs/index.rst docs/make.bat docs/_static/copybutton.js docs/_static/favicon.ico docs/_static/logo.png docs/_static/sidebar.js docs/_template/globaltoc.html docs/_template/indexcontent.html docs/_template/indexsidebar.html docs/_template/page.html docs/_themes/pydoctheme/theme.conf docs/_themes/pydoctheme/static/pydoctheme.css examples/disk_usage.py examples/free.py examples/ifconfig.py examples/iotop.py examples/killall.py examples/meminfo.py examples/netstat.py examples/nettop.py examples/pidof.py examples/pmap.py examples/process_detail.py examples/ps.py examples/pstree.py examples/top.py examples/who.py psutil/__init__.py psutil/_common.py psutil/_compat.py psutil/_psbsd.py psutil/_pslinux.py psutil/_psosx.py psutil/_psposix.py psutil/_pssunos.py psutil/_psutil_bsd.c psutil/_psutil_bsd.h psutil/_psutil_common.c psutil/_psutil_common.h psutil/_psutil_linux.c psutil/_psutil_linux.h psutil/_psutil_osx.c psutil/_psutil_osx.h psutil/_psutil_posix.c psutil/_psutil_posix.h psutil/_psutil_sunos.c psutil/_psutil_sunos.h psutil/_psutil_windows.c psutil/_psutil_windows.h psutil/_pswindows.py psutil.egg-info/PKG-INFO psutil.egg-info/SOURCES.txt psutil.egg-info/dependency_links.txt psutil.egg-info/top_level.txt psutil/arch/bsd/freebsd.c psutil/arch/bsd/freebsd.h psutil/arch/bsd/freebsd_socks.c psutil/arch/bsd/freebsd_socks.h psutil/arch/bsd/netbsd.c psutil/arch/bsd/netbsd.h psutil/arch/bsd/netbsd_socks.c psutil/arch/bsd/netbsd_socks.h psutil/arch/bsd/openbsd.c psutil/arch/bsd/openbsd.h psutil/arch/osx/process_info.c psutil/arch/osx/process_info.h psutil/arch/solaris/v10/ifaddrs.c psutil/arch/solaris/v10/ifaddrs.h psutil/arch/windows/glpi.h psutil/arch/windows/inet_ntop.c psutil/arch/windows/inet_ntop.h psutil/arch/windows/ntextapi.h psutil/arch/windows/process_handles.c psutil/arch/windows/process_handles.h psutil/arch/windows/process_info.c psutil/arch/windows/process_info.h psutil/arch/windows/security.c psutil/arch/windows/security.h test/README.rst test/_bsd.py test/_linux.py test/_osx.py test/_posix.py test/_sunos.py test/_windows.py test/test_memory_leaks.py test/test_psutil.pypsutil-3.4.2/psutil.egg-info/top_level.txt0000664000175000017500000000000712647732502022555 0ustar giampaologiampaolo00000000000000psutil psutil-3.4.2/psutil.egg-info/dependency_links.txt0000664000175000017500000000000112647732502024074 0ustar giampaologiampaolo00000000000000 psutil-3.4.2/HISTORY.rst0000664000175000017500000012337612647732375016733 0ustar giampaologiampaolo00000000000000Bug tracker at https://github.com/giampaolo/psutil/issues 3.4.2 - 2016-01-20 ================== **Enhancements** - #728: [Solaris] exposed psutil.PROCFS_PATH constant to change the default location of /proc filesystem. **Bug fixes** - #730: [FreeBSD] psutil.virtual_memory() crashes. 3.4.1 - 2016-01-15 ================== **Enhancements** - #557: [NetBSD] added NetBSD support. (contributed by Ryo Onodera and Thomas Klausner) - #708: [Linux] psutil.net_connections() and Process.connections() on Python 2 can be up to 3x faster in case of many connections. Also psutil.Process.memory_maps() is slightly faster. - #718: process_iter() is now thread safe. **Bug fixes** - #714: [OpenBSD] virtual_memory().cached value was always set to 0. - #715: don't crash at import time if cpu_times() fail for some reason. - #717: [Linux] Process.open_files fails if deleted files still visible. - #722: [Linux] swap_memory() no longer crashes if sin/sout can't be determined due to missing /proc/vmstat. - #724: [FreeBSD] virtual_memory().total is slightly incorrect. 3.3.0 - 2015-11-25 ================== **Enhancements** - #558: [Linux] exposed psutil.PROCFS_PATH constant to change the default location of /proc filesystem. - #615: [OpenBSD] added OpenBSD support. (contributed by Landry Breuil) **Bug fixes** - #692: [UNIX] Process.name() is no longer cached as it may change. 3.2.2 - 2015-10-04 ================== **Bug fixes** - #517: [SunOS] net_io_counters failed to detect network interfaces correctly on Solaris 10 - #541: [FreeBSD] disk_io_counters r/w times were expressed in seconds instead of milliseconds. (patch by dasumin) - #610: [SunOS] fix build and tests on Solaris 10 - #623: [Linux] process or system connections raises ValueError if IPv6 is not supported by the system. - #678: [Linux] can't install psutil due to bug in setup.py. - #688: [Windows] compilation fails with MSVC 2015, Python 3.5. (patch by Mike Sarahan) 3.2.1 - 2015-09-03 ================== **Bug fixes** - #677: [Linux] can't install psutil due to bug in setup.py. 3.2.0 - 2015-09-02 ================== **Enhancements** - #644: [Windows] added support for CTRL_C_EVENT and CTRL_BREAK_EVENT signals to use with Process.send_signal(). - #648: CI test integration for OSX. (patch by Jeff Tang) - #663: [UNIX] net_if_addrs() now returns point-to-point (VPNs) addresses. - #655: [Windows] different issues regarding unicode handling were fixed. On Python 2 all APIs returning a string will now return an encoded version of it by using sys.getfilesystemencoding() codec. The APIs involved are: - psutil.net_if_addrs() - psutil.net_if_stats() - psutil.net_io_counters() - psutil.Process.cmdline() - psutil.Process.name() - psutil.Process.username() - psutil.users() **Bug fixes** - #513: [Linux] fixed integer overflow for RLIM_INFINITY. - #641: [Windows] fixed many compilation warnings. (patch by Jeff Tang) - #652: [Windows] net_if_addrs() UnicodeDecodeError in case of non-ASCII NIC names. - #655: [Windows] net_if_stats() UnicodeDecodeError in case of non-ASCII NIC names. - #659: [Linux] compilation error on Suse 10. (patch by maozguttman) - #664: [Linux] compilation error on Alpine Linux. (patch by Bart van Kleef) - #670: [Windows] segfgault of net_if_addrs() in case of non-ASCII NIC names. (patch by sk6249) - #672: [Windows] compilation fails if using Windows SDK v8.0. (patch by Steven Winfield) - #675: [Linux] net_connections(); UnicodeDecodeError may occur when listing UNIX sockets. 3.1.1 - 2015-07-15 ================== **Bug fixes** - #603: [Linux] ionice_set value range is incorrect. (patch by spacewander) - #645: [Linux] psutil.cpu_times_percent() may produce negative results. - #656: 'from psutil import *' does not work. 3.1.0 - 2015-07-15 ================== **Enhancements** - #534: [Linux] disk_partitions() added support for ZFS filesystems. - #646: continuous tests integration for Windows with https://ci.appveyor.com/project/giampaolo/psutil. - #647: new dev guide: https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst - #651: continuous code quality test integration with https://scrutinizer-ci.com/g/giampaolo/psutil/ **Bug fixes** - #340: [Windows] Process.open_files() no longer hangs. Instead it uses a thred which times out and skips the file handle in case it's taking too long to be retrieved. (patch by Jeff Tang, PR #597) - #627: [Windows] Process.name() no longer raises AccessDenied for pids owned by another user. - #636: [Windows] Process.memory_info() raise AccessDenied. - #637: [UNIX] raise exception if trying to send signal to Process PID 0 as it will affect os.getpid()'s process group instead of PID 0. - #639: [Linux] Process.cmdline() can be truncated. - #640: [Linux] *connections functions may swallow errors and return an incomplete list of connnections. - #642: repr() of exceptions is incorrect. - #653: [Windows] Add inet_ntop function for Windows XP to support IPv6. - #641: [Windows] Replace deprecated string functions with safe equivalents. 3.0.1 - 2015-06-18 ================== **Bug fixes** - #632: [Linux] better error message if cannot parse process UNIX connections. - #634: [Linux] Proces.cmdline() does not include empty string arguments. - #635: [UNIX] crash on module import if 'enum' package is installed on python < 3.4. 3.0.0 - 2015-06-13 ================== **Enhancements** - #250: new psutil.net_if_stats() returning NIC statistics (isup, duplex, speed, MTU). - #376: new psutil.net_if_addrs() returning all NIC addresses a-la ifconfig. - #469: on Python >= 3.4 ``IOPRIO_CLASS_*`` and ``*_PRIORITY_CLASS`` constants returned by psutil.Process' ionice() and nice() methods are enums instead of plain integers. - #581: add .gitignore. (patch by Gabi Davar) - #582: connection constants returned by psutil.net_connections() and psutil.Process.connections() were turned from int to enums on Python > 3.4. - #587: Move native extension into the package. - #589: Process.cpu_affinity() accepts any kind of iterable (set, tuple, ...), not only lists. - #594: all deprecated APIs were removed. - #599: [Windows] process name() can now be determined for all processes even when running as a limited user. - #602: pre-commit GIT hook. - #629: enhanced support for py.test and nose test discovery and tests run. - #616: [Windows] Add inet_ntop function for Windows XP. **Bug fixes** - #428: [all UNIXes except Linux] correct handling of zombie processes; introduced new ZombieProcess exception class. - #512: [BSD] fix segfault in net_connections(). - #555: [Linux] psutil.users() correctly handles ":0" as an alias for "localhost" - #579: [Windows] Fixed open_files() for PID>64K. - #579: [Windows] fixed many compiler warnings. - #585: [FreeBSD] net_connections() may raise KeyError. - #586: [FreeBSD] cpu_affinity() segfaults on set in case an invalid CPU number is provided. - #593: [FreeBSD] Process().memory_maps() segfaults. - #606: Process.parent() may swallow NoSuchProcess exceptions. - #611: [SunOS] net_io_counters has send and received swapped - #614: [Linux]: cpu_count(logical=False) return the number of physical CPUs instead of physical cores. - #618: [SunOS] swap tests fail on Solaris when run as normal user - #628: [Linux] Process.name() truncates process name in case it contains spaces or parentheses. 2.2.1 - 2015-02-02 ================== **Bug fixes** - #496: [Linux] fix "ValueError: ambiguos inode with multiple PIDs references" (patch by Bruno Binet) 2.2.0 - 2015-01-06 ================== **Enhancements** - #521: drop support for Python 2.4 and 2.5. - #553: new examples/pstree.py script. - #564: C extension version mismatch in case the user messed up with psutil installation or with sys.path is now detected at import time. - #568: New examples/pidof.py script. - #569: [FreeBSD] add support for process CPU affinity. **Bug fixes** - #496: [Solaris] can't import psutil. - #547: [UNIX] Process.username() may raise KeyError if UID can't be resolved. - #551: [Windows] get rid of the unicode hack for net_io_counters() NIC names. - #556: [Linux] lots of file handles were left open. - #561: [Linux] net_connections() might skip some legitimate UNIX sockets. (patch by spacewander) - #565: [Windows] use proper encoding for psutil.Process.username() and psutil.users(). (patch by Sylvain Mouquet) - #567: [Linux] in the alternative implementation of CPU affinity PyList_Append and Py_BuildValue return values are not checked. - #569: [FreeBSD] fix memory leak in psutil.cpu_count(logical=False). - #571: [Linux] Process.open_files() might swallow AccessDenied exceptions and return an incomplete list of open files. 2.1.3 - 2014-09-26 ================== - #536: [Linux]: fix "undefined symbol: CPU_ALLOC" compilation error. 2.1.2 - 2014-09-21 ================== **Enhancements** - #407: project moved from Google Code to Github; code moved from Mercurial to Git. - #492: use tox to run tests on multiple python versions. (patch by msabramo) - #505: [Windows] distribution as wheel packages. - #511: new examples/ps.py sample code. **Bug fixes** - #340: [Windows] Process.get_open_files() no longer hangs. (patch by Jeff Tang) - #501: [Windows] disk_io_counters() may return negative values. - #503: [Linux] in rare conditions Process exe(), open_files() and connections() methods can raise OSError(ESRCH) instead of NoSuchProcess. - #504: [Linux] can't build RPM packages via setup.py - #506: [Linux] python 2.4 support was broken. - #522: [Linux] Process.cpu_affinity() might return EINVAL. (patch by David Daeschler) - #529: [Windows] Process.exe() may raise unhandled WindowsError exception for PIDs 0 and 4. (patch by Jeff Tang) - #530: [Linux] psutil.disk_io_counters() may crash on old Linux distros (< 2.6.5) (patch by Yaolong Huang) - #533: [Linux] Process.memory_maps() may raise TypeError on old Linux distros. 2.1.1 - 2014-04-30 ================== **Bug fixes** - #446: [Windows] fix encoding error when using net_io_counters() on Python 3. (patch by Szigeti Gabor Niif) - #460: [Windows] net_io_counters() wraps after 4G. - #491: [Linux] psutil.net_connections() exceptions. (patch by Alexander Grothe) 2.1.0 - 2014-04-08 ================== **Enhancements** - #387: system-wide open connections a-la netstat. **Bug fixes** - #421: [Solaris] psutil does not compile on SunOS 5.10 (patch by Naveed Roudsari) - #489: [Linux] psutil.disk_partitions() return an empty list. 2.0.0 - 2014-03-10 ================== **Enhancements** - #424: [Windows] installer for Python 3.X 64 bit. - #427: number of logical and physical CPUs (psutil.cpu_count()). - #447: psutil.wait_procs() timeout parameter is now optional. - #452: make Process instances hashable and usable with set()s. - #453: tests on Python < 2.7 require unittest2 module. - #459: add a make file for running tests and other repetitive tasks (also on Windows). - #463: make timeout parameter of cpu_percent* functions default to 0.0 'cause it's a common trap to introduce slowdowns. - #468: move documentation to readthedocs.com. - #477: process cpu_percent() is about 30% faster. (suggested by crusaderky) - #478: [Linux] almost all APIs are about 30% faster on Python 3.X. - #479: long deprecated psutil.error module is gone; exception classes now live in "psutil" namespace only. **Bug fixes** - #193: psutil.Popen constructor can throw an exception if the spawned process terminates quickly. - #340: [Windows] process get_open_files() no longer hangs. (patch by jtang@vahna.net) - #443: [Linux] fix a potential overflow issue for Process.set_cpu_affinity() on systems with more than 64 CPUs. - #448: [Windows] get_children() and ppid() memory leak (patch by Ulrich Klank). - #457: [POSIX] pid_exists() always returns True for PID 0. - #461: namedtuples are not pickle-able. - #466: [Linux] process exe improper null bytes handling. (patch by Gautam Singh) - #470: wait_procs() might not wait. (patch by crusaderky) - #471: [Windows] process exe improper unicode handling. (patch by alex@mroja.net) - #473: psutil.Popen.wait() does not set returncode attribute. - #474: [Windows] Process.cpu_percent() is no longer capped at 100%. - #476: [Linux] encoding error for process name and cmdline. **API changes** For the sake of consistency a lot of psutil APIs have been renamed. In most cases accessing the old names will work but it will cause a DeprecationWarning. - psutil.* module level constants have being replaced by functions: +-----------------------+-------------------------------+ | Old name | Replacement | +=======================+===============================+ | psutil.NUM_CPUS | psutil.cpu_cpunt() | +-----------------------+-------------------------------+ | psutil.BOOT_TIME | psutil.boot_time() | +-----------------------+-------------------------------+ | psutil.TOTAL_PHYMEM | psutil.virtual_memory().total | +-----------------------+-------------------------------+ - Renamed psutil.* functions: +--------------------------+-------------------------------+ | Old name | Replacement | +==========================+===============================+ | - psutil.get_pid_list() | psutil.pids() | +--------------------------+-------------------------------+ | - psutil.get_users() | psutil.users() | +--------------------------+-------------------------------+ | - psutil.get_boot_time() | psutil.boot_time() | +--------------------------+-------------------------------+ - All psutil.Process ``get_*`` methods lost the ``get_`` prefix. get_ext_memory_info() renamed to memory_info_ex(). Assuming "p = psutil.Process()": +--------------------------+----------------------+ | Old name | Replacement | +==========================+======================+ | p.get_children() | p.children() | +--------------------------+----------------------+ | p.get_connections() | p.connections() | +--------------------------+----------------------+ | p.get_cpu_affinity() | p.cpu_affinity() | +--------------------------+----------------------+ | p.get_cpu_percent() | p.cpu_percent() | +--------------------------+----------------------+ | p.get_cpu_times() | p.cpu_times() | +--------------------------+----------------------+ | p.get_ext_memory_info() | p.memory_info_ex() | +--------------------------+----------------------+ | p.get_io_counters() | p.io_counters() | +--------------------------+----------------------+ | p.get_ionice() | p.ionice() | +--------------------------+----------------------+ | p.get_memory_info() | p.memory_info() | +--------------------------+----------------------+ | p.get_memory_maps() | p.memory_maps() | +--------------------------+----------------------+ | p.get_memory_percent() | p.memory_percent() | +--------------------------+----------------------+ | p.get_nice() | p.nice() | +--------------------------+----------------------+ | p.get_num_ctx_switches() | p.num_ctx_switches() | +--------------------------+----------------------+ | p.get_num_fds() | p.num_fds() | +--------------------------+----------------------+ | p.get_num_threads() | p.num_threads() | +--------------------------+----------------------+ | p.get_open_files() | p.open_files() | +--------------------------+----------------------+ | p.get_rlimit() | p.rlimit() | +--------------------------+----------------------+ | p.get_threads() | p.threads() | +--------------------------+----------------------+ | p.getcwd() | p.cwd() | +--------------------------+----------------------+ - All psutil.Process ``set_*`` methods lost the ``set_`` prefix. Assuming "p = psutil.Process()": +----------------------+---------------------------------+ | Old name | Replacement | +======================+=================================+ | p.set_nice() | p.nice(value) | +----------------------+---------------------------------+ | p.set_ionice() | p.ionice(ioclass, value=None) | +----------------------+---------------------------------+ | p.set_cpu_affinity() | p.cpu_affinity(cpus) | +----------------------+---------------------------------+ | p.set_rlimit() | p.rlimit(resource, limits=None) | +----------------------+---------------------------------+ - Except for 'pid' all psutil.Process class properties have been turned into methods. This is the only case which there are no aliases. Assuming "p = psutil.Process()": +---------------+-----------------+ | Old name | Replacement | +===============+=================+ | p.name | p.name() | +---------------+-----------------+ | p.parent | p.parent() | +---------------+-----------------+ | p.ppid | p.ppid() | +---------------+-----------------+ | p.exe | p.exe() | +---------------+-----------------+ | p.cmdline | p.cmdline() | +---------------+-----------------+ | p.status | p.status() | +---------------+-----------------+ | p.uids | p.uids() | +---------------+-----------------+ | p.gids | p.gids() | +---------------+-----------------+ | p.username | p.username() | +---------------+-----------------+ | p.create_time | p.create_time() | +---------------+-----------------+ - timeout parameter of cpu_percent* functions defaults to 0.0 instead of 0.1. - long deprecated psutil.error module is gone; exception classes now live in "psutil" namespace only. - Process instances' "retcode" attribute returned by psutil.wait_procs() has been renamed to "returncode" for consistency with subprocess.Popen. 1.2.1 - 2013-11-25 ================== **Bug fixes** - #348: [Windows XP] fixed "ImportError: DLL load failed" occurring on module import. - #425: [Solaris] crash on import due to failure at determining BOOT_TIME. - #443: [Linux] can't set CPU affinity on systems with more than 64 cores. 1.2.0 - 2013-11-20 ================== **Enhancements** - #439: assume os.getpid() if no argument is passed to psutil.Process constructor. - #440: new psutil.wait_procs() utility function which waits for multiple processes to terminate. **Bug fixes** - #348: [Windows XP/Vista] fix "ImportError: DLL load failed" occurring on module import. 1.1.3 - 2013-11-07 ================== **Bug fixes** - #442: [Linux] psutil won't compile on certain version of Linux because of missing prlimit(2) syscall. 1.1.2 - 2013-10-22 ================== **Bug fixes** - #442: [Linux] psutil won't compile on Debian 6.0 because of missing prlimit(2) syscall. 1.1.1 - 2013-10-08 ================== **Bug fixes** - #442: [Linux] psutil won't compile on kernels < 2.6.36 due to missing prlimit(2) syscall. 1.1.0 - 2013-09-28 ================== **Enhancements** - #410: host tar.gz and windows binary files are on PYPI. - #412: [Linux] get/set process resource limits. - #415: [Windows] Process.get_children() is an order of magnitude faster. - #426: [Windows] Process.name is an order of magnitude faster. - #431: [UNIX] Process.name is slightly faster because it unnecessarily retrieved also process cmdline. **Bug fixes** - #391: [Windows] psutil.cpu_times_percent() returns negative percentages. - #408: STATUS_* and CONN_* constants don't properly serialize on JSON. - #411: [Windows] examples/disk_usage.py may pop-up a GUI error. - #413: [Windows] Process.get_memory_info() leaks memory. - #414: [Windows] Process.exe on Windows XP may raise ERROR_INVALID_PARAMETER. - #416: psutil.disk_usage() doesn't work well with unicode path names. - #430: [Linux] process IO counters report wrong number of r/w syscalls. - #435: [Linux] psutil.net_io_counters() might report erreneous NIC names. - #436: [Linux] psutil.net_io_counters() reports a wrong 'dropin' value. **API changes** - #408: turn STATUS_* and CONN_* constants into plain Python strings. 1.0.1 - 2013-07-12 ================== **Bug fixes** - #405: network_io_counters(pernic=True) no longer works as intended in 1.0.0. 1.0.0 - 2013-07-10 ================== **Enhancements** - #18: Solaris support (yay!) (thanks Justin Venus) - #367: Process.get_connections() 'status' strings are now constants. - #380: test suite exits with non-zero on failure. (patch by floppymaster) - #391: introduce unittest2 facilities and provide workarounds if unittest2 is not installed (python < 2.7). **Bug fixes** - #374: [Windows] negative memory usage reported if process uses a lot of memory. - #379: [Linux] Process.get_memory_maps() may raise ValueError. - #394: [OSX] Mapped memory regions report incorrect file name. - #404: [Linux] sched_*affinity() are implicitly declared. (patch by Arfrever) **API changes** - Process.get_connections() 'status' field is no longer a string but a constant object (psutil.CONN_*). - Process.get_connections() 'local_address' and 'remote_address' fields renamed to 'laddr' and 'raddr'. - psutil.network_io_counters() renamed to psutil.net_io_counters(). 0.7.1 - 2013-05-03 ================== **Bug fixes** - #325: [BSD] psutil.virtual_memory() can raise SystemError. (patch by Jan Beich) - #370: [BSD] Process.get_connections() requires root. (patch by John Baldwin) - #372: [BSD] different process methods raise NoSuchProcess instead of AccessDenied. 0.7.0 - 2013-04-12 ================== **Enhancements** - #233: code migrated to Mercurial (yay!) - #246: psutil.error module is deprecated and scheduled for removal. - #328: [Windows] process IO nice/priority support. - #359: psutil.get_boot_time() - #361: [Linux] psutil.cpu_times() now includes new 'steal', 'guest' and 'guest_nice' fields available on recent Linux kernels. Also, psutil.cpu_percent() is more accurate. - #362: cpu_times_percent() (per-CPU-time utilization as a percentage) **Bug fixes** - #234: [Windows] disk_io_counters() fails to list certain disks. - #264: [Windows] use of psutil.disk_partitions() may cause a message box to appear. - #313: [Linux] psutil.virtual_memory() and psutil.swap_memory() can crash on certain exotic Linux flavors having an incomplete /proc interface. If that's the case we now set the unretrievable stats to 0 and raise a RuntimeWarning. - #315: [OSX] fix some compilation warnings. - #317: [Windows] cannot set process CPU affinity above 31 cores. - #319: [Linux] process get_memory_maps() raises KeyError 'Anonymous' on Debian squeeze. - #321: [UNIX] Process.ppid property is no longer cached as the kernel may set the ppid to 1 in case of a zombie process. - #323: [OSX] disk_io_counters()'s read_time and write_time parameters were reporting microseconds not milliseconds. (patch by Gregory Szorc) - #331: Process cmdline is no longer cached after first acces as it may change. - #333: [OSX] Leak of Mach ports on OS X (patch by rsesek@google.com) - #337: [Linux] process methods not working because of a poor /proc implementation will raise NotImplementedError rather than RuntimeError and Process.as_dict() will not blow up. (patch by Curtin1060) - #338: [Linux] disk_io_counters() fails to find some disks. - #339: [FreeBSD] get_pid_list() can allocate all the memory on system. - #341: [Linux] psutil might crash on import due to error in retrieving system terminals map. - #344: [FreeBSD] swap_memory() might return incorrect results due to kvm_open(3) not being called. (patch by Jean Sebastien) - #338: [Linux] disk_io_counters() fails to find some disks. - #351: [Windows] if psutil is compiled with mingw32 (provided installers for py2.4 and py2.5 are) disk_io_counters() will fail. (Patch by m.malycha) - #353: [OSX] get_users() returns an empty list on OSX 10.8. - #356: Process.parent now checks whether parent PID has been reused in which case returns None. - #365: Process.set_nice() should check PID has not been reused by another process. - #366: [FreeBSD] get_memory_maps(), get_num_fds(), get_open_files() and getcwd() Process methods raise RuntimeError instead of AccessDenied. **API changes** - Process.cmdline property is no longer cached after first access. - Process.ppid property is no longer cached after first access. - [Linux] Process methods not working because of a poor /proc implementation will raise NotImplementedError instead of RuntimeError. - psutil.error module is deprecated and scheduled for removal. 0.6.1 - 2012-08-16 ================== **Enhancements** - #316: process cmdline property now makes a better job at guessing the process executable from the cmdline. **Bug fixes** - #316: process exe was resolved in case it was a symlink. - #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 ================== **Enhancements** - #216: [POSIX] get_connections() UNIX sockets support. - #220: [FreeBSD] get_connections() has been rewritten in C and no longer requires lsof. - #222: [OSX] add support for process cwd. - #261: process extended memory info. - #295: [OSX] process executable path is now determined by asking the OS instead of being guessed from process cmdline. - #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() - #300: examples/pmap.py script. - #301: process_iter() now yields processes sorted by their PIDs. - #302: process number of voluntary and involuntary context switches. - #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() - #305: add examples/netstat.py script. - #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 [POSIX] - inactive [POSIX] - buffers (BSD, Linux) - cached (BSD, OSX) - wired (OSX, BSD) - shared [FreeBSD] 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. - #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** - #298: [OSX and BSD] memory leak in get_num_fds(). - #299: potential memory leak every time PyList_New(0) is used. - #303: [Windows] potential heap corruption in get_num_threads() and get_status() Process methods. - #305: [FreeBSD] psutil can't compile on FreeBSD 9 due to removal of utmp.h. - #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. - #307: [FreeBSD] values returned by psutil.network_io_counters() are wrong. - #308: [BSD / Windows] psutil.virtmem_usage() wasn't actually returning information about swap memory usage as it was supposed to do. It does now. - #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 ================== **Enhancements** - #293: [Windows] process executable path is now determined by asking the OS instead of being guessed from process cmdline. **Bugfixes** - #292: [Linux] race condition in process files/threads/connections. - #294: [Windows] Process CPU affinity is only able to set CPU #0. 0.5.0 - 2012-06-27 ================== **Enhancements** - #195: [Windows] number of handles opened by process. - #209: psutil.disk_partitions() now provides also mount options. - #229: list users currently connected on the system (psutil.get_users()). - #238: [Linux, Windows] process CPU affinity (get and set). - #242: Process.get_children(recursive=True): return all process descendants. - #245: [POSIX] Process.wait() incrementally consumes less CPU cycles. - #257: [Windows] removed Windows 2000 support. - #258: [Linux] Process.get_memory_info() is now 0.5x faster. - #260: process's mapped memory regions. (Windows patch by wj32.64, OSX patch by Jeremy Whitlock) - #262: [Windows] psutil.disk_partitions() was slow due to inspecting the floppy disk drive also when "all" argument was False. - #273: psutil.get_process_list() is deprecated. - #274: psutil no longer requires 2to3 at installation time in order to work with Python 3. - #278: new Process.as_dict() method. - #281: ppid, name, exe, cmdline and create_time properties of Process class are now cached after being accessed. - #282: psutil.STATUS_* constants can now be compared by using their string representation. - #283: speedup Process.is_running() by caching its return value in case the process is terminated. - #284: [POSIX] per-process number of opened file descriptors. - #287: psutil.process_iter() now caches Process instances between calls. - #290: Process.nice property is deprecated in favor of new get_nice() and set_nice() methods. **Bugfixes** - #193: psutil.Popen constructor can throw an exception if the spawned process terminates quickly. - #240: [OSX] incorrect use of free() for Process.get_connections(). - #244: [POSIX] Process.wait() can hog CPU resources if called against a process which is not our children. - #248: [Linux] psutil.network_io_counters() might return erroneous NIC names. - #252: [Windows] process getcwd() erroneously raise NoSuchProcess for processes owned by another user. It now raises AccessDenied instead. - #266: [Windows] psutil.get_pid_list() only shows 1024 processes. (patch by Amoser) - #267: [OSX] Process.get_connections() - an erroneous remote address was returned. (Patch by Amoser) - #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. - #275: [Linux] Process.get_io_counters() erroneously raise NoSuchProcess on old Linux versions. Where not available it now raises NotImplementedError. - #286: Process.is_running() doesn't actually check whether PID has been reused. - #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** - #228: some example scripts were not working with python 3. - #230: [Windows / OSX] memory leak in Process.get_connections(). - #232: [Linux] psutil.phymem_usage() can report erroneous values which are different than "free" command. - #236: [Windows] memory/handle leak in Process's get_memory_info(), suspend() and resume() methods. 0.4.0 - 2011-10-29 ================== **Enhancements** - #150: network I/O counters. (OSX and Windows patch by Jeremy Whitlock) - #154: [FreeBSD] add support for process getcwd() - #157: [Windows] provide installer for Python 3.2 64-bit. - #198: Process.wait(timeout=0) can now be used to make wait() return immediately. - #206: disk I/O counters. (OSX and Windows patch by Jeremy Whitlock) - #213: examples/iotop.py script. - #217: Process.get_connections() now has a "kind" argument to filter for connections with different criteria. - #221: [FreeBSD] Process.get_open_files has been rewritten in C and no longer relies on lsof. - #223: examples/top.py script. - #227: examples/nettop.py script. **Bugfixes** - #135: [OSX] psutil cannot create Process object. - #144: [Linux] no longer support 0 special PID. - #188: [Linux] psutil import error on Linux ARM architectures. - #194: [POSIX] psutil.Process.get_cpu_percent() now reports a percentage over 100 on multicore processors. - #197: [Linux] Process.get_connections() is broken on platforms not supporting IPv6. - #200: [Linux] psutil.NUM_CPUS not working on armel and sparc architectures and causing crash on module import. - #201: [Linux] Process.get_connections() is broken on big-endian architectures. - #211: Process instance can unexpectedly raise NoSuchProcess if tested for equality with another object. - #218: [Linux] crash at import time on Debian 64-bit because of a missing line in /proc/meminfo. - #226: [FreeBSD] crash at import time on FreeBSD 7 and minor. 0.3.0 - 2011-07-08 ================== **Enhancements** - #125: system per-cpu percentage utilization and times. - #163: per-process associated terminal (TTY). - #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. - #172: disk usage statistics. - #174: mounted disk partitions. - #179: setuptools is now used in setup.py **Bugfixes** - #159: SetSeDebug() does not close handles or unset impersonation on return. - #164: [Windows] wait function raises a TimeoutException when a process returns -1 . - #165: process.status raises an unhandled exception. - #166: get_memory_info() leaks handles hogging system resources. - #168: psutil.cpu_percent() returns erroneous results when used in non-blocking mode. (patch by Philip Roberts) - #178: OSX - Process.get_threads() leaks memory - #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 ================== **Enhancements** - #64: per-process I/O counters. - #116: per-process wait() (wait for process to terminate and return its exit code). - #134: per-process get_threads() returning information (id, user and kernel times) about threads opened by process. - #136: process executable path on FreeBSD is now determined by asking the kernel instead of guessing it from cmdline[0]. - #137: per-process real, effective and saved user and group ids. - #140: system boot time. - #142: per-process get and set niceness (priority). - #143: per-process status. - #147: per-process I/O nice (priority) - Linux only. - #148: psutil.Popen class which tidies up subprocess.Popen and psutil.Process in a unique interface. - #152: [OSX] get_process_open_files() implementation has been rewritten in C and no longer relies on lsof resulting in a 3x speedup. - #153: [OSX] get_process_connection() implementation has been rewritten in C and no longer relies on lsof resulting in a 3x speedup. **Bugfixes** - #83: process cmdline is empty on OSX 64-bit. - #130: a race condition can cause IOError exception be raised on Linux if process disappears between open() and subsequent read() calls. - #145: WindowsError was raised instead of psutil.AccessDenied when using process resume() or suspend() on Windows. - #146: 'exe' property on Linux can raise TypeError if path contains NULL bytes. - #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 ================== **Enhancements** - #79: per-process open files. - #88: total system physical cached memory. - #88: total system physical memory buffers used by the kernel. - #91: per-process send_signal() and terminate() methods. - #95: NoSuchProcess and AccessDenied exception classes now provide "pid", "name" and "msg" attributes. - #97: per-process children. - #98: Process.get_cpu_times() and Process.get_memory_info now return a namedtuple instead of a tuple. - #103: per-process opened TCP and UDP connections. - #107: add support for Windows 64 bit. (patch by cjgohlke) - #111: per-process executable name. - #113: exception messages now include process name and pid. - #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) - #117: added support for Windows 2000. - #123: psutil.cpu_percent() and psutil.Process.cpu_percent() accept a new 'interval' parameter. - #129: per-process number of threads. **Bugfixes** - #80: fixed warnings when installing psutil with easy_install. - #81: psutil fails to compile with Visual Studio. - #94: suspend() raises OSError instead of AccessDenied. - #86: psutil didn't compile against FreeBSD 6.x. - #102: orphaned process handles obtained by using OpenProcess in C were left behind every time Process class was instantiated. - #111: path and name Process properties report truncated or erroneous values on UNIX. - #120: cpu_percent() always returning 100% on OS X. - #112: uid and gid properties don't change if process changes effective user/group id at some point. - #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 ================== **Enhancements** - #14: per-process username - #51: per-process current working directory (Windows and Linux only) - #59: Process.is_running() is now 10 times faster - #61: added supoprt for FreeBSD 64 bit - #71: implemented suspend/resume process - #75: python 3 support **Bugfixes** - #36: process cpu_times() and memory_info() functions succeeded also for dead processes while a NoSuchProcess exception is supposed to be raised. - #48: incorrect size for mib array defined in getcmdargs for BSD - #49: possible memory leak due to missing free() on error condition on - #50: fixed getcmdargs() memory fragmentation on BSD - #55: test_pid_4 was failing on Windows Vista - #57: some unit tests were failing on systems where no swap memory is available - #58: is_running() is now called before kill() to make sure we are going to kill the correct process. - #73: virtual memory size reported on OS X includes shared library size - #77: NoSuchProcess wasn't raised on Process.create_time if kill() was used first. 0.1.2 - 2009-05-06 ================== **Enhancements** - #32: Per-process CPU user/kernel times - #33: Process create time - #34: Per-process CPU utilization percentage - #38: Per-process memory usage (bytes) - #41: Per-process memory utilization (percent) - #39: System uptime - #43: Total system virtual memory - #46: Total system physical memory - #44: Total system used/free virtual and physical memory **Bugfixes** - #36: [Windows] NoSuchProcess not raised when accessing timing methods. - #40: test_get_cpu_times() failing on FreeBSD and OS X. - #42: [Windows] get_memory_percent() raises AccessDenied. 0.1.1 - 2009-03-06 ================== **Enhancements** - #4: FreeBSD support for all functions of psutil - #9: Process.uid and Process.gid now retrieve process UID and GID. - #11: Support for parent/ppid - Process.parent property returns a Process object representing the parent process, and Process.ppid returns the parent PID. - #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. - #21: AccessDenied exception created for raising access denied errors from OSError or WindowsError on individual platforms. - #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** - #16: [Windows] Special case for "System Idle Process" (PID 0) which otherwise would return an "invalid parameter" exception. - #17: get_process_list() ignores NoSuchProcess and AccessDenied exceptions during building of the list. - #22: [Windows] Process(0).kill() was failing with an unset exception. - #23: Special case for pid_exists(0) - #24: [Windows] Process(0).kill() now raises AccessDenied exception instead of WindowsError. - #30: psutil.get_pid_list() was returning two ins psutil-3.4.2/appveyor.yml0000664000175000017500000000440612572074510017403 0ustar giampaologiampaolo00000000000000environment: global: # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the # /E:ON and /V:ON options are not enabled in the batch script intepreter # See: http://stackoverflow.com/a/13751649/163740 WITH_COMPILER: "cmd /E:ON /V:ON /C .\\.ci\\appveyor\\run_with_compiler.cmd" matrix: # Pre-installed Python versions, which Appveyor may upgrade to # a later point release. - PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" - PYTHON: "C:\\Python33" PYTHON_VERSION: "3.3.x" PYTHON_ARCH: "32" - PYTHON: "C:\\Python34" PYTHON_VERSION: "3.4.x" PYTHON_ARCH: "32" - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" WINDOWS_SDK_VERSION: "v7.0" - PYTHON: "C:\\Python33-x64" PYTHON_VERSION: "3.3.x" PYTHON_ARCH: "64" WINDOWS_SDK_VERSION: "v7.1" - PYTHON: "C:\\Python34-x64" PYTHON_VERSION: "3.4.x" PYTHON_ARCH: "64" WINDOWS_SDK_VERSION: "v7.1" # Also build on a Python version not pre-installed by Appveyor. # See: https://github.com/ogrisel/python-appveyor-demo/issues/10 # - PYTHON: "C:\\Python266" # PYTHON_VERSION: "2.6.6" # PYTHON_ARCH: "32" init: - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" install: - "powershell .ci\\appveyor\\install.ps1" # - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') # - "%PYTHON%/python.exe C:/get-pip.py" # - "%PYTHON%/python.exe -m pip install ..." - "%WITH_COMPILER% %PYTHON%/python.exe setup.py build" - "%WITH_COMPILER% %PYTHON%/python.exe setup.py build build_ext -i" - "%WITH_COMPILER% %PYTHON%/python.exe setup.py install" - "%WITH_COMPILER% %PYTHON%/Scripts/pip.exe install unittest2 ipaddress pypiwin32 wmi wheel --upgrade" # 1.0.1 is the latest release supporting python 2.6 - "%WITH_COMPILER% %PYTHON%/Scripts/pip.exe install mock==1.0.1" build: off test_script: - "%WITH_COMPILER% %PYTHON%/python test/test_psutil.py" after_test: - "%WITH_COMPILER% %PYTHON%/python setup.py bdist_wheel" artifacts: - path: dist\* # on_success: # - might want to upload the content of dist/*.whl to a public wheelhouse skip_commits: message: skip-ci psutil-3.4.2/.ci/0000775000175000017500000000000012647732502015465 5ustar giampaologiampaolo00000000000000psutil-3.4.2/.ci/README0000664000175000017500000000025712572074510016344 0ustar giampaologiampaolo00000000000000This directory contains support scripts for Travis and Appveyor continuous integration services. Travis is used to run tests on Linux and OSX, Appveyor runs tests on Windows. psutil-3.4.2/.ci/appveyor/0000775000175000017500000000000012647732502017332 5ustar giampaologiampaolo00000000000000psutil-3.4.2/.ci/appveyor/README0000664000175000017500000000020012572074510020175 0ustar giampaologiampaolo00000000000000This directory contains support files for appveyor, a continuous integration service which runs tests on Windows on every push. psutil-3.4.2/.ci/appveyor/run_with_compiler.cmd0000664000175000017500000000346212572074510023550 0ustar giampaologiampaolo00000000000000:: To build extensions for 64 bit Python 3, we need to configure environment :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) :: :: To build extensions for 64 bit Python 2, we need to configure environment :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) :: :: 32 bit builds do not require specific environment configurations. :: :: Note: this script needs to be run with the /E:ON and /V:ON flags for the :: cmd interpreter, at least for (SDK v7.0) :: :: More details at: :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows :: http://stackoverflow.com/a/13751649/163740 :: :: Author: Olivier Grisel :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ @ECHO OFF SET COMMAND_TO_RUN=%* SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows SET MAJOR_PYTHON_VERSION="%PYTHON_VERSION:~0,1%" IF %MAJOR_PYTHON_VERSION% == "2" ( SET WINDOWS_SDK_VERSION="v7.0" ) ELSE IF %MAJOR_PYTHON_VERSION% == "3" ( SET WINDOWS_SDK_VERSION="v7.1" ) ELSE ( ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" EXIT 1 ) IF "%PYTHON_ARCH%"=="64" ( ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture SET DISTUTILS_USE_SDK=1 SET MSSdk=1 "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release ECHO Executing: %COMMAND_TO_RUN% call %COMMAND_TO_RUN% || EXIT 1 ) ELSE ( ECHO Using default MSVC build environment for 32 bit architecture ECHO Executing: %COMMAND_TO_RUN% call %COMMAND_TO_RUN% || EXIT 1 ) psutil-3.4.2/.ci/appveyor/install.ps10000664000175000017500000000534212572074510021424 0ustar giampaologiampaolo00000000000000# Sample script to install Python and pip under Windows # Authors: Olivier Grisel and Kyle Kastner # License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ $BASE_URL = "https://www.python.org/ftp/python/" $GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" $GET_PIP_PATH = "C:\get-pip.py" function DownloadPython ($python_version, $platform_suffix) { $webclient = New-Object System.Net.WebClient $filename = "python-" + $python_version + $platform_suffix + ".msi" $url = $BASE_URL + $python_version + "/" + $filename $basedir = $pwd.Path + "\" $filepath = $basedir + $filename if (Test-Path $filename) { Write-Host "Reusing" $filepath return $filepath } # Download and retry up to 5 times in case of network transient errors. Write-Host "Downloading" $filename "from" $url $retry_attempts = 3 for($i=0; $i -lt $retry_attempts; $i++){ try { $webclient.DownloadFile($url, $filepath) break } Catch [Exception]{ Start-Sleep 1 } } Write-Host "File saved at" $filepath return $filepath } function InstallPython ($python_version, $architecture, $python_home) { Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home if (Test-Path $python_home) { Write-Host $python_home "already exists, skipping." return $false } if ($architecture -eq "32") { $platform_suffix = "" } else { $platform_suffix = ".amd64" } $filepath = DownloadPython $python_version $platform_suffix Write-Host "Installing" $filepath "to" $python_home $args = "/qn /i $filepath TARGETDIR=$python_home" Write-Host "msiexec.exe" $args Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru Write-Host "Python $python_version ($architecture) installation complete" return $true } function InstallPip ($python_home) { $pip_path = $python_home + "/Scripts/pip.exe" $python_path = $python_home + "/python.exe" if (-not(Test-Path $pip_path)) { Write-Host "Installing pip..." $webclient = New-Object System.Net.WebClient $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) Write-Host "Executing:" $python_path $GET_PIP_PATH Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru } else { Write-Host "pip already installed." } } function InstallPackage ($python_home, $pkg) { $pip_path = $python_home + "/Scripts/pip.exe" & $pip_path install $pkg } function main () { InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON InstallPip $env:PYTHON InstallPackage $env:PYTHON wheel } main psutil-3.4.2/.ci/travis/0000775000175000017500000000000012647732502016775 5ustar giampaologiampaolo00000000000000psutil-3.4.2/.ci/travis/README0000664000175000017500000000021012572074510017641 0ustar giampaologiampaolo00000000000000This directory contains support files for Travis, a continuous integration service which runs tests on Linux and Windows on every push. psutil-3.4.2/.ci/travis/run.sh0000775000175000017500000000052712572074510020137 0ustar giampaologiampaolo00000000000000#!/bin/bash set -e set -x if [[ "$(uname -s)" == 'Darwin' ]]; then if which pyenv > /dev/null; then eval "$(pyenv init -)" fi pyenv activate psutil fi python setup.py build python setup.py install coverage run test/test_psutil.py --include="psutil/*" --omit="test/*,*setup*" python test/test_memory_leaks.py flake8 pep8 psutil-3.4.2/.ci/travis/install.sh0000775000175000017500000000253312572074510021000 0ustar giampaologiampaolo00000000000000#!/bin/bash set -e set -x if [[ "$(uname -s)" == 'Darwin' ]]; then brew update || brew update brew outdated pyenv || brew upgrade pyenv brew install pyenv-virtualenv if which pyenv > /dev/null; then eval "$(pyenv init -)" fi case "${PYVER}" in py26) pyenv install 2.6.9 pyenv virtualenv 2.6.9 psutil ;; py27) pyenv install 2.7.10 pyenv virtualenv 2.7.10 psutil ;; py32) pyenv install 3.2.6 pyenv virtualenv 3.2.6 psutil ;; py33) pyenv install 3.3.6 pyenv virtualenv 3.3.6 psutil ;; py34) pyenv install 3.4.3 pyenv virtualenv 3.4.3 psutil ;; esac pyenv rehash pyenv activate psutil fi if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]] || [[ $PYVER == 'py26' ]]; then pip install -U ipaddress unittest2 mock==1.0.1 elif [[ $TRAVIS_PYTHON_VERSION == '2.7' ]] || [[ $PYVER == 'py27' ]]; then pip install -U ipaddress mock elif [[ $TRAVIS_PYTHON_VERSION == '3.2' ]] || [[ $PYVER == 'py32' ]]; then pip install -U ipaddress mock elif [[ $TRAVIS_PYTHON_VERSION == '3.3' ]] || [[ $PYVER == 'py33' ]]; then pip install -U ipaddress fi pip install coverage coveralls flake8 pep8psutil-3.4.2/tox.ini0000664000175000017500000000132412572074510016322 0ustar giampaologiampaolo00000000000000# Tox (http://tox.testrun.org/) is a tool for running tests # in multiple virtualenvs. This configuration file will run the # test suite on all supported python versions. # To use it run "pip install tox" and then run "tox" from this # directory. [tox] envlist = py26, py27, py32, py33, py34 [testenv] deps = flake8 pytest py26: ipaddress py26: mock==1.0.1 py26: unittest2 py27: ipaddress py27: mock py32: ipaddress py32: mock py33: ipaddress setenv = PYTHONPATH = {toxinidir}/test commands = py.test {posargs} git ls-files | grep \\.py$ | xargs flake8 # suppress "WARNING: 'git' command found but not installed in testenv whitelist_externals = git usedevelop = True psutil-3.4.2/LICENSE0000664000175000017500000000306012572074510016013 0ustar giampaologiampaolo00000000000000psutil 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. psutil-3.4.2/setup.py0000664000175000017500000002247512646164546016546 0ustar giampaologiampaolo00000000000000#!/usr/bin/env python # Copyright (c) 2009 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 cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network) in Python. """ import atexit import contextlib import io import os import sys import tempfile import platform try: from setuptools import setup, Extension except ImportError: from distutils.core import setup, Extension HERE = os.path.abspath(os.path.dirname(__file__)) def get_version(): INIT = os.path.join(HERE, 'psutil/__init__.py') with open(INIT, 'r') as f: for line in f: if line.startswith('__version__'): ret = eval(line.strip().split(' = ')[1]) assert ret.count('.') == 2, ret for num in ret.split('.'): assert num.isdigit(), ret return ret else: raise ValueError("couldn't find version string") def get_description(): README = os.path.join(HERE, 'README.rst') with open(README, 'r') as f: return f.read() @contextlib.contextmanager def silenced_output(stream_name): class DummyFile(io.BytesIO): # see: https://github.com/giampaolo/psutil/issues/678 errors = "ignore" def write(self, s): pass orig = getattr(sys, stream_name) try: setattr(sys, stream_name, DummyFile()) yield finally: setattr(sys, stream_name, orig) VERSION = get_version() VERSION_MACRO = ('PSUTIL_VERSION', int(VERSION.replace('.', ''))) # POSIX if os.name == 'posix': posix_extension = Extension( 'psutil._psutil_posix', sources=['psutil/_psutil_posix.c']) if sys.platform.startswith("sunos"): posix_extension.libraries.append('socket') if platform.release() == '5.10': posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c') posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1)) # Windows if sys.platform.startswith("win32"): def get_winver(): maj, min = sys.getwindowsversion()[0:2] return '0x0%s' % ((maj * 100) + min) ext = Extension( 'psutil._psutil_windows', sources=[ 'psutil/_psutil_windows.c', 'psutil/_psutil_common.c', 'psutil/arch/windows/process_info.c', 'psutil/arch/windows/process_handles.c', 'psutil/arch/windows/security.c', 'psutil/arch/windows/inet_ntop.c', ], define_macros=[ VERSION_MACRO, # be nice to mingw, see: # http://www.mingw.org/wiki/Use_more_recent_defined_functions ('_WIN32_WINNT', get_winver()), ('_AVAIL_WINVER_', get_winver()), ('_CRT_SECURE_NO_WARNINGS', None), # see: https://github.com/giampaolo/psutil/issues/348 ('PSAPI_VERSION', 1), ], libraries=[ "psapi", "kernel32", "advapi32", "shell32", "netapi32", "iphlpapi", "wtsapi32", "ws2_32", ], # extra_compile_args=["/Z7"], # extra_link_args=["/DEBUG"] ) extensions = [ext] # OS X elif sys.platform.startswith("darwin"): ext = Extension( 'psutil._psutil_osx', sources=[ 'psutil/_psutil_osx.c', 'psutil/_psutil_common.c', 'psutil/arch/osx/process_info.c' ], define_macros=[VERSION_MACRO], extra_link_args=[ '-framework', 'CoreFoundation', '-framework', 'IOKit' ]) extensions = [ext, posix_extension] # FreeBSD elif sys.platform.startswith("freebsd"): ext = Extension( 'psutil._psutil_bsd', sources=[ 'psutil/_psutil_bsd.c', 'psutil/_psutil_common.c', 'psutil/arch/bsd/freebsd.c', 'psutil/arch/bsd/freebsd_socks.c', ], define_macros=[VERSION_MACRO], libraries=["devstat"]) extensions = [ext, posix_extension] # OpenBSD elif sys.platform.startswith("openbsd"): ext = Extension( 'psutil._psutil_bsd', sources=[ 'psutil/_psutil_bsd.c', 'psutil/_psutil_common.c', 'psutil/arch/bsd/openbsd.c', ], define_macros=[VERSION_MACRO], libraries=["kvm"]) extensions = [ext, posix_extension] # NetBSD elif sys.platform.startswith("netbsd"): ext = Extension( 'psutil._psutil_bsd', sources=[ 'psutil/_psutil_bsd.c', 'psutil/_psutil_common.c', 'psutil/arch/bsd/netbsd.c', 'psutil/arch/bsd/netbsd_socks.c', ], define_macros=[VERSION_MACRO], libraries=["kvm"]) extensions = [ext, posix_extension] # Linux elif sys.platform.startswith("linux"): def get_ethtool_macro(): # see: https://github.com/giampaolo/psutil/issues/659 from distutils.unixccompiler import UnixCCompiler from distutils.errors import CompileError with tempfile.NamedTemporaryFile( suffix='.c', delete=False, mode="wt") as f: f.write("#include ") @atexit.register def on_exit(): try: os.remove(f.name) except OSError: pass compiler = UnixCCompiler() try: with silenced_output('stderr'): with silenced_output('stdout'): compiler.compile([f.name]) except CompileError: return ("PSUTIL_ETHTOOL_MISSING_TYPES", 1) else: return None ETHTOOL_MACRO = get_ethtool_macro() macros = [VERSION_MACRO] if ETHTOOL_MACRO is not None: macros.append(ETHTOOL_MACRO) ext = Extension( 'psutil._psutil_linux', sources=['psutil/_psutil_linux.c'], define_macros=macros) extensions = [ext, posix_extension] # Solaris elif sys.platform.lower().startswith('sunos'): ext = Extension( 'psutil._psutil_sunos', sources=['psutil/_psutil_sunos.c'], define_macros=[VERSION_MACRO], libraries=['kstat', 'nsl', 'socket']) extensions = [ext, posix_extension] else: sys.exit('platform %s is not supported' % sys.platform) def main(): setup_args = dict( name='psutil', version=VERSION, description=__doc__.replace('\n', '').strip(), long_description=get_description(), keywords=[ 'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty', 'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat', 'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'pstree', 'monitoring', 'ulimit', 'prlimit', ], author='Giampaolo Rodola', author_email='g.rodola gmail com', url='https://github.com/giampaolo/psutil', platforms='Platform Independent', license='BSD', packages=['psutil'], # see: python setup.py register --list-classifiers classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Environment :: Win32 (MS Windows)', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: BSD License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows :: Windows NT/2000', 'Operating System :: Microsoft', 'Operating System :: OS Independent', 'Operating System :: POSIX :: BSD :: FreeBSD', 'Operating System :: POSIX :: BSD :: NetBSD', 'Operating System :: POSIX :: BSD :: OpenBSD', 'Operating System :: POSIX :: BSD', 'Operating System :: POSIX :: Linux', 'Operating System :: POSIX :: SunOS/Solaris', 'Operating System :: POSIX', 'Programming Language :: C', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries', 'Topic :: System :: Benchmark', 'Topic :: System :: Hardware', 'Topic :: System :: Monitoring', 'Topic :: System :: Networking :: Monitoring', 'Topic :: System :: Networking', 'Topic :: System :: Operating System', 'Topic :: System :: Systems Administration', 'Topic :: Utilities', ], ) if extensions is not None: setup_args["ext_modules"] = extensions setup(**setup_args) if __name__ == '__main__': main() psutil-3.4.2/CREDITS0000664000175000017500000001234112647443504016036 0ustar giampaologiampaolo00000000000000Intro ===== I would like to recognize some of the people who have been instrumental in the development of psutil. I'm sure I'm forgetting some people (feel free to email me), 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 https://github.com/giampaolo/psutil/issues). Really thanks to all of you. - Giampaolo Author ====== N: Giampaolo Rodola' C: Italy E: g.rodola@gmail.com W: http://grodola.blogspot.com/ Contributors ============ N: Jay Loden C: NJ, USA E: jloden@gmail.com D: original co-author, initial design/bootstrap and occasional bug fixes W: http://www.jayloden.com N: Jeff Tang W: https://github.com/mrjefftang I: 340, 529, 616, 653, 654, 648, 641 N: Jeremy Whitlock E: jcscoobyrs@gmail.com D: great help with OSX C development. I: 125, 150, 174, 206 N: Landry Breuil W: https://github.com/landryb D: OpenBSD implementation. I: 615 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 (initial version of Process.username()) N: Justin Venus E: justin.venus@gmail.com D: Solaris support I: 18 N: Dave Daeschler C: USA E: david.daeschler@gmail.com W: http://daviddaeschler.com D: some contributions to initial design/bootstrap plus occasional bug fixing I: 522, 536 N: Thomas Klausner W: https://github.com/0-wiz-0 I: #557 N: Ryo Onodera W: https://github.com/ryoon I: #557 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, 340 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 N: Florent Xicluna E: florent.xicluna@gmail.com I: 319 N: Michal Spondr E: michal.spondr I: 313 N: Jean Sebastien E: dumbboules@gmail.com I: 344 N: Rob Smith W: http://www.kormoc.com/ I: 341 N: Youngsik Kim W: https://plus.google.com/101320747613749824490/ I: 317 N: Gregory Szorc W: https://plus.google.com/116873264322260110710/posts I: 323 N: André Oriani E: aoriani@gmail.com I: 361 N: clackwell E: clackwell@gmail.com I: 356 N: m.malycha E: m.malycha@gmail.com I: 351 N: John Baldwin E: jhb@FreeBSD.org I: 370 N: Jan Beich E: jbeich@tormail.org I: 325 N: floppymaster E: floppymaster@gmail.com I: 380 N: Arfrever.FTA E: Arfrever.FTA@gmail.com I: 369, 404 N: danudey E: danudey@gmail.com I: 386 N: Adrien Fallou I: 224 N: Gisle Vanem E: gisle.vanem@gmail.com I: 411 N: thepyr0 E: thepyr0@gmail.com I: 414 N: John Pankov E: john.pankov@gmail.com I: 435 N: Matt Good W: http://matt-good.net/ I: 438 N: Ulrich Klank E: ulrich.klank@scitics.de I: 448 N: Josiah Carlson E: josiah.carlson@gmail.com I: 451, 452 N: Raymond Hettinger D: namedtuple and lru_cache backward compatible implementations. N: Jason Kirtland D: backward compatible implementation of collections.defaultdict. M: Ken Seeho D: @cached_property decorator N: crusaderky E: crusaderky@gmail.com I: 470, 477 E: alex@mroja.net I: 471 N: Gautam Singh E: gautam.singh@gmail.com I: 466 E: lhn@hupfeldtit.dk I: 476, 479 N: Francois Charron E: francois.charron.1@gmail.com I: 474 N: Naveed Roudsari E: naveed.roudsari@gmail.com I: 421 N: Alexander Grothe E: Alexander.Grothe@gmail.com I: 497 N: Szigeti Gabor Niif E: szigeti.gabor.niif@gmail.com I: 446 N: msabramo E: msabramo@gmail.com I: 492 N: Yaolong Huang E: airekans@gmail.com W: http://airekans.github.io/ I: 530 N: Anders Chrigström W: https://github.com/anders-chrigstrom I: 496 N: spacewander W: https://github.com/spacewander E: spacewanderlzx@gmail.com I: 561, 603 N: Sylvain Mouquet E: sylvain.mouquet@gmail.com I: 565 N: karthikrev I: 568 N: Bruno Binet E: bruno.binet@gmail.com I: 572 N: Gabi Davar C: Israel W: https://github.com/mindw I: 578, 581, 587 N: spacewanderlzx C: Guangzhou,China E: spacewanderlzx@gmail.com I: 555 N: Fabian Groffen I: 611, 618 N: desbma W: https://github.com/desbma C: France I: 628 N: John Burnett W: http://www.johnburnett.com/ C: Irvine, CA, US I: 614 N: Ãrni Már Jónsson E: Reykjavik, Iceland E: https://github.com/arnimarj I: 634 N: Bart van Kleef W: https://github.com/bkleef I: 664 N: Steven Winfield W: https://github.com/stevenwinfield I: 672 N: sk6249 W: https://github.com/sk6249 I: 670 N: maozguttman W: https://github.com/maozguttman I: 659 N: wiggin15 W: https://github.com/wiggin15 I: 517, 607, 610 N: dasumin W: https://github.com/dasumin I: 541 N: Mike Sarahan W: https://github.com/msarahan I: 688 N: Syohei YOSHIDA W: https://github.com/syohex I: 730 psutil-3.4.2/setup.cfg0000664000175000017500000000007312647732503016636 0ustar giampaologiampaolo00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 psutil-3.4.2/psutil/0000775000175000017500000000000012647732502016334 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/__init__.py0000664000175000017500000021001112647732362020444 0ustar giampaologiampaolo00000000000000# -*- coding: utf-8 -*- # Copyright (c) 2009, 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 cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network) in Python. """ from __future__ import division import collections import errno import functools import os import signal import subprocess import sys import time import traceback try: import pwd except ImportError: pwd = None from . import _common from ._common import memoize from ._compat import callable from ._compat import long from ._compat import PY3 as _PY3 from ._common import STATUS_DEAD from ._common import STATUS_DISK_SLEEP from ._common import STATUS_IDLE # bsd from ._common import STATUS_LOCKED from ._common import STATUS_RUNNING from ._common import STATUS_SLEEPING from ._common import STATUS_STOPPED from ._common import STATUS_TRACING_STOP from ._common import STATUS_WAITING # bsd from ._common import STATUS_WAKING from ._common import STATUS_ZOMBIE from ._common import CONN_CLOSE from ._common import CONN_CLOSE_WAIT from ._common import CONN_CLOSING from ._common import CONN_ESTABLISHED from ._common import CONN_FIN_WAIT1 from ._common import CONN_FIN_WAIT2 from ._common import CONN_LAST_ACK from ._common import CONN_LISTEN from ._common import CONN_NONE from ._common import CONN_SYN_RECV from ._common import CONN_SYN_SENT from ._common import CONN_TIME_WAIT from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_UNKNOWN if sys.platform.startswith("linux"): # This is public API and it will be retrieved from _pslinux.py # via sys.modules. PROCFS_PATH = "/proc" from . import _pslinux as _psplatform from ._pslinux import IOPRIO_CLASS_BE # NOQA from ._pslinux import IOPRIO_CLASS_IDLE # NOQA from ._pslinux import IOPRIO_CLASS_NONE # NOQA from ._pslinux import IOPRIO_CLASS_RT # NOQA # Linux >= 2.6.36 if _psplatform.HAS_PRLIMIT: from ._psutil_linux import RLIM_INFINITY # NOQA from ._psutil_linux import RLIMIT_AS # NOQA from ._psutil_linux import RLIMIT_CORE # NOQA from ._psutil_linux import RLIMIT_CPU # NOQA from ._psutil_linux import RLIMIT_DATA # NOQA from ._psutil_linux import RLIMIT_FSIZE # NOQA from ._psutil_linux import RLIMIT_LOCKS # NOQA from ._psutil_linux import RLIMIT_MEMLOCK # NOQA from ._psutil_linux import RLIMIT_NOFILE # NOQA from ._psutil_linux import RLIMIT_NPROC # NOQA from ._psutil_linux import RLIMIT_RSS # NOQA from ._psutil_linux import RLIMIT_STACK # NOQA # Kinda ugly but considerably faster than using hasattr() and # setattr() against the module object (we are at import time: # speed matters). from . import _psutil_linux try: RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE except AttributeError: pass try: RLIMIT_NICE = _psutil_linux.RLIMIT_NICE except AttributeError: pass try: RLIMIT_RTPRIO = _psutil_linux.RLIMIT_RTPRIO except AttributeError: pass try: RLIMIT_RTTIME = _psutil_linux.RLIMIT_RTTIME except AttributeError: pass try: RLIMIT_SIGPENDING = _psutil_linux.RLIMIT_SIGPENDING except AttributeError: pass elif sys.platform.startswith("win32"): from . import _pswindows as _psplatform from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # NOQA from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # NOQA from ._psutil_windows import HIGH_PRIORITY_CLASS # NOQA from ._psutil_windows import IDLE_PRIORITY_CLASS # NOQA from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA from ._pswindows import CONN_DELETE_TCB # NOQA elif sys.platform.startswith("darwin"): from . import _psosx as _psplatform elif sys.platform.startswith("freebsd") or \ sys.platform.startswith("openbsd") or \ sys.platform.startswith("netbsd"): from . import _psbsd as _psplatform elif sys.platform.startswith("sunos"): from . import _pssunos as _psplatform from ._pssunos import CONN_BOUND # NOQA from ._pssunos import CONN_IDLE # NOQA # This is public API and it will be retrieved from _pssunos.py # via sys.modules. PROCFS_PATH = "/proc" else: # pragma: no cover raise NotImplementedError('platform %s is not supported' % sys.platform) __all__ = [ # exceptions "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied", "TimeoutExpired", # constants "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", "STATUS_WAITING", "STATUS_LOCKED", "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", "AF_LINK", "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN", # classes "Process", "Popen", # functions "pid_exists", "pids", "process_iter", "wait_procs", # proc "virtual_memory", "swap_memory", # memory "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu "net_io_counters", "net_connections", "net_if_addrs", # network "net_if_stats", "disk_io_counters", "disk_partitions", "disk_usage", # disk "users", "boot_time", # others ] __all__.extend(_psplatform.__extra__all__) __author__ = "Giampaolo Rodola'" __version__ = "3.4.2" version_info = tuple([int(num) for num in __version__.split('.')]) AF_LINK = _psplatform.AF_LINK _TOTAL_PHYMEM = None _POSIX = os.name == 'posix' _WINDOWS = os.name == 'nt' _OPENBSD = sys.platform.startswith("openbsd") _timer = getattr(time, 'monotonic', time.time) # Sanity check in case the user messed up with psutil installation # or did something weird with sys.path. In this case we might end # up importing a python module using a C extension module which # was compiled for a different version of psutil. # We want to prevent that by failing sooner rather than later. # See: https://github.com/giampaolo/psutil/issues/564 if (int(__version__.replace('.', '')) != getattr(_psplatform.cext, 'version', None)): msg = "version conflict: %r C extension module was built for another " \ "version of psutil (different than %s)" % (_psplatform.cext.__file__, __version__) raise ImportError(msg) # ===================================================================== # --- exceptions # ===================================================================== class Error(Exception): """Base exception class. All other psutil exceptions inherit from this one. """ def __init__(self, msg=""): self.msg = msg def __repr__(self): ret = "%s.%s %s" % (self.__class__.__module__, self.__class__.__name__, self.msg) return ret.strip() __str__ = __repr__ class NoSuchProcess(Error): """Exception raised when a process with a certain PID doesn't or no longer exists. """ def __init__(self, pid, name=None, msg=None): Error.__init__(self, msg) self.pid = pid self.name = name self.msg = msg if msg is None: if name: details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) else: details = "(pid=%s)" % self.pid self.msg = "process no longer exists " + details class ZombieProcess(NoSuchProcess): """Exception raised when querying a zombie process. This is raised on OSX, BSD and Solaris only, and not always: depending on the query the OS may be able to succeed anyway. On Linux all zombie processes are querable (hence this is never raised). Windows doesn't have zombie processes. """ def __init__(self, pid, name=None, ppid=None, msg=None): Error.__init__(self, msg) self.pid = pid self.ppid = ppid self.name = name self.msg = msg if msg is None: if name and ppid: details = "(pid=%s, name=%s, ppid=%s)" % ( self.pid, repr(self.name), self.ppid) elif name: details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) else: details = "(pid=%s)" % self.pid self.msg = "process still exists but it's a zombie " + details class AccessDenied(Error): """Exception raised when permission to perform an action is denied.""" def __init__(self, pid=None, name=None, msg=None): Error.__init__(self, msg) self.pid = pid self.name = name self.msg = msg if msg is None: if (pid is not None) and (name is not None): self.msg = "(pid=%s, name=%s)" % (pid, repr(name)) elif (pid is not None): self.msg = "(pid=%s)" % self.pid else: self.msg = "" class TimeoutExpired(Error): """Raised on Process.wait(timeout) if timeout expires and process is still alive. """ def __init__(self, seconds, pid=None, name=None): Error.__init__(self, "timeout after %s seconds" % seconds) self.seconds = seconds self.pid = pid self.name = name if (pid is not None) and (name is not None): self.msg += " (pid=%s, name=%s)" % (pid, repr(name)) elif (pid is not None): self.msg += " (pid=%s)" % self.pid # push exception classes into platform specific module namespace _psplatform.NoSuchProcess = NoSuchProcess _psplatform.ZombieProcess = ZombieProcess _psplatform.AccessDenied = AccessDenied _psplatform.TimeoutExpired = TimeoutExpired # ===================================================================== # --- Process class # ===================================================================== def _assert_pid_not_reused(fun): """Decorator which raises NoSuchProcess in case a process is no longer running or its PID has been reused. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): if not self.is_running(): raise NoSuchProcess(self.pid, self._name) return fun(self, *args, **kwargs) return wrapper class Process(object): """Represents an OS process with the given PID. If PID is omitted current process PID (os.getpid()) is used. Raise NoSuchProcess if PID does not exist. Note that most of the methods of this class do not make sure the PID of the process being queried has been reused over time. That means you might end up retrieving an information referring to another process in case the original one this instance refers to is gone in the meantime. The only exceptions for which process identity is pre-emptively checked and guaranteed are: - parent() - children() - nice() (set) - ionice() (set) - rlimit() (set) - cpu_affinity (set) - suspend() - resume() - send_signal() - terminate() - kill() To prevent this problem for all other methods you can: - use is_running() before querying the process - if you're continuously iterating over a set of Process instances use process_iter() which pre-emptively checks process identity for every yielded instance """ def __init__(self, pid=None): self._init(pid) def _init(self, pid, _ignore_nsp=False): if pid is None: pid = os.getpid() else: if not _PY3 and not isinstance(pid, (int, long)): raise TypeError('pid must be an integer (got %r)' % pid) if pid < 0: raise ValueError('pid must be a positive integer (got %s)' % pid) self._pid = pid self._name = None self._exe = None self._create_time = None self._gone = False self._hash = None # used for caching on Windows only (on POSIX ppid may change) self._ppid = None # platform-specific modules define an _psplatform.Process # implementation class self._proc = _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: # we should never get here as AFAIK we're able to get # process creation time on all platforms even as a # limited user pass except ZombieProcess: # Let's consider a zombie process as legitimate as # tehcnically it's still alive (it can be queried, # although not always, and it's returned by pids()). pass except NoSuchProcess: if not _ignore_nsp: msg = 'no process found with pid %s' % pid raise NoSuchProcess(pid, None, msg) else: self._gone = True # This pair is supposed to indentify a Process instance # univocally over time (the PID alone is not enough as # it might refer to a process whose PID has been reused). # This will be used later in __eq__() and is_running(). self._ident = (self.pid, self._create_time) def __str__(self): try: pid = self.pid name = repr(self.name()) except ZombieProcess: details = "(pid=%s (zombie))" % self.pid 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 __eq__(self, other): # Test for equality with another Process object based # on PID and creation time. if not isinstance(other, Process): return NotImplemented return self._ident == other._ident def __ne__(self, other): return not self == other def __hash__(self): if self._hash is None: self._hash = hash(self._ident) return self._hash # --- utility methods def as_dict(self, attrs=None, 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' attribute names (e.g. ['cpu_times', 'name']) else all public (read only) attributes are assumed. 'ad_value' is the value which gets assigned in case AccessDenied or ZombieProcess exception is raised when retrieving that particular process information. """ excluded_names = set( ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'is_running', 'as_dict', 'parent', 'children', 'rlimit']) retdict = dict() ls = set(attrs or [x for x in dir(self)]) for name in ls: if name.startswith('_'): continue if name in excluded_names: continue try: attr = getattr(self, name) if callable(attr): ret = attr() else: ret = attr except (AccessDenied, ZombieProcess): 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 retdict[name] = ret return retdict def parent(self): """Return the parent process as a Process object pre-emptively checking whether PID has been reused. If no parent is known return None. """ ppid = self.ppid() if ppid is not None: ctime = self.create_time() try: parent = Process(ppid) if parent.create_time() <= ctime: return parent # ...else ppid has been reused by another process except NoSuchProcess: pass def is_running(self): """Return whether this process is running. It also checks if PID has been reused by another process in which case return False. """ if self._gone: return False try: # Checking if PID is alive is not enough as the PID might # have been reused by another process: we also want to # verify process identity. # Process identity / uniqueness over time is guaranteed by # (PID + creation time) and that is verified in __eq__. return self == Process(self.pid) except ZombieProcess: # We should never get here as it's already handled in # Process.__init__; here just for extra safety. return True except NoSuchProcess: self._gone = True return False # --- actual API @property def pid(self): """The process PID.""" return self._pid def ppid(self): """The process parent PID. On Windows the return value is cached after first call. """ # On POSIX we don't want to cache the ppid as it may unexpectedly # change to 1 (init) in case this process turns into a zombie: # https://github.com/giampaolo/psutil/issues/321 # http://stackoverflow.com/questions/356722/ # XXX should we check creation time here rather than in # Process.parent()? if _POSIX: return self._proc.ppid() else: self._ppid = self._ppid or self._proc.ppid() return self._ppid def name(self): """The process name. The return value is cached after first call.""" # Process name is only cached on Windows as on POSIX it may # change, see: # https://github.com/giampaolo/psutil/issues/692 if _WINDOWS and self._name is not None: return self._name name = self._proc.name() if _POSIX and len(name) >= 15: # 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 self._name = name self._proc._name = name return name def exe(self): """The process executable as an absolute path. May also be an empty string. The return value is cached after first call. """ 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 # Attempt to guess only in case of an absolute path. # It is not safe otherwise as the process might have # changed cwd. if (os.path.isabs(exe) and os.path.isfile(exe) and os.access(exe, os.X_OK)): return exe if isinstance(fallback, AccessDenied): raise fallback return fallback if self._exe is None: try: exe = self._proc.exe() except AccessDenied as err: 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 self._exe = exe return self._exe def cmdline(self): """The command line this process has been called with.""" return self._proc.cmdline() def status(self): """The process current status as a STATUS_* constant.""" try: return self._proc.status() except ZombieProcess: return STATUS_ZOMBIE def username(self): """The name of the user that owns the process. On UNIX this is calculated by using *real* process uid. """ if _POSIX: if pwd is None: # might happen if python was installed from sources raise ImportError( "requires pwd module shipped with standard python") real_uid = self.uids().real try: return pwd.getpwuid(real_uid).pw_name except KeyError: # the uid can't be resolved by the system return str(real_uid) else: return self._proc.username() def create_time(self): """The process creation time as a floating point number expressed in seconds since the epoch, in UTC. The return value is cached after first call. """ if self._create_time is None: self._create_time = self._proc.create_time() return self._create_time def cwd(self): """Process current working directory as an absolute path.""" return self._proc.cwd() def nice(self, value=None): """Get or set process niceness (priority).""" if value is None: return self._proc.nice_get() else: if not self.is_running(): raise NoSuchProcess(self.pid, self._name) self._proc.nice_set(value) if _POSIX: def uids(self): """Return process UIDs as a (real, effective, saved) namedtuple. """ return self._proc.uids() def gids(self): """Return process GIDs as a (real, effective, saved) namedtuple. """ return self._proc.gids() def terminal(self): """The terminal associated with this process, if any, else None. """ return self._proc.terminal() def num_fds(self): """Return the number of file descriptors opened by this process (POSIX only). """ return self._proc.num_fds() # Linux, BSD and Windows only if hasattr(_psplatform.Process, "io_counters"): def io_counters(self): """Return process I/O statistics as a (read_count, write_count, read_bytes, write_bytes) namedtuple. Those are the number of read/write calls performed and the amount of bytes read and written by the process. """ return self._proc.io_counters() # Linux and Windows >= Vista only if hasattr(_psplatform.Process, "ionice_get"): def ionice(self, ioclass=None, value=None): """Get or set process I/O niceness (priority). On Linux 'ioclass' is one of the IOPRIO_CLASS_* constants. 'value' is a number which goes from 0 to 7. The higher the value, the lower the I/O priority of the process. On Windows only 'ioclass' is used and it can be set to 2 (normal), 1 (low) or 0 (very low). Available on Linux and Windows > Vista only. """ if ioclass is None: if value is not None: raise ValueError("'ioclass' argument must be specified") return self._proc.ionice_get() else: return self._proc.ionice_set(ioclass, value) # Linux only if hasattr(_psplatform.Process, "rlimit"): def rlimit(self, resource, limits=None): """Get or set process resource limits as a (soft, hard) tuple. 'resource' is one of the RLIMIT_* constants. 'limits' is supposed to be a (soft, hard) tuple. See "man prlimit" for further info. Available on Linux only. """ if limits is None: return self._proc.rlimit(resource) else: return self._proc.rlimit(resource, limits) # Windows, Linux and FreeBSD only if hasattr(_psplatform.Process, "cpu_affinity_get"): def cpu_affinity(self, cpus=None): """Get or set process CPU affinity. If specified 'cpus' must be a list of CPUs for which you want to set the affinity (e.g. [0, 1]). (Windows, Linux and BSD only). """ # Automatically remove duplicates both on get and # set (for get it's not really necessary, it's # just for extra safety). if cpus is None: return list(set(self._proc.cpu_affinity_get())) else: self._proc.cpu_affinity_set(list(set(cpus))) if _WINDOWS: def num_handles(self): """Return the number of handles opened by this process (Windows only). """ return self._proc.num_handles() def num_ctx_switches(self): """Return the number of voluntary and involuntary context switches performed by this process. """ return self._proc.num_ctx_switches() def num_threads(self): """Return the number of threads used by this process.""" return self._proc.num_threads() def threads(self): """Return threads opened by process as a list of (id, user_time, system_time) namedtuples representing thread id and thread CPU times (user/system). On OpenBSD this method requires root access. """ return self._proc.threads() @_assert_pid_not_reused def children(self, recursive=False): """Return the children of this process as a list of Process instances, pre-emptively checking whether PID has been reused. 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) >>> import psutil >>> p = psutil.Process() >>> p.children() B, C, D >>> p.children(recursive=True) B, X, Y, C, D Note that in the example above if process X disappears process Y won't be listed as the reference to process A is lost. """ if hasattr(_psplatform, 'ppid_map'): # Windows only: obtain a {pid:ppid, ...} dict for all running # processes in one shot (faster). ppid_map = _psplatform.ppid_map() else: ppid_map = None ret = [] if not recursive: if ppid_map is None: # 'slow' version, common to all platforms except Windows 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, ZombieProcess): pass else: # Windows only (faster) for pid, ppid in ppid_map.items(): if ppid == self.pid: try: child = Process(pid) # if child happens to be older than its parent # (self) it means child's PID has been reused if self.create_time() <= child.create_time(): ret.append(child) except (NoSuchProcess, ZombieProcess): pass else: # construct a dict where 'values' are all the processes # having 'key' as their parent table = collections.defaultdict(list) if ppid_map is None: for p in process_iter(): try: table[p.ppid()].append(p) except (NoSuchProcess, ZombieProcess): pass else: for pid, ppid in ppid_map.items(): try: p = Process(pid) table[ppid].append(p) except (NoSuchProcess, ZombieProcess): pass # At this point we have a mapping table where table[self.pid] # are the current process' 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, ZombieProcess): pass else: if intime: ret.append(child) if child.pid not in checkpids: checkpids.append(child.pid) return ret def cpu_percent(self, interval=None): """Return a float representing the current process CPU utilization as a percentage. When interval is 0.0 or None (default) compares process times to system CPU times elapsed since last call, returning immediately (non-blocking). That means that the first time this is called it will return a meaningful 0.0 value. When interval is > 0.0 compares process times to system CPU times elapsed before and after the interval (blocking). In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls. Examples: >>> import psutil >>> p = psutil.Process(os.getpid()) >>> # blocking >>> p.cpu_percent(interval=1) 2.0 >>> # non-blocking (percentage since last call) >>> p.cpu_percent(interval=None) 2.9 >>> """ blocking = interval is not None and interval > 0.0 num_cpus = cpu_count() if _POSIX: def timer(): return _timer() * num_cpus else: def timer(): return sum(cpu_times()) if blocking: st1 = timer() pt1 = self._proc.cpu_times() time.sleep(interval) st2 = timer() pt2 = self._proc.cpu_times() else: st1 = self._last_sys_cpu_times pt1 = self._last_proc_cpu_times st2 = timer() pt2 = self._proc.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. # Note: a percentage > 100 is legitimate as it can result # from a process with multiple threads running on different # CPU cores, see: # http://stackoverflow.com/questions/1032357 # https://github.com/giampaolo/psutil/issues/474 overall_percent = ((delta_proc / delta_time) * 100) * num_cpus except ZeroDivisionError: # interval was too low return 0.0 else: return round(overall_percent, 1) def cpu_times(self): """Return a (user, system) namedtuple representing the accumulated process time, in seconds. This is the same as os.times() but per-process. """ return self._proc.cpu_times() def 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._proc.memory_info() def memory_info_ex(self): """Return a namedtuple with variable fields depending on the platform representing extended memory information about this process. All numbers are expressed in bytes. """ return self._proc.memory_info_ex() def memory_percent(self): """Compare physical system memory to process resident memory (RSS) and calculate process memory utilization as a percentage. """ rss = self._proc.memory_info()[0] # use cached value if available total_phymem = _TOTAL_PHYMEM or virtual_memory().total try: return (rss / float(total_phymem)) * 100 except ZeroDivisionError: return 0.0 if hasattr(_psplatform.Process, "memory_maps"): # Available everywhere except OpenBSD and NetBSD. def memory_maps(self, grouped=True): """Return process' mapped memory regions as a list of namedtuples 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._proc.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 = _psplatform.pmmap_grouped return [nt(path, *d[path]) for path in d] # NOQA else: nt = _psplatform.pmmap_ext return [nt(*x) for x in it] def open_files(self): """Return files opened by process as a list of (path, fd) namedtuples including the absolute file name and file descriptor number. """ return self._proc.open_files() def connections(self, kind='inet'): """Return connections opened by process as a list of (fd, family, type, laddr, raddr, status) namedtuples. The 'kind' parameter filters for connections that match 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._proc.connections(kind) if _POSIX: def _send_signal(self, sig): if self.pid == 0: # see "man 2 kill" raise ValueError( "preventing sending signal to process with PID 0 as it " "would affect every process in the process group of the " "calling process (os.getpid()) instead of PID 0") try: os.kill(self.pid, sig) except OSError as err: if err.errno == errno.ESRCH: if _OPENBSD and pid_exists(self.pid): # We do this because os.kill() lies in case of # zombie processes. raise ZombieProcess(self.pid, self._name, self._ppid) else: self._gone = True raise NoSuchProcess(self.pid, self._name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise @_assert_pid_not_reused def send_signal(self, sig): """Send a signal to process pre-emptively checking whether PID has been reused (see signal module constants) . On Windows only SIGTERM is valid and is treated as an alias for kill(). """ if _POSIX: self._send_signal(sig) else: if sig == signal.SIGTERM: self._proc.kill() # py >= 2.7 elif sig in (getattr(signal, "CTRL_C_EVENT", object()), getattr(signal, "CTRL_BREAK_EVENT", object())): self._proc.send_signal(sig) else: raise ValueError( "only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals " "are supported on Windows") @_assert_pid_not_reused def suspend(self): """Suspend process execution with SIGSTOP pre-emptively checking whether PID has been reused. On Windows this has the effect ot suspending all process threads. """ if _POSIX: self._send_signal(signal.SIGSTOP) else: self._proc.suspend() @_assert_pid_not_reused def resume(self): """Resume process execution with SIGCONT pre-emptively checking whether PID has been reused. On Windows this has the effect of resuming all process threads. """ if _POSIX: self._send_signal(signal.SIGCONT) else: self._proc.resume() @_assert_pid_not_reused def terminate(self): """Terminate the process with SIGTERM pre-emptively checking whether PID has been reused. On Windows this is an alias for kill(). """ if _POSIX: self._send_signal(signal.SIGTERM) else: self._proc.kill() @_assert_pid_not_reused def kill(self): """Kill the current process with SIGKILL pre-emptively checking whether PID has been reused. """ if _POSIX: self._send_signal(signal.SIGKILL) else: self._proc.kill() def wait(self, timeout=None): """Wait for process to terminate and, if process is a children of os.getpid(), also return its exit code, else None. If the process is already terminated immediately return None instead of raising NoSuchProcess. If timeout (in seconds) is specified and process is still alive raise TimeoutExpired. To wait for multiple Process(es) use psutil.wait_procs(). """ if timeout is not None and not timeout >= 0: raise ValueError("timeout must be a positive integer") return self._proc.wait(timeout) # ===================================================================== # --- Popen class # ===================================================================== class Popen(Process): """A more convenient interface to stdlib subprocess.Popen class. It starts a sub process and deals with it exactly as when using subprocess.Popen class but in addition also provides all the properties and methods of psutil.Process class as a unified interface: >>> import psutil >>> from subprocess import PIPE >>> p = psutil.Popen(["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. Unlike subprocess.Popen this class pre-emptively checks wheter PID has been reused on send_signal(), terminate() and kill() so that you don't accidentally terminate another process, fixing http://bugs.python.org/issue6973. For a complete documentation refer to: http://docs.python.org/library/subprocess.html """ def __init__(self, *args, **kwargs): # Explicitly avoid to raise NoSuchProcess in case the process # spawned by subprocess.Popen terminates too quickly, see: # https://github.com/giampaolo/psutil/issues/193 self.__subproc = subprocess.Popen(*args, **kwargs) self._init(self.__subproc.pid, _ignore_nsp=True) def __dir__(self): return sorted(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)) def wait(self, timeout=None): if self.__subproc.returncode is not None: return self.__subproc.returncode ret = super(Popen, self).wait(timeout) self.__subproc.returncode = ret return ret # ===================================================================== # --- system processes related functions # ===================================================================== def pids(): """Return a list of current running PIDs.""" return _psplatform.pids() def pid_exists(pid): """Return True if given PID exists in the current process list. This is faster than doing "pid in psutil.pids()" and should be preferred. """ if pid < 0: return False elif pid == 0 and _POSIX: # On POSIX we use os.kill() to determine PID existence. # According to "man 2 kill" PID 0 has a special meaning # though: it refers to <> and that is not we want # to do here. return pid in pids() else: return _psplatform.pid_exists(pid) _pmap = {} def process_iter(): """Return a generator yielding a Process instance for all running processes. Every new Process instance is only created once and then cached into an internal table which is updated every time this is used. Cached Process instances are checked for identity so that you're safe in case a PID has been reused by another process, in which case the cached instance is updated. 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(pids()) 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. if proc is None and pid in _pmap: try: yield _pmap[pid] except KeyError: # If we get here it is likely that 2 threads were # using process_iter(). pass else: raise def wait_procs(procs, timeout=None, callback=None): """Convenience function which waits for a list of processes to terminate. Return a (gone, alive) tuple indicating which processes are gone and which ones are still alive. The gone ones will have a new 'returncode' attribute indicating process exit status (may be None). 'callback' is a function which gets called every time a process terminates (a Process instance is passed as callback argument). Function will return as soon as all processes terminate or when timeout occurs. Typical use case is: - send SIGTERM to a list of processes - give them some time to terminate - send SIGKILL to those ones which are still alive Example: >>> def on_terminate(proc): ... print("process {} terminated".format(proc)) ... >>> for p in procs: ... p.terminate() ... >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate) >>> for p in alive: ... p.kill() """ def check_gone(proc, timeout): try: returncode = proc.wait(timeout=timeout) except TimeoutExpired: pass else: if returncode is not None or not proc.is_running(): proc.returncode = returncode gone.add(proc) if callback is not None: callback(proc) if timeout is not None and not timeout >= 0: msg = "timeout must be a positive integer, got %s" % timeout raise ValueError(msg) gone = set() alive = set(procs) if callback is not None and not callable(callback): raise TypeError("callback %r is not a callable" % callable) if timeout is not None: deadline = _timer() + timeout while alive: if timeout is not None and timeout <= 0: break for proc in alive: # Make sure that every complete iteration (all processes) # will last max 1 sec. # We do this because we don't want to wait too long on a # single process: in case it terminates too late other # processes may disappear in the meantime and their PID # reused. max_timeout = 1.0 / len(alive) if timeout is not None: timeout = min((deadline - _timer()), max_timeout) if timeout <= 0: break check_gone(proc, timeout) else: check_gone(proc, max_timeout) alive = alive - gone if alive: # Last attempt over processes survived so far. # timeout == 0 won't make this function wait any further. for proc in alive: check_gone(proc, 0) alive = alive - gone return (list(gone), list(alive)) # ===================================================================== # --- CPU related functions # ===================================================================== @memoize def cpu_count(logical=True): """Return the number of logical CPUs in the system (same as os.cpu_count() in Python 3.4). If logical is False return the number of physical cores only (e.g. hyper thread CPUs are excluded). Return None if undetermined. The return value is cached after first call. If desired cache can be cleared like this: >>> psutil.cpu_count.cache_clear() """ if logical: return _psplatform.cpu_count_logical() else: return _psplatform.cpu_count_physical() def cpu_times(percpu=False): """Return system-wide CPU times as a namedtuple. Every CPU time represents the seconds the CPU has spent in the given mode. The namedtuple's fields availability varies depending on the platform: - user - system - idle - nice (UNIX) - iowait (Linux) - irq (Linux, FreeBSD) - softirq (Linux) - steal (Linux >= 2.6.11) - guest (Linux >= 2.6.24) - guest_nice (Linux >= 3.2.0) When percpu is True return a list of namedtuples 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.cpu_times() else: return _psplatform.per_cpu_times() try: _last_cpu_times = cpu_times() except Exception: # Don't want to crash at import time. _last_cpu_times = None traceback.print_exc() try: _last_per_cpu_times = cpu_times(percpu=True) except Exception: # Don't want to crash at import time. _last_per_cpu_times = None traceback.print_exc() def cpu_percent(interval=None, 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 (non blocking). That means the first time this is called it will return a meaningless 0.0 value which you should ignore. 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. Examples: >>> # blocking, system-wide >>> psutil.cpu_percent(interval=1) 2.0 >>> >>> # blocking, per-cpu >>> psutil.cpu_percent(interval=1, percpu=True) [2.0, 1.0] >>> >>> # non-blocking (percentage since last call) >>> psutil.cpu_percent(interval=None) 2.9 >>> """ 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 if t1 is None: # Something bad happened at import time. We'll # get a meaningful result on the next call. See: # https://github.com/giampaolo/psutil/pull/715 t1 = 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 if tot1 is None: # Something bad happened at import time. We'll # get a meaningful result on the next call. See: # https://github.com/giampaolo/psutil/pull/715 tot1 = cpu_times(percpu=True) _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 # Use separate global vars for cpu_times_percent() so that it's # independent from cpu_percent() and they can both be used within # the same program. _last_cpu_times_2 = _last_cpu_times _last_per_cpu_times_2 = _last_per_cpu_times def cpu_times_percent(interval=None, percpu=False): """Same as cpu_percent() but provides utilization percentages for each specific CPU time as is returned by cpu_times(). For instance, on Linux we'll get: >>> cpu_times_percent() cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) >>> interval and percpu arguments have the same meaning as in cpu_percent(). """ global _last_cpu_times_2 global _last_per_cpu_times_2 blocking = interval is not None and interval > 0.0 def calculate(t1, t2): nums = [] all_delta = sum(t2) - sum(t1) for field in t1._fields: field_delta = getattr(t2, field) - getattr(t1, field) try: field_perc = (100 * field_delta) / all_delta except ZeroDivisionError: field_perc = 0.0 field_perc = round(field_perc, 1) # CPU times are always supposed to increase over time # or at least remain the same and that's because time # cannot go backwards. # Surprisingly sometimes this might not be the case (at # least on Windows and Linux), see: # https://github.com/giampaolo/psutil/issues/392 # https://github.com/giampaolo/psutil/issues/645 # I really don't know what to do about that except # forcing the value to 0 or 100. if field_perc > 100.0: field_perc = 100.0 # `<=` because `-0.0 == 0.0` evaluates to True elif field_perc <= 0.0: field_perc = 0.0 nums.append(field_perc) return _psplatform.scputimes(*nums) # system-wide usage if not percpu: if blocking: t1 = cpu_times() time.sleep(interval) else: t1 = _last_cpu_times_2 if t1 is None: # Something bad happened at import time. We'll # get a meaningful result on the next call. See: # https://github.com/giampaolo/psutil/pull/715 t1 = cpu_times() _last_cpu_times_2 = cpu_times() return calculate(t1, _last_cpu_times_2) # per-cpu usage else: ret = [] if blocking: tot1 = cpu_times(percpu=True) time.sleep(interval) else: tot1 = _last_per_cpu_times_2 if tot1 is None: # Something bad happened at import time. We'll # get a meaningful result on the next call. See: # https://github.com/giampaolo/psutil/pull/715 tot1 = cpu_times(percpu=True) _last_per_cpu_times_2 = cpu_times(percpu=True) for t1, t2 in zip(tot1, _last_per_cpu_times_2): 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. """ global _TOTAL_PHYMEM ret = _psplatform.virtual_memory() # cached for later use in Process.memory_percent() _TOTAL_PHYMEM = ret.total return ret def swap_memory(): """Return system swap memory statistics as a namedtuple including the following fields: - 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.disk_usage(path) def disk_partitions(all=False): """Return mounted partitions as a list of (device, mountpoint, fstype, opts) namedtuple. 'opts' field is a raw string separated by commas indicating mount options 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 fields: - 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 namedtuple described above as the values. On recent Windows versions 'diskperf -y' command may need to be executed first otherwise this function won't find any disk. """ 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] = _common.sdiskio(*fields) return rawdict else: return _common.sdiskio(*[sum(x) for x in zip(*rawdict.values())]) # ===================================================================== # --- network related functions # ===================================================================== def net_io_counters(pernic=False): """Return network I/O statistics as a namedtuple including the following fields: - 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.net_io_counters() if not rawdict: raise RuntimeError("couldn't find any network interface") if pernic: for nic, fields in rawdict.items(): rawdict[nic] = _common.snetio(*fields) return rawdict else: return _common.snetio(*[sum(x) for x in zip(*rawdict.values())]) def net_connections(kind='inet'): """Return system-wide connections as a list of (fd, family, type, laddr, raddr, status, pid) namedtuples. In case of limited privileges 'fd' and 'pid' may be set to -1 and None respectively. 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 On OSX this function requires root privileges. """ return _psplatform.net_connections(kind) def net_if_addrs(): """Return the addresses associated to each NIC (network interface card) installed on the system as a dictionary whose keys are the NIC names and value is a list of namedtuples for each address assigned to the NIC. Each namedtuple includes 5 fields: - family - address - netmask - broadcast - ptp 'family' can be either socket.AF_INET, socket.AF_INET6 or psutil.AF_LINK, which refers to a MAC address. 'address' is the primary address and it is always set. 'netmask' and 'broadcast' and 'ptp' may be None. 'ptp' stands for "point to point" and references the destination address on a point to point interface (tipically a VPN). 'broadcast' and 'ptp' are mutually exclusive. Note: you can have more than one address of the same family associated with each interface. """ has_enums = sys.version_info >= (3, 4) if has_enums: import socket rawlist = _psplatform.net_if_addrs() rawlist.sort(key=lambda x: x[1]) # sort by family ret = collections.defaultdict(list) for name, fam, addr, mask, broadcast, ptp in rawlist: if has_enums: try: fam = socket.AddressFamily(fam) except ValueError: if os.name == 'nt' and fam == -1: fam = _psplatform.AF_LINK elif (hasattr(_psplatform, "AF_LINK") and _psplatform.AF_LINK == fam): # Linux defines AF_LINK as an alias for AF_PACKET. # We re-set the family here so that repr(family) # will show AF_LINK rather than AF_PACKET fam = _psplatform.AF_LINK ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp)) return dict(ret) def net_if_stats(): """Return information about each NIC (network interface card) installed on the system as a dictionary whose keys are the NIC names and value is a namedtuple with the following fields: - isup: whether the interface is up (bool) - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or NIC_DUPLEX_UNKNOWN - speed: the NIC speed expressed in mega bits (MB); if it can't be determined (e.g. 'localhost') it will be set to 0. - mtu: the maximum transmission unit expressed in bytes. """ return _psplatform.net_if_stats() # ===================================================================== # --- other system related functions # ===================================================================== def boot_time(): """Return the system boot time expressed in seconds since the epoch.""" # Note: we are not caching this because it is subject to # system clock updates. return _psplatform.boot_time() def users(): """Return users currently connected on the system as a list of namedtuples including the following fields. - 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.users() def test(): # pragma: no cover """List info of all currently running processes emulating ps aux output. """ import datetime today_day = datetime.date.today() templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s" attrs = ['pid', 'cpu_percent', 'memory_percent', 'name', 'cpu_times', 'create_time', 'memory_info'] if _POSIX: attrs.append('uids') attrs.append('terminal') print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "START", "TIME", "COMMAND")) for p in process_iter(): 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") else: ctime = '' cputime = time.strftime("%M:%S", time.localtime(sum(pinfo['cpu_times']))) try: user = p.username() except Error: user = '' if _WINDOWS 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 '?')) del memoize, division if sys.version_info < (3, 0): del num if __name__ == "__main__": test() psutil-3.4.2/psutil/_psutil_bsd.c0000664000175000017500000010107512645412102021000 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil (OpenBSD). * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Platform-specific module methods for FreeBSD and OpenBSD. * OpenBSD references: * - OpenBSD source code: http://anoncvs.spacehopper.org/openbsd-src/ * * OpenBSD / NetBSD: missing APIs compared to FreeBSD implementation: * - psutil.net_connections() * - psutil.Process.get/set_cpu_affinity() (not supported natively) * - psutil.Process.memory_maps() */ #if defined(__NetBSD__) #define _KMEMUSER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for struct xsocket #include #include // for xinpcb struct #include #include #include #include #include #include #include #include // for struct xtcpcb #include // for TCP connection states #include // for inet_ntop() #include #include // net io counters #include #include #include // process open files/connections #include #include "_psutil_bsd.h" #include "_psutil_common.h" #ifdef __FreeBSD__ #include "arch/bsd/freebsd.h" #include "arch/bsd/freebsd_socks.h" #elif __OpenBSD__ #include "arch/bsd/openbsd.h" #elif __NetBSD__ #include "arch/bsd/netbsd.h" #include "arch/bsd/netbsd_socks.h" #endif #ifdef __FreeBSD__ #include #include // get io counters #include // process open files, shared libs (kinfo_getvmmap) #if __FreeBSD_version < 900000 #include // system users #else #include #endif #endif #ifdef __OpenBSD__ #include #include // for VREG #define _KERNEL // for DTYPE_VNODE #include #undef _KERNEL #include // for CPUSTATES & CP_* #endif #if defined(__NetBSD__) #include #include // for VREG #include // for CPUSTATES & CP_* #include // for PAGE_SHIFT #define _KERNEL #include #undef _KERNEL #endif // convert a timeval struct to a double #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) #ifdef __FreeBSD__ // convert a bintime struct to milliseconds #define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * \ (uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000) #endif #if defined(__OpenBSD__) || defined (__NetBSD__) #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) #endif /* * Return a Python list of all the PIDs running on the system. */ static PyObject * psutil_pids(PyObject *self, PyObject *args) { kinfo_proc *proclist = NULL; kinfo_proc *orig_address = NULL; size_t num_processes; size_t idx; PyObject *py_retlist = PyList_New(0); PyObject *py_pid = NULL; if (py_retlist == NULL) return NULL; if (psutil_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++) { #ifdef __FreeBSD__ py_pid = Py_BuildValue("i", proclist->ki_pid); #elif defined(__OpenBSD__) || defined(__NetBSD__) py_pid = Py_BuildValue("i", proclist->p_pid); #endif if (!py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) goto error; Py_DECREF(py_pid); proclist++; } free(orig_address); } return py_retlist; error: Py_XDECREF(py_pid); Py_DECREF(py_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 * psutil_boot_time(PyObject *self, PyObject *args) { // fetch sysctl "kern.boottime" static int request[2] = { CTL_KERN, KERN_BOOTTIME }; struct timeval boottime; size_t len = sizeof(boottime); if (sysctl(request, 2, &boottime, &len, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("d", (double)boottime.tv_sec); } /* * Return process name from kinfo_proc as a Python string. */ static PyObject * psutil_proc_name(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("s", kp.ki_comm); #elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("s", kp.p_comm); #endif } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject * psutil_proc_cmdline(PyObject *self, PyObject *args) { long pid; PyObject *py_retlist = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; py_retlist = psutil_get_cmdline(pid); // psutil_get_cmdline() returns NULL only if psutil_cmd_args // failed with ESRCH (no process with that PID) if (NULL == py_retlist) return PyErr_SetFromErrno(PyExc_OSError); return Py_BuildValue("N", py_retlist); } /* * Return process parent pid from kinfo_proc as a Python integer. */ static PyObject * psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("l", (long)kp.ki_ppid); #elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("l", (long)kp.p_ppid); #endif } /* * Return process status as a Python integer. */ static PyObject * psutil_proc_status(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("i", (int)kp.ki_stat); #elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("i", (int)kp.p_stat); #endif } /* * Return process real, effective and saved user ids from kinfo_proc * as a Python tuple. */ static PyObject * psutil_proc_uids(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", #ifdef __FreeBSD__ (long)kp.ki_ruid, (long)kp.ki_uid, (long)kp.ki_svuid); #elif defined(__OpenBSD__) || defined(__NetBSD__) (long)kp.p_ruid, (long)kp.p_uid, (long)kp.p_svuid); #endif } /* * Return process real, effective and saved group ids from kinfo_proc * as a Python tuple. */ static PyObject * psutil_proc_gids(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", #ifdef __FreeBSD__ (long)kp.ki_rgid, (long)kp.ki_groups[0], (long)kp.ki_svuid); #elif defined(__OpenBSD__) || defined(__NetBSD__) (long)kp.p_rgid, (long)kp.p_groups[0], (long)kp.p_svuid); #endif } /* * Return process real, effective and saved group ids from kinfo_proc * as a Python tuple. */ static PyObject * psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("i", kp.ki_tdev); #elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("i", kp.p_tdev); #endif } /* * Return the number of context switches performed by process as a tuple. */ static PyObject * psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("(ll)", #ifdef __FreeBSD__ kp.ki_rusage.ru_nvcsw, kp.ki_rusage.ru_nivcsw); #elif defined(__OpenBSD__) || defined(__NetBSD__) kp.p_uru_nvcsw, kp.p_uru_nivcsw); #endif } /* * Return a Python tuple (user_time, kernel_time) */ static PyObject * psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; double user_t, sys_t; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; // convert from microseconds to seconds #ifdef __FreeBSD__ user_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime); sys_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime); #elif defined(__OpenBSD__) || defined(__NetBSD__) user_t = PSUTIL_KPT2DOUBLE(kp.p_uutime); sys_t = PSUTIL_KPT2DOUBLE(kp.p_ustime); #endif return Py_BuildValue("(dd)", user_t, sys_t); } /* * Return the number of logical CPUs in the system. * XXX this could be shared with OSX */ static PyObject * psutil_cpu_count_logical(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) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("i", ncpu); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject * psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; #ifdef __FreeBSD__ return Py_BuildValue("d", PSUTIL_TV2DOUBLE(kp.ki_start)); #elif defined(__OpenBSD__) || defined(__NetBSD__) return Py_BuildValue("d", PSUTIL_KPT2DOUBLE(kp.p_ustart)); #endif } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject * psutil_proc_io_counters(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", #ifdef __FreeBSD__ kp.ki_rusage.ru_inblock, kp.ki_rusage.ru_oublock, #elif defined(__OpenBSD__) || defined(__NetBSD__) kp.p_uru_inblock, kp.p_uru_oublock, #endif -1, -1); } #if defined(__OpenBSD__) || defined(__NetBSD__) #define ptoa(x) ((paddr_t)(x) << PAGE_SHIFT) #endif /* * Return extended memory info for a process as a Python tuple. */ static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue( "(lllll)", #ifdef __FreeBSD__ (long) ptoa(kp.ki_rssize), // rss (long) kp.ki_size, // vms (long) ptoa(kp.ki_tsize), // text (long) ptoa(kp.ki_dsize), // data (long) ptoa(kp.ki_ssize) // stack #else (long) ptoa(kp.p_vm_rssize), // rss #ifdef __OpenBSD__ // VMS, this is how ps determines it on OpenBSD: // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461 (long) ptoa(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize), // vms #elif __NetBSD__ // VMS, this is how top determines it on NetBSD: // ftp://ftp.iij.ad.jp/pub/NetBSD/NetBSD-release-6/src/external/bsd/ // top/dist/machine/m_netbsd.c (long) ptoa(kp.p_vm_msize), // vms #endif (long) ptoa(kp.p_vm_tsize), // text (long) ptoa(kp.p_vm_dsize), // data (long) ptoa(kp.p_vm_ssize) // stack #endif ); } /* * Return a Python tuple representing user, kernel and idle CPU times */ static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { #if defined(__NetBSD__) u_int64_t cpu_time[CPUSTATES]; #else long cpu_time[CPUSTATES]; #endif size_t size = sizeof(cpu_time); int ret; #if defined(__FreeBSD__) || defined(__NetBSD__) ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0); #elif __OpenBSD__ int mib[] = {CTL_KERN, KERN_CPTIME}; ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0); #endif if (ret == -1) { PyErr_SetFromErrno(PyExc_OSError); 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 ); } /* * Return files opened by process as a list of (path, fd) tuples. * TODO: this is broken as it may report empty paths. 'procstat' * utility has the same problem see: * https://github.com/giampaolo/psutil/issues/595 */ #if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || __OpenBSD__ || defined(__NetBSD__) static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; kinfo_proc kipp; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; } for (i = 0; i < cnt; i++) { kif = &freep[i]; #ifdef __FreeBSD__ if ((kif->kf_type == KF_TYPE_VNODE) && (kif->kf_vnode_type == KF_VTYPE_VREG)) { py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); #elif defined(__OpenBSD__) if ((kif->f_type == DTYPE_VNODE) && (kif->v_type == VREG)) { py_tuple = Py_BuildValue("(si)", "", kif->fd_fd); #elif defined(__NetBSD__) if ((kif->ki_ftype == DTYPE_VNODE) && (kif->ki_vtype == VREG)) { py_tuple = Py_BuildValue("(si)", "", kif->ki_fd); #endif if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } free(freep); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_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 * psutil_disk_partitions(PyObject *self, PyObject *args) { int num; int i; long len; uint64_t flags; char opts[200]; #if defined(__NetBSD__) struct statvfs *fs = NULL; #else struct statfs *fs = NULL; #endif PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; // get the number of mount points Py_BEGIN_ALLOW_THREADS #if defined(__NetBSD__) num = getvfsstat(NULL, 0, MNT_NOWAIT); #else num = getfsstat(NULL, 0, MNT_NOWAIT); #endif Py_END_ALLOW_THREADS if (num == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } len = sizeof(*fs) * num; fs = malloc(len); if (fs == NULL) { PyErr_NoMemory(); goto error; } Py_BEGIN_ALLOW_THREADS #if defined(__NetBSD__) num = getvfsstat(fs, len, MNT_NOWAIT); #else num = getfsstat(fs, len, MNT_NOWAIT); #endif Py_END_ALLOW_THREADS if (num == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (i = 0; i < num; i++) { py_tuple = NULL; opts[0] = 0; #if defined(__NetBSD__) flags = fs[i].f_flag; #else flags = fs[i].f_flags; #endif // 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_ASYNC) strlcat(opts, ",async", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); if (flags & MNT_SOFTDEP) strlcat(opts, ",softdep", sizeof(opts)); #ifdef __FreeBSD__ if (flags & MNT_UNION) strlcat(opts, ",union", 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_NOCLUSTERR) strlcat(opts, ",noclusterr", sizeof(opts)); if (flags & MNT_NOCLUSTERW) strlcat(opts, ",noclusterw", sizeof(opts)); if (flags & MNT_NFS4ACLS) strlcat(opts, ",nfs4acls", sizeof(opts)); #elif __NetBSD__ if (flags & MNT_NODEV) strlcat(opts, ",nodev", sizeof(opts)); if (flags & MNT_UNION) strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_NOCOREDUMP) strlcat(opts, ",nocoredump", sizeof(opts)); if (flags & MNT_RELATIME) strlcat(opts, ",relatime", sizeof(opts)); if (flags & MNT_IGNORE) strlcat(opts, ",ignore", sizeof(opts)); if (flags & MNT_DISCARD) strlcat(opts, ",discard", sizeof(opts)); if (flags & MNT_EXTATTR) strlcat(opts, ",extattr", sizeof(opts)); if (flags & MNT_LOG) strlcat(opts, ",log", sizeof(opts)); if (flags & MNT_SYMPERM) strlcat(opts, ",symperm", sizeof(opts)); if (flags & MNT_NODEVMTIME) strlcat(opts, ",nodevmtime", sizeof(opts)); #endif 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 * psutil_net_io_counters(PyObject *self, PyObject *args) { char *buf = NULL, *lim, *next; struct if_msghdr *ifm; int mib[6]; size_t len; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; if (py_retdict == NULL) return NULL; 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(PyExc_OSError); goto error; } buf = malloc(len); if (buf == NULL) { PyErr_NoMemory(); goto error; } if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); 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; // XXX: ignore usbus interfaces: // http://lists.freebsd.org/pipermail/freebsd-current/ // 2011-October/028752.html // 'ifconfig -a' doesn't show them, nor do we. if (strncmp(ifc_name, "usbus", 5) == 0) continue; 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 currently connected users as a list of tuples. */ static PyObject * psutil_users(PyObject *self, PyObject *args) { PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; #if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || __OpenBSD__ struct utmp ut; FILE *fp; fp = fopen(_PATH_UTMP, "r"); if (fp == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } while (fread(&ut, sizeof(ut), 1, fp) == 1) { if (*ut.ut_name == '\0') continue; py_tuple = Py_BuildValue( "(sssf)", ut.ut_name, // username ut.ut_line, // tty ut.ut_host, // hostname (float)ut.ut_time); // start time if (!py_tuple) { fclose(fp); goto error; } if (PyList_Append(py_retlist, py_tuple)) { fclose(fp); goto error; } Py_DECREF(py_tuple); } fclose(fp); #else struct utmpx *utx; setutxent(); while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; py_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 (!py_tuple) { endutxent(); goto error; } if (PyList_Append(py_retlist, py_tuple)) { endutxent(); goto error; } Py_DECREF(py_tuple); } endutxent(); #endif return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions {"proc_name", psutil_proc_name, METH_VARARGS, "Return process name"}, {"proc_connections", psutil_proc_connections, METH_VARARGS, "Return connections opened by process"}, {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_ppid", psutil_proc_ppid, METH_VARARGS, "Return process ppid as an integer"}, {"proc_uids", psutil_proc_uids, METH_VARARGS, "Return process real effective and saved user ids as a Python tuple"}, {"proc_gids", psutil_proc_gids, METH_VARARGS, "Return process real effective and saved group ids as a Python tuple"}, {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"proc_create_time", psutil_proc_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, "Return extended memory info for a process as a Python tuple."}, {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"proc_threads", psutil_proc_threads, METH_VARARGS, "Return process threads"}, {"proc_status", psutil_proc_status, METH_VARARGS, "Return process status as an integer"}, {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, "Return process IO counters"}, {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, #if defined(__FreeBSD__) || defined(__OpenBSD__) {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__) {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__) {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, #endif #if defined(__FreeBSD__) || defined(__NetBSD__) {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return process pathname executable"}, {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, "Return number of threads used by process"}, #if defined(__FreeBSD__) {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, "Return process CPU affinity."}, {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, "Set process CPU affinity."}, {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return an XML string to determine the number physical CPUs."}, #endif #endif // --- system-related functions {"pids", psutil_pids, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, "Return number of logical CPUs on the system"}, {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return system virtual memory usage statistics"}, {"swap_mem", psutil_swap_mem, METH_VARARGS, "Return swap mem stats"}, {"cpu_times", psutil_cpu_times, METH_VARARGS, "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, {"boot_time", psutil_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS, "Return a list of tuples including device, mount point and " "fs type for all partitions mounted on the system."}, {"net_io_counters", psutil_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, "Return a Python dict of tuples for disk I/O information"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, #if defined(__FreeBSD__) || defined(__NetBSD__) {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide open connections."}, #endif {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 PyMODINIT_FUNC 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, "version", PSUTIL_VERSION); // process status constants #ifdef __FreeBSD__ PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SZOMB", SZOMB); PyModule_AddIntConstant(module, "SWAIT", SWAIT); PyModule_AddIntConstant(module, "SLOCK", SLOCK); #elif __OpenBSD__ PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused PyModule_AddIntConstant(module, "SDEAD", SDEAD); PyModule_AddIntConstant(module, "SONPROC", SONPROC); #elif defined(__NetBSD__) PyModule_AddIntConstant(module, "SIDL", LSIDL); PyModule_AddIntConstant(module, "SRUN", LSRUN); PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP); PyModule_AddIntConstant(module, "SSTOP", LSSTOP); PyModule_AddIntConstant(module, "SZOMB", LSZOMB); PyModule_AddIntConstant(module, "SDEAD", LSDEAD); PyModule_AddIntConstant(module, "SONPROC", LSONPROC); // unique to NetBSD PyModule_AddIntConstant(module, "SSUSPENDED", LSSUSPENDED); #endif // connection status constants PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); // PSUTIL_CONN_NONE PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128); if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_psutil_posix.c0000664000175000017500000003500212645406531021377 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Functions specific to all POSIX compliant platforms. */ #include #include #include #include #include #include #include #include #ifdef PSUTIL_SUNOS10 #include "arch/solaris10/ifaddrs.h" #else #include #endif #ifdef __linux #include #include #endif // end linux #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) #include #include #include #endif #if defined(__sun) #include #endif #include "_psutil_posix.h" /* * Given a PID return process priority as a Python integer. */ static PyObject * psutil_posix_getpriority(PyObject *self, PyObject *args) { long pid; int priority; errno = 0; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; priority = getpriority(PRIO_PROCESS, pid); if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); return Py_BuildValue("i", priority); } /* * Given a PID and a value change process priority. */ static PyObject * psutil_posix_setpriority(PyObject *self, PyObject *args) { long pid; int priority; int retval; if (! PyArg_ParseTuple(args, "li", &pid, &priority)) return NULL; retval = setpriority(PRIO_PROCESS, pid, priority); if (retval == -1) return PyErr_SetFromErrno(PyExc_OSError); Py_RETURN_NONE; } /* * Translate a sockaddr struct into a Python string. * Return None if address family is not AF_INET* or AF_PACKET. */ static PyObject * psutil_convert_ipaddr(struct sockaddr *addr, int family) { char buf[NI_MAXHOST]; int err; int addrlen; int n; size_t len; const char *data; char *ptr; if (addr == NULL) { Py_INCREF(Py_None); return Py_None; } else if (family == AF_INET || family == AF_INET6) { if (family == AF_INET) addrlen = sizeof(struct sockaddr_in); else addrlen = sizeof(struct sockaddr_in6); err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); if (err != 0) { // XXX we get here on FreeBSD when processing 'lo' / AF_INET6 // broadcast. Not sure what to do other than returning None. // ifconfig does not show anything BTW. //PyErr_Format(PyExc_RuntimeError, gai_strerror(err)); //return NULL; Py_INCREF(Py_None); return Py_None; } else { return Py_BuildValue("s", buf); } } #ifdef __linux else if (family == AF_PACKET) { struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr; len = lladdr->sll_halen; data = (const char *)lladdr->sll_addr; } #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) else if (addr->sa_family == AF_LINK) { // Note: prior to Python 3.4 socket module does not expose // AF_LINK so we'll do. struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr; len = dladdr->sdl_alen; data = LLADDR(dladdr); } #endif else { // unknown family Py_INCREF(Py_None); return Py_None; } // AF_PACKET or AF_LINK if (len > 0) { ptr = buf; for (n = 0; n < len; ++n) { sprintf(ptr, "%02x:", data[n] & 0xff); ptr += 3; } *--ptr = '\0'; return Py_BuildValue("s", buf); } else { Py_INCREF(Py_None); return Py_None; } } /* * Return NICs information a-la ifconfig as a list of tuples. * TODO: on Solaris we won't get any MAC address. */ static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args) { struct ifaddrs *ifaddr, *ifa; int family; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_address = NULL; PyObject *py_netmask = NULL; PyObject *py_broadcast = NULL; PyObject *py_ptp = NULL; if (py_retlist == NULL) return NULL; if (getifaddrs(&ifaddr) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; family = ifa->ifa_addr->sa_family; py_address = psutil_convert_ipaddr(ifa->ifa_addr, family); // If the primary address can't be determined just skip it. // I've never seen this happen on Linux but I did on FreeBSD. if (py_address == Py_None) continue; if (py_address == NULL) goto error; py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family); if (py_netmask == NULL) goto error; if (ifa->ifa_flags & IFF_BROADCAST) { py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family); Py_INCREF(Py_None); py_ptp = Py_None; } else if (ifa->ifa_flags & IFF_POINTOPOINT) { py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family); Py_INCREF(Py_None); py_broadcast = Py_None; } else { Py_INCREF(Py_None); Py_INCREF(Py_None); py_broadcast = Py_None; py_ptp = Py_None; } if ((py_broadcast == NULL) || (py_ptp == NULL)) goto error; py_tuple = Py_BuildValue( "(siOOOO)", ifa->ifa_name, family, py_address, py_netmask, py_broadcast, py_ptp ); if (! py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_DECREF(py_address); Py_DECREF(py_netmask); Py_DECREF(py_broadcast); Py_DECREF(py_ptp); } freeifaddrs(ifaddr); return py_retlist; error: if (ifaddr != NULL) freeifaddrs(ifaddr); Py_DECREF(py_retlist); Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_XDECREF(py_netmask); Py_XDECREF(py_broadcast); Py_XDECREF(py_ptp); return NULL; } /* * net_if_stats() implementation. This is here because it is common * to both OSX and FreeBSD and I didn't know where else to put it. */ #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) #include #include #include int psutil_get_nic_speed(int ifm_active) { // Determine NIC speed. Taken from: // http://www.i-scream.org/libstatgrab/ // Assuming only ETHER devices switch(IFM_TYPE(ifm_active)) { case IFM_ETHER: switch(IFM_SUBTYPE(ifm_active)) { #if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \ || (IFM_10G_LR != IFM_HPNA_1)) // HomePNA 1.0 (1Mb/s) case(IFM_HPNA_1): return 1; #endif // 10 Mbit case(IFM_10_T): // 10BaseT - RJ45 case(IFM_10_2): // 10Base2 - Thinnet case(IFM_10_5): // 10Base5 - AUI case(IFM_10_STP): // 10BaseT over shielded TP case(IFM_10_FL): // 10baseFL - Fiber return 10; // 100 Mbit case(IFM_100_TX): // 100BaseTX - RJ45 case(IFM_100_FX): // 100BaseFX - Fiber case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3 case(IFM_100_VG): // 100VG-AnyLAN case(IFM_100_T2): // 100BaseT2 return 100; // 1000 Mbit case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber case(IFM_1000_LX): // 1000baseLX - single-mode fiber case(IFM_1000_CX): // 1000baseCX - 150ohm STP #if defined(IFM_1000_TX) && !defined(__OpenBSD__) // FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h case(IFM_1000_TX): #endif #ifdef IFM_1000_FX case(IFM_1000_FX): #endif #ifdef IFM_1000_T case(IFM_1000_T): #endif return 1000; #if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \ || defined(IFM_10G_T) #ifdef IFM_10G_SR case(IFM_10G_SR): #endif #ifdef IFM_10G_LR case(IFM_10G_LR): #endif #ifdef IFM_10G_CX4 case(IFM_10G_CX4): #endif #ifdef IFM_10G_TWINAX case(IFM_10G_TWINAX): #endif #ifdef IFM_10G_TWINAX_LONG case(IFM_10G_TWINAX_LONG): #endif #ifdef IFM_10G_T case(IFM_10G_T): #endif return 10000; #endif #if defined(IFM_2500_SX) #ifdef IFM_2500_SX case(IFM_2500_SX): #endif return 2500; #endif // any 2.5GBit stuff... // We don't know what it is default: return 0; } break; #ifdef IFM_TOKEN case IFM_TOKEN: switch(IFM_SUBTYPE(ifm_active)) { case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9 case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45 return 4; case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9 case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45 return 16; #if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100) #ifdef IFM_TOK_STP100 case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9 #endif #ifdef IFM_TOK_UTP100 case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45 #endif return 100; #endif // We don't know what it is default: return 0; } break; #endif #ifdef IFM_FDDI case IFM_FDDI: switch(IFM_SUBTYPE(ifm_active)) { // We don't know what it is default: return 0; } break; #endif case IFM_IEEE80211: switch(IFM_SUBTYPE(ifm_active)) { case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps return 1; case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps return 2; case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps return 5; case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps return 11; case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps return 22; // We don't know what it is default: return 0; } break; default: return 0; } } /* * Return stats about a particular network interface. * References: * http://www.i-scream.org/libstatgrab/ */ static PyObject * psutil_net_if_stats(PyObject *self, PyObject *args) { char *nic_name; int sock = 0; int ret; int duplex; int speed; int mtu; struct ifreq ifr; struct ifmediareq ifmed; PyObject *py_is_up = NULL; if (! PyArg_ParseTuple(args, "s", &nic_name)) return NULL; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) goto error; strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); // is up? ret = ioctl(sock, SIOCGIFFLAGS, &ifr); if (ret == -1) goto error; if ((ifr.ifr_flags & IFF_UP) != 0) py_is_up = Py_True; else py_is_up = Py_False; Py_INCREF(py_is_up); // MTU ret = ioctl(sock, SIOCGIFMTU, &ifr); if (ret == -1) goto error; mtu = ifr.ifr_mtu; // speed / duplex memset(&ifmed, 0, sizeof(struct ifmediareq)); strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name)); ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed); if (ret == -1) { speed = 0; duplex = 0; } else { speed = psutil_get_nic_speed(ifmed.ifm_active); if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active) duplex = 2; else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active) duplex = 1; else duplex = 0; } close(sock); Py_DECREF(py_is_up); return Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu); error: Py_XDECREF(py_is_up); if (sock != 0) close(sock); PyErr_SetFromErrno(PyExc_OSError); return NULL; } #endif // net_if_stats() implementation /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { {"getpriority", psutil_posix_getpriority, METH_VARARGS, "Return process priority"}, {"setpriority", psutil_posix_setpriority, METH_VARARGS, "Set process priority"}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, "Retrieve NICs information"}, #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NIC stats."}, #endif {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_posix_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_posix", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_posix_traverse, psutil_posix_clear, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__psutil_posix(void) #else #define INITERROR return void init_psutil_posix(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) || defined(__NetBSD__) PyModule_AddIntConstant(module, "AF_LINK", AF_LINK); #endif if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_psutil_common.c0000664000175000017500000000155112572074510021524 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 /* * 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; } psutil-3.4.2/psutil/_psutil_osx.c0000664000175000017500000015324612621206131021045 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * OS X platform-specific module methods for _psutil_osx */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_psutil_osx.h" #include "_psutil_common.h" #include "arch/osx/process_info.h" #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) /* * A wrapper around host_statistics() invoked with HOST_VM_INFO. */ int psutil_sys_vminfo(vm_statistics_data_t *vmstat) { kern_return_t ret; mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); mach_port_t mport = mach_host_self(); ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)vmstat, &count); if (ret != KERN_SUCCESS) { PyErr_Format(PyExc_RuntimeError, "host_statistics() failed: %s", mach_error_string(ret)); return 0; } mach_port_deallocate(mach_task_self(), mport); return 1; } /* * Set exception to AccessDenied if pid exists else NoSuchProcess. */ void psutil_raise_ad_or_nsp(long pid) { int ret; ret = psutil_pid_exists(pid); if (ret == 0) NoSuchProcess(); else AccessDenied(); } /* * Return a Python list of all the PIDs running on the system. */ static PyObject * psutil_pids(PyObject *self, PyObject *args) { kinfo_proc *proclist = NULL; kinfo_proc *orig_address = NULL; size_t num_processes; size_t idx; PyObject *py_pid = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (psutil_get_proc_list(&proclist, &num_processes) != 0) { PyErr_SetString(PyExc_RuntimeError, "failed to retrieve process list."); goto error; } if (num_processes > 0) { // save the address of proclist so we can free it later orig_address = proclist; for (idx = 0; idx < num_processes; idx++) { py_pid = Py_BuildValue("i", proclist->kp_proc.p_pid); if (! py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) goto error; Py_DECREF(py_pid); proclist++; } free(orig_address); } return py_retlist; error: Py_XDECREF(py_pid); Py_DECREF(py_retlist); if (orig_address != NULL) free(orig_address); return NULL; } /* * Return process name from kinfo_proc as a Python string. */ static PyObject * psutil_proc_name(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("s", kp.kp_proc.p_comm); } /* * Return process current working directory. */ static PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { long pid; struct proc_vnodepathinfo pathinfo; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo, sizeof(pathinfo))) { return NULL; } return Py_BuildValue("s", pathinfo.pvi_cdir.vip_path); } /* * Return path of the process executable. */ static PyObject * psutil_proc_exe(PyObject *self, PyObject *args) { long pid; char buf[PATH_MAX]; int ret; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; ret = proc_pidpath(pid, &buf, sizeof(buf)); if (ret == 0) { psutil_raise_ad_or_nsp(pid); return NULL; } return Py_BuildValue("s", buf); } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject * psutil_proc_cmdline(PyObject *self, PyObject *args) { long pid; PyObject *py_retlist = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; // get the commandline, defined in arch/osx/process_info.c py_retlist = psutil_get_cmdline(pid); return py_retlist; } /* * Return process parent pid from kinfo_proc as a Python integer. */ static PyObject * psutil_proc_ppid(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid); } /* * Return process real uid from kinfo_proc as a Python integer. */ static PyObject * psutil_proc_uids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_ruid, (long)kp.kp_eproc.e_ucred.cr_uid, (long)kp.kp_eproc.e_pcred.p_svuid); } /* * Return process real group id from ki_comm as a Python integer. */ static PyObject * psutil_proc_gids(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_rgid, (long)kp.kp_eproc.e_ucred.cr_groups[0], (long)kp.kp_eproc.e_pcred.p_svgid); } /* * Return process controlling terminal number as an integer. */ static PyObject * psutil_proc_tty_nr(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("i", kp.kp_eproc.e_tdev); } /* * Return a list of tuples for every process memory maps. * 'procstat' cmdline utility has been used as an example. */ static PyObject * psutil_proc_memory_maps(PyObject *self, PyObject *args) { char buf[PATH_MAX]; char addr_str[34]; char perms[8]; int pagesize = getpagesize(); long pid; kern_return_t err = KERN_SUCCESS; mach_port_t task = MACH_PORT_NULL; uint32_t depth = 1; vm_address_t address = 0; vm_size_t size = 0; PyObject *py_tuple = NULL; PyObject *py_list = PyList_New(0); if (py_list == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; err = task_for_pid(mach_task_self(), pid, &task); if (err != KERN_SUCCESS) { psutil_raise_ad_or_nsp(pid); goto error; } while (1) { py_tuple = NULL; struct vm_region_submap_info_64 info; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; err = vm_region_recurse_64(task, &address, &size, &depth, (vm_region_info_64_t)&info, &count); if (err == KERN_INVALID_ADDRESS) break; if (info.is_submap) { depth++; } else { // Free/Reset the char[]s to avoid weird paths memset(buf, 0, sizeof(buf)); memset(addr_str, 0, sizeof(addr_str)); memset(perms, 0, sizeof(perms)); sprintf(addr_str, "%016lx-%016lx", address, address + size); sprintf(perms, "%c%c%c/%c%c%c", (info.protection & VM_PROT_READ) ? 'r' : '-', (info.protection & VM_PROT_WRITE) ? 'w' : '-', (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', (info.max_protection & VM_PROT_READ) ? 'r' : '-', (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-'); err = proc_regionfilename(pid, address, buf, sizeof(buf)); if (info.share_mode == SM_COW && info.ref_count == 1) { // Treat single reference SM_COW as SM_PRIVATE info.share_mode = SM_PRIVATE; } if (strlen(buf) == 0) { switch (info.share_mode) { // case SM_LARGE_PAGE: // Treat SM_LARGE_PAGE the same as SM_PRIVATE // since they are not shareable and are wired. case SM_COW: strcpy(buf, "[cow]"); break; case SM_PRIVATE: strcpy(buf, "[prv]"); break; case SM_EMPTY: strcpy(buf, "[nul]"); break; case SM_SHARED: case SM_TRUESHARED: strcpy(buf, "[shm]"); break; case SM_PRIVATE_ALIASED: strcpy(buf, "[ali]"); break; case SM_SHARED_ALIASED: strcpy(buf, "[s/a]"); break; default: strcpy(buf, "[???]"); } } py_tuple = Py_BuildValue( "sssIIIIIH", addr_str, // "start-end"address perms, // "rwx" permissions buf, // path info.pages_resident * pagesize, // rss info.pages_shared_now_private * pagesize, // private info.pages_swapped_out * pagesize, // swapped info.pages_dirtied * pagesize, // dirtied info.ref_count, // ref count info.shadow_depth // shadow depth ); if (!py_tuple) goto error; if (PyList_Append(py_list, py_tuple)) goto error; Py_DECREF(py_tuple); } // increment address for the next map/file address += size; } if (task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), task); return py_list; error: if (task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), task); Py_XDECREF(py_tuple); Py_DECREF(py_list); return NULL; } /* * Return the number of logical CPUs in the system. * XXX this could be shared with BSD. */ static PyObject * psutil_cpu_count_logical(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) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("i", ncpu); */ int num; size_t size = sizeof(int); if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2)) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("i", num); } /* * Return the number of physical CPUs in the system. */ static PyObject * psutil_cpu_count_phys(PyObject *self, PyObject *args) { int num; size_t size = sizeof(int); if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("i", num); } /* * Return a Python tuple (user_time, kernel_time) */ static PyObject * psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; return Py_BuildValue("(dd)", (float)pti.pti_total_user / 1000000000.0, (float)pti.pti_total_system / 1000000000.0); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject * psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("d", PSUTIL_TV2DOUBLE(kp.kp_proc.p_starttime)); } /* * Return extended memory info about a process. */ static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; // Note: determining other memory stats on OSX is a mess: // http://www.opensource.apple.com/source/top/top-67/libtop.c?txt // I just give up... // struct proc_regioninfo pri; // psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, &pri, sizeof(pri)) return Py_BuildValue( "(KKkk)", pti.pti_resident_size, // resident memory size (rss) pti.pti_virtual_size, // virtual memory size (vms) pti.pti_faults, // number of page faults (pages) pti.pti_pageins // number of actual pageins (pages) ); } /* * Return number of threads used by process as a Python integer. */ static PyObject * psutil_proc_num_threads(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; return Py_BuildValue("k", pti.pti_threadnum); } /* * Return the number of context switches performed by process. */ static PyObject * psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) return NULL; // unvoluntary value seems not to be available; // pti.pti_csw probably refers to the sum of the two (getrusage() // numbers seems to confirm this theory). return Py_BuildValue("ki", pti.pti_csw, 0); } /* * Return system virtual memory stats */ static PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { int mib[2]; uint64_t total; size_t len = sizeof(total); vm_statistics_data_t vm; int pagesize = getpagesize(); // physical mem mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; // This is also available as sysctlbyname("hw.memsize"). if (sysctl(mib, 2, &total, &len, NULL, 0)) { if (errno != 0) PyErr_SetFromErrno(PyExc_OSError); else PyErr_Format(PyExc_RuntimeError, "sysctl(HW_MEMSIZE) failed"); return NULL; } // vm if (!psutil_sys_vminfo(&vm)) return NULL; return Py_BuildValue( "KKKKK", total, (unsigned long long) vm.active_count * pagesize, (unsigned long long) vm.inactive_count * pagesize, (unsigned long long) vm.wire_count * pagesize, (unsigned long long) vm.free_count * pagesize ); } /* * Return stats about swap memory. */ static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { int mib[2]; size_t size; struct xsw_usage totals; vm_statistics_data_t vmstat; int pagesize = getpagesize(); mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; size = sizeof(totals); if (sysctl(mib, 2, &totals, &size, NULL, 0) == -1) { if (errno != 0) PyErr_SetFromErrno(PyExc_OSError); else PyErr_Format(PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) failed"); return NULL; } if (!psutil_sys_vminfo(&vmstat)) return NULL; return Py_BuildValue( "LLLKK", totals.xsu_total, totals.xsu_used, totals.xsu_avail, (unsigned long long)vmstat.pageins * pagesize, (unsigned long long)vmstat.pageouts * pagesize); } /* * Return a Python tuple representing user, kernel and idle CPU times */ static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; kern_return_t error; host_cpu_load_info_data_t r_load; mach_port_t host_port = mach_host_self(); error = host_statistics(host_port, HOST_CPU_LOAD_INFO, (host_info_t)&r_load, &count); if (error != KERN_SUCCESS) return PyErr_Format(PyExc_RuntimeError, "Error in host_statistics(): %s", mach_error_string(error)); mach_port_deallocate(mach_task_self(), host_port); return Py_BuildValue( "(dddd)", (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK, (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK, (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK ); } /* * Return a Python list of tuple representing per-cpu times */ static PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { natural_t cpu_count; processor_info_array_t info_array; mach_msg_type_number_t info_count; kern_return_t error; processor_cpu_load_info_data_t *cpu_load_info = NULL; int i, ret; PyObject *py_retlist = PyList_New(0); PyObject *py_cputime = NULL; if (py_retlist == NULL) return NULL; mach_port_t host_port = mach_host_self(); error = host_processor_info(host_port, PROCESSOR_CPU_LOAD_INFO, &cpu_count, &info_array, &info_count); if (error != KERN_SUCCESS) { PyErr_Format(PyExc_RuntimeError, "Error in host_processor_info(): %s", mach_error_string(error)); goto error; } mach_port_deallocate(mach_task_self(), host_port); cpu_load_info = (processor_cpu_load_info_data_t *) info_array; for (i = 0; i < cpu_count; i++) { py_cputime = Py_BuildValue( "(dddd)", (double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK, (double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK, (double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK, (double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK ); if (!py_cputime) goto error; if (PyList_Append(py_retlist, py_cputime)) goto error; Py_DECREF(py_cputime); } ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count * sizeof(int)); if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); return py_retlist; error: Py_XDECREF(py_cputime); Py_DECREF(py_retlist); if (cpu_load_info != NULL) { ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array, info_count * sizeof(int)); if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); } return NULL; } /* * Return a Python float indicating the system boot time expressed in * seconds since the epoch. */ static PyObject * psutil_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(PyExc_OSError); return NULL; } boot_time = result.tv_sec; return Py_BuildValue("f", (float)boot_time); } /* * Return a list of tuples including device, mount point and fs type * for all partitions mounted on the system. */ static PyObject * psutil_disk_partitions(PyObject *self, PyObject *args) { int num; int i; long len; uint64_t flags; char opts[400]; struct statfs *fs = NULL; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return 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(PyExc_OSError); goto error; } len = sizeof(*fs) * num; fs = malloc(len); if (fs == NULL) { PyErr_NoMemory(); goto error; } Py_BEGIN_ALLOW_THREADS num = getfsstat(fs, len, MNT_NOWAIT); Py_END_ALLOW_THREADS if (num == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (i = 0; i < num; i++) { opts[0] = 0; flags = fs[i].f_flags; // see sys/mount.h if (flags & MNT_RDONLY) strlcat(opts, "ro", sizeof(opts)); else strlcat(opts, "rw", sizeof(opts)); if (flags & MNT_SYNCHRONOUS) strlcat(opts, ",sync", sizeof(opts)); if (flags & MNT_NOEXEC) strlcat(opts, ",noexec", sizeof(opts)); if (flags & MNT_NOSUID) strlcat(opts, ",nosuid", sizeof(opts)); if (flags & MNT_UNION) strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_ASYNC) strlcat(opts, ",async", sizeof(opts)); if (flags & MNT_EXPORTED) strlcat(opts, ",exported", sizeof(opts)); if (flags & MNT_QUARANTINE) strlcat(opts, ",quarantine", sizeof(opts)); if (flags & MNT_LOCAL) strlcat(opts, ",local", sizeof(opts)); if (flags & MNT_QUOTA) strlcat(opts, ",quota", sizeof(opts)); if (flags & MNT_ROOTFS) strlcat(opts, ",rootfs", sizeof(opts)); if (flags & MNT_DOVOLFS) strlcat(opts, ",dovolfs", sizeof(opts)); if (flags & MNT_DONTBROWSE) strlcat(opts, ",dontbrowse", sizeof(opts)); if (flags & MNT_IGNORE_OWNERSHIP) strlcat(opts, ",ignore-ownership", sizeof(opts)); if (flags & MNT_AUTOMOUNTED) strlcat(opts, ",automounted", sizeof(opts)); if (flags & MNT_JOURNALED) strlcat(opts, ",journaled", sizeof(opts)); if (flags & MNT_NOUSERXATTR) strlcat(opts, ",nouserxattr", sizeof(opts)); if (flags & MNT_DEFWRITE) strlcat(opts, ",defwrite", sizeof(opts)); if (flags & MNT_MULTILABEL) strlcat(opts, ",multilabel", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); if (flags & MNT_UPDATE) strlcat(opts, ",update", sizeof(opts)); if (flags & MNT_RELOAD) strlcat(opts, ",reload", sizeof(opts)); if (flags & MNT_FORCE) strlcat(opts, ",force", sizeof(opts)); if (flags & MNT_CMDFLAGS) strlcat(opts, ",cmdflags", sizeof(opts)); py_tuple = Py_BuildValue( "(ssss)", fs[i].f_mntfromname, // device fs[i].f_mntonname, // mount point fs[i].f_fstypename, // fs type opts); // options if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(fs); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (fs != NULL) free(fs); return NULL; } /* * Return process status as a Python integer. */ static PyObject * psutil_proc_status(PyObject *self, PyObject *args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("i", (int)kp.kp_proc.p_stat); } /* * Return process threads */ static PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { long pid; int err, j, ret; kern_return_t kr; unsigned int info_count = TASK_BASIC_INFO_COUNT; mach_port_t task = MACH_PORT_NULL; struct task_basic_info tasks_info; thread_act_port_array_t thread_list = NULL; thread_info_data_t thinfo_basic; thread_basic_info_t basic_info_th; mach_msg_type_number_t thread_count, thread_info_count; PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; // the argument passed should be a process id if (! PyArg_ParseTuple(args, "l", &pid)) goto error; // task_for_pid() requires special privileges err = task_for_pid(mach_task_self(), pid, &task); if (err != KERN_SUCCESS) { psutil_raise_ad_or_nsp(pid); goto error; } info_count = TASK_BASIC_INFO_COUNT; err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count); if (err != KERN_SUCCESS) { // errcode 4 is "invalid argument" (access denied) if (err == 4) { AccessDenied(); } else { // otherwise throw a runtime error with appropriate error code PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } goto error; } err = task_threads(task, &thread_list, &thread_count); if (err != KERN_SUCCESS) { PyErr_Format(PyExc_RuntimeError, "task_threads() failed"); goto error; } for (j = 0; j < thread_count; j++) { py_tuple = NULL; thread_info_count = THREAD_INFO_MAX; kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo_basic, &thread_info_count); if (kr != KERN_SUCCESS) { PyErr_Format(PyExc_RuntimeError, "thread_info() with flag THREAD_BASIC_INFO failed"); goto error; } basic_info_th = (thread_basic_info_t)thinfo_basic; py_tuple = Py_BuildValue( "Iff", j + 1, (float)basic_info_th->user_time.microseconds / 1000000.0, (float)basic_info_th->system_time.microseconds / 1000000.0 ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); mach_port_deallocate(mach_task_self(), task); return py_retlist; error: if (task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), task); Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (thread_list != NULL) { ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); if (ret != KERN_SUCCESS) PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); } return NULL; } /* * Return process open files as a Python tuple. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd * - /usr/include/sys/proc_info.h */ static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer = NULL; struct proc_fdinfo *fdp_pointer; struct vnode_fdinfowithpath vi; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { // may be be ignored later if errno != 0 PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); goto error; } fds_pointer = malloc(pidinfo_result); if (fds_pointer == NULL) { PyErr_NoMemory(); goto error; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); if (pidinfo_result <= 0) { // may be be ignored later if errno != 0 PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); goto error; } iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { py_tuple = NULL; fdp_pointer = &fds_pointer[i]; if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); // --- errors checking if (nb <= 0) { if ((errno == ENOENT) || (errno == EBADF)) { // no such file or directory or bad file descriptor; // let's assume the file has been closed or removed continue; } // may be be ignored later if errno != 0 PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); goto error; } if (nb < sizeof(vi)) { PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed " "(buffer mismatch)"); goto error; } // --- /errors checking // --- construct python list py_tuple = Py_BuildValue( "(si)", vi.pvip.vip_path, (int)fdp_pointer->proc_fd); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); // --- /construct python list } } free(fds_pointer); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (fds_pointer != NULL) free(fds_pointer); if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); else if (! psutil_pid_exists(pid)) return NoSuchProcess(); else return NULL; // exception has already been set earlier } // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; /* * Return process TCP and UDP connections as a list of tuples. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0 * - /usr/include/sys/proc_info.h */ static PyObject * psutil_proc_connections(PyObject *self, PyObject *args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer = NULL; struct proc_fdinfo *fdp_pointer; struct socket_fdinfo si; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) goto error; if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } if (pid == 0) return py_retlist; pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) goto error; fds_pointer = malloc(pidinfo_result); if (fds_pointer == NULL) { PyErr_NoMemory(); goto error; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); if (pidinfo_result <= 0) goto error; iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE); for (i = 0; i < iterations; i++) { py_tuple = NULL; py_laddr = NULL; py_raddr = NULL; errno = 0; fdp_pointer = &fds_pointer[i]; if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); // --- errors checking if (nb <= 0) { if (errno == EBADF) { // let's assume socket has been closed continue; } if (errno != 0) PyErr_SetFromErrno(PyExc_OSError); else PyErr_Format( PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); goto error; } if (nb < sizeof(si)) { PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed " "(buffer mismatch)"); goto error; } // --- /errors checking // int fd, family, type, lport, rport, state; char lip[200], rip[200]; int inseq; PyObject *py_family; PyObject *py_type; fd = (int)fdp_pointer->proc_fd; family = si.psi.soi_family; type = si.psi.soi_type; // apply filters py_family = PyLong_FromLong((long)family); inseq = PySequence_Contains(py_af_filter, py_family); Py_DECREF(py_family); if (inseq == 0) continue; py_type = PyLong_FromLong((long)type); inseq = PySequence_Contains(py_type_filter, py_type); Py_DECREF(py_type); if (inseq == 0) continue; if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if ((family == AF_INET) || (family == AF_INET6)) { if (family == AF_INET) { inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ insi_laddr.ina_46.i46a_addr4, lip, sizeof(lip)); inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr. \ ina_46.i46a_addr4, rip, sizeof(rip)); } else { inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ insi_laddr.ina_6, lip, sizeof(lip)); inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini. \ insi_faddr.ina_6, rip, sizeof(rip)); } // check for inet_ntop failures if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); if (type == SOCK_STREAM) state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state; else state = PSUTIL_CONN_NONE; py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; // construct the python list py_tuple = Py_BuildValue( "(iiiNNi)", fd, family, type, py_laddr, py_raddr, state); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } else if (family == AF_UNIX) { // construct the python list py_tuple = Py_BuildValue( "(iiissi)", fd, family, type, si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path, si.psi.soi_proto.pri_un.unsi_caddr.ua_sun.sun_path, PSUTIL_CONN_NONE); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } } free(fds_pointer); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); Py_DECREF(py_retlist); if (fds_pointer != NULL) free(fds_pointer); if (errno != 0) return PyErr_SetFromErrno(PyExc_OSError); else if (! psutil_pid_exists(pid)) return NoSuchProcess(); else return PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDLISTFDS) failed"); } /* * Return number of file descriptors opened by process. */ static PyObject * psutil_proc_num_fds(PyObject *self, PyObject *args) { long pid; int pidinfo_result; int num; struct proc_fdinfo *fds_pointer; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) return PyErr_SetFromErrno(PyExc_OSError); fds_pointer = malloc(pidinfo_result); if (fds_pointer == NULL) return PyErr_NoMemory(); pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer, pidinfo_result); if (pidinfo_result <= 0) { free(fds_pointer); return PyErr_SetFromErrno(PyExc_OSError); } num = (pidinfo_result / PROC_PIDLISTFD_SIZE); free(fds_pointer); return Py_BuildValue("i", num); } /* * Return a Python list of named tuples with overall network I/O information */ static PyObject * psutil_net_io_counters(PyObject *self, PyObject *args) { char *buf = NULL, *lim, *next; struct if_msghdr *ifm; int mib[6]; size_t len; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; if (py_retdict == NULL) return NULL; mib[0] = CTL_NET; // networking subsystem mib[1] = PF_ROUTE; // type of information mib[2] = 0; // protocol (IPPROTO_xxx) mib[3] = 0; // address family mib[4] = NET_RT_IFLIST2; // operation mib[5] = 0; if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } buf = malloc(len); if (buf == NULL) { PyErr_NoMemory(); goto error; } if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } lim = buf + len; for (next = buf; next < lim; ) { ifm = (struct if_msghdr *)next; next += ifm->ifm_msglen; if (ifm->ifm_type == RTM_IFINFO2) { py_ifc_info = NULL; struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm; struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); char ifc_name[32]; strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen); ifc_name[sdl->sdl_nlen] = 0; py_ifc_info = Py_BuildValue( "(KKKKKKKi)", if2m->ifm_data.ifi_obytes, if2m->ifm_data.ifi_ibytes, if2m->ifm_data.ifi_opackets, if2m->ifm_data.ifi_ipackets, if2m->ifm_data.ifi_ierrors, if2m->ifm_data.ifi_oerrors, if2m->ifm_data.ifi_iqdrops, 0); // dropout not supported if (!py_ifc_info) goto error; if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info)) goto error; Py_DECREF(py_ifc_info); } else { continue; } } free(buf); return py_retdict; error: Py_XDECREF(py_ifc_info); Py_DECREF(py_retdict); if (buf != NULL) free(buf); return NULL; } /* * Return a Python dict of tuples for disk I/O information */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { CFDictionaryRef parent_dict; CFDictionaryRef props_dict; CFDictionaryRef stats_dict; io_registry_entry_t parent; io_registry_entry_t disk; io_iterator_t disk_list; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; // Get list of disks if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOMediaClass), &disk_list) != kIOReturnSuccess) { PyErr_SetString(PyExc_RuntimeError, "unable to get the list of disks."); goto error; } // Iterate over disks while ((disk = IOIteratorNext(disk_list)) != 0) { py_disk_info = NULL; parent_dict = NULL; props_dict = NULL; stats_dict = NULL; if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) != kIOReturnSuccess) { PyErr_SetString(PyExc_RuntimeError, "unable to get the disk's parent."); IOObjectRelease(disk); goto error; } if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) { if (IORegistryEntryCreateCFProperties( disk, (CFMutableDictionaryRef *) &parent_dict, kCFAllocatorDefault, kNilOptions ) != kIOReturnSuccess) { PyErr_SetString(PyExc_RuntimeError, "unable to get the parent's properties."); IOObjectRelease(disk); IOObjectRelease(parent); goto error; } if (IORegistryEntryCreateCFProperties( parent, (CFMutableDictionaryRef *) &props_dict, kCFAllocatorDefault, kNilOptions ) != kIOReturnSuccess) { PyErr_SetString(PyExc_RuntimeError, "unable to get the disk properties."); CFRelease(props_dict); IOObjectRelease(disk); IOObjectRelease(parent); goto error; } const int kMaxDiskNameSize = 64; CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue( parent_dict, CFSTR(kIOBSDNameKey)); char disk_name[kMaxDiskNameSize]; CFStringGetCString(disk_name_ref, disk_name, kMaxDiskNameSize, CFStringGetSystemEncoding()); stats_dict = (CFDictionaryRef)CFDictionaryGetValue( props_dict, CFSTR(kIOBlockStorageDriverStatisticsKey)); if (stats_dict == NULL) { PyErr_SetString(PyExc_RuntimeError, "Unable to get disk stats."); goto error; } CFNumberRef number; int64_t reads = 0; int64_t writes = 0; int64_t read_bytes = 0; int64_t write_bytes = 0; int64_t read_time = 0; int64_t write_time = 0; // Get disk reads/writes if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &reads); } if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &writes); } // Get disk bytes read/written if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes); } if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes); } // Get disk time spent reading/writing (nanoseconds) if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &read_time); } if ((number = (CFNumberRef)CFDictionaryGetValue( stats_dict, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) { CFNumberGetValue(number, kCFNumberSInt64Type, &write_time); } // Read/Write time on OS X comes back in nanoseconds and in psutil // we've standardized on milliseconds so do the conversion. py_disk_info = Py_BuildValue( "(KKKKKK)", reads, writes, read_bytes, write_bytes, read_time / 1000 / 1000, write_time / 1000 / 1000); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); CFRelease(parent_dict); IOObjectRelease(parent); CFRelease(props_dict); IOObjectRelease(disk); } } IOObjectRelease (disk_list); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); return NULL; } /* * Return currently connected users as a list of tuples. */ static PyObject * psutil_users(PyObject *self, PyObject *args) { struct utmpx *utx; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; py_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 (!py_tuple) { endutxent(); goto error; } if (PyList_Append(py_retlist, py_tuple)) { endutxent(); goto error; } Py_DECREF(py_tuple); } endutxent(); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions {"proc_name", psutil_proc_name, METH_VARARGS, "Return process name"}, {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return path of the process executable"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory."}, {"proc_ppid", psutil_proc_ppid, METH_VARARGS, "Return process ppid as an integer"}, {"proc_uids", psutil_proc_uids, METH_VARARGS, "Return process real user id as an integer"}, {"proc_gids", psutil_proc_gids, METH_VARARGS, "Return process real group id as an integer"}, {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"proc_create_time", psutil_proc_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, "Return memory information about a process"}, {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS, "Return number of threads used by process"}, {"proc_status", psutil_proc_status, METH_VARARGS, "Return process status as an integer"}, {"proc_threads", psutil_proc_threads, METH_VARARGS, "Return process threads as a list of tuples"}, {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process as a list of tuples"}, {"proc_num_fds", psutil_proc_num_fds, METH_VARARGS, "Return the number of fds opened by process."}, {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"proc_connections", psutil_proc_connections, METH_VARARGS, "Get process TCP and UDP connections as a list of tuples"}, {"proc_tty_nr", psutil_proc_tty_nr, METH_VARARGS, "Return process tty number as an integer"}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, // --- system-related functions {"pids", psutil_pids, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, "Return number of logical CPUs on the system"}, {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return number of physical CPUs on the system"}, {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return system virtual memory stats"}, {"swap_mem", psutil_swap_mem, METH_VARARGS, "Return stats about swap memory, in bytes"}, {"cpu_times", psutil_cpu_times, METH_VARARGS, "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, {"boot_time", psutil_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS, "Return a list of tuples including device, mount point and " "fs type for all partitions mounted on the system."}, {"net_io_counters", psutil_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, "Return dict of tuples of disks I/O information."}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_osx_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_osx", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_osx_traverse, psutil_osx_clear, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__psutil_osx(void) #else #define INITERROR return void init_psutil_osx(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods); #endif PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); // process status constants, defined in: // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149 PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SZOMB", SZOMB); // connection status constants PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_compat.py0000664000175000017500000001767612634022357020345 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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.""" import collections import functools import os import sys __all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"] PY3 = sys.version_info[0] == 3 if PY3: long = int xrange = range unicode = str basestring = str def u(s): return s def b(s): return s.encode("latin-1") else: long = long xrange = xrange unicode = unicode basestring = basestring def u(s): return unicode(s, "unicode_escape") def b(s): return s # removed in 3.0, reintroduced in 3.2 try: callable = callable except NameError: def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) # --- stdlib additions # py 3.2 functools.lru_cache # Taken from: http://code.activestate.com/recipes/578078 # Credit: Raymond Hettinger try: from functools import lru_cache except ImportError: try: from threading import RLock except ImportError: from dummy_threading import RLock _CacheInfo = collections.namedtuple( "CacheInfo", ["hits", "misses", "maxsize", "currsize"]) class _HashedSeq(list): __slots__ = 'hashvalue' def __init__(self, tup, hash=hash): self[:] = tup self.hashvalue = hash(tup) def __hash__(self): return self.hashvalue def _make_key(args, kwds, typed, kwd_mark=(object(), ), fasttypes=set((int, str, frozenset, type(None))), sorted=sorted, tuple=tuple, type=type, len=len): key = args if kwds: sorted_items = sorted(kwds.items()) key += kwd_mark for item in sorted_items: key += item if typed: key += tuple(type(v) for v in args) if kwds: key += tuple(type(v) for k, v in sorted_items) elif len(key) == 1 and type(key[0]) in fasttypes: return key[0] return _HashedSeq(key) def lru_cache(maxsize=100, typed=False): """Least-recently-used cache decorator, see: http://docs.python.org/3/library/functools.html#functools.lru_cache """ def decorating_function(user_function): cache = dict() stats = [0, 0] HITS, MISSES = 0, 1 make_key = _make_key cache_get = cache.get _len = len lock = RLock() root = [] root[:] = [root, root, None, None] nonlocal_root = [root] PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 if maxsize == 0: def wrapper(*args, **kwds): result = user_function(*args, **kwds) stats[MISSES] += 1 return result elif maxsize is None: def wrapper(*args, **kwds): key = make_key(args, kwds, typed) result = cache_get(key, root) if result is not root: stats[HITS] += 1 return result result = user_function(*args, **kwds) cache[key] = result stats[MISSES] += 1 return result else: def wrapper(*args, **kwds): if kwds or typed: key = make_key(args, kwds, typed) else: key = args lock.acquire() try: link = cache_get(key) if link is not None: root, = nonlocal_root link_prev, link_next, key, result = link link_prev[NEXT] = link_next link_next[PREV] = link_prev last = root[PREV] last[NEXT] = root[PREV] = link link[PREV] = last link[NEXT] = root stats[HITS] += 1 return result finally: lock.release() result = user_function(*args, **kwds) lock.acquire() try: root, = nonlocal_root if key in cache: pass elif _len(cache) >= maxsize: oldroot = root oldroot[KEY] = key oldroot[RESULT] = result root = nonlocal_root[0] = oldroot[NEXT] oldkey = root[KEY] root[KEY] = root[RESULT] = None del cache[oldkey] cache[key] = oldroot else: last = root[PREV] link = [last, root, key, result] last[NEXT] = root[PREV] = cache[key] = link stats[MISSES] += 1 finally: lock.release() return result def cache_info(): """Report cache statistics""" lock.acquire() try: return _CacheInfo(stats[HITS], stats[MISSES], maxsize, len(cache)) finally: lock.release() def cache_clear(): """Clear the cache and cache statistics""" lock.acquire() try: cache.clear() root = nonlocal_root[0] root[:] = [root, root, None, None] stats[:] = [0, 0] finally: lock.release() wrapper.__wrapped__ = user_function wrapper.cache_info = cache_info wrapper.cache_clear = cache_clear return functools.update_wrapper(wrapper, user_function) return decorating_function # python 3.3 try: from shutil import which except ImportError: def which(cmd, mode=os.F_OK | os.X_OK, path=None): """Given a command, mode, and a PATH string, return the path which conforms to the given mode on the PATH, or None if there is no such file. `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result of os.environ.get("PATH"), or can be overridden with a custom search path. """ def _access_check(fn, mode): return (os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)) if os.path.dirname(cmd): if _access_check(cmd, mode): return cmd return None if path is None: path = os.environ.get("PATH", os.defpath) if not path: return None path = path.split(os.pathsep) if sys.platform == "win32": if os.curdir not in path: path.insert(0, os.curdir) pathext = os.environ.get("PATHEXT", "").split(os.pathsep) if any(cmd.lower().endswith(ext.lower()) for ext in pathext): files = [cmd] else: files = [cmd + ext for ext in pathext] else: files = [cmd] seen = set() for dir in path: normdir = os.path.normcase(dir) if normdir not in seen: seen.add(normdir) for thefile in files: name = os.path.join(dir, thefile) if _access_check(name, mode): return name return None psutil-3.4.2/psutil/_common.py0000664000175000017500000001715212645411704020337 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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 contextlib import errno import functools import os import socket import stat import sys from collections import namedtuple from socket import AF_INET from socket import SOCK_DGRAM from socket import SOCK_STREAM try: import threading except ImportError: import dummy_threading as threading if sys.version_info >= (3, 4): import enum else: enum = None # --- constants AF_INET6 = getattr(socket, 'AF_INET6', None) AF_UNIX = getattr(socket, 'AF_UNIX', None) STATUS_RUNNING = "running" STATUS_SLEEPING = "sleeping" STATUS_DISK_SLEEP = "disk-sleep" STATUS_STOPPED = "stopped" STATUS_TRACING_STOP = "tracing-stop" STATUS_ZOMBIE = "zombie" STATUS_DEAD = "dead" STATUS_WAKE_KILL = "wake-kill" STATUS_WAKING = "waking" STATUS_IDLE = "idle" # FreeBSD, OSX STATUS_LOCKED = "locked" # FreeBSD STATUS_WAITING = "waiting" # FreeBSD STATUS_SUSPENDED = "suspended" # NetBSD CONN_ESTABLISHED = "ESTABLISHED" CONN_SYN_SENT = "SYN_SENT" CONN_SYN_RECV = "SYN_RECV" CONN_FIN_WAIT1 = "FIN_WAIT1" CONN_FIN_WAIT2 = "FIN_WAIT2" CONN_TIME_WAIT = "TIME_WAIT" CONN_CLOSE = "CLOSE" CONN_CLOSE_WAIT = "CLOSE_WAIT" CONN_LAST_ACK = "LAST_ACK" CONN_LISTEN = "LISTEN" CONN_CLOSING = "CLOSING" CONN_NONE = "NONE" if enum is None: NIC_DUPLEX_FULL = 2 NIC_DUPLEX_HALF = 1 NIC_DUPLEX_UNKNOWN = 0 else: class NicDuplex(enum.IntEnum): NIC_DUPLEX_FULL = 2 NIC_DUPLEX_HALF = 1 NIC_DUPLEX_UNKNOWN = 0 globals().update(NicDuplex.__members__) # --- 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 def memoize(fun): """A simple memoize decorator for functions supporting (hashable) positional arguments. It also provides a cache_clear() function for clearing the cache: >>> @memoize ... def foo() ... return 1 ... >>> foo() 1 >>> foo.cache_clear() >>> """ @functools.wraps(fun) def wrapper(*args, **kwargs): key = (args, frozenset(sorted(kwargs.items()))) with lock: try: return cache[key] except KeyError: ret = cache[key] = fun(*args, **kwargs) return ret def cache_clear(): """Clear cache.""" lock.acquire() try: cache.clear() finally: lock.release() lock = threading.RLock() cache = {} wrapper.cache_clear = cache_clear return wrapper 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 as err: if err.errno in (errno.EPERM, errno.EACCES): raise return False else: return stat.S_ISREG(st.st_mode) def path_exists_strict(path): """Same as os.path.exists() but does not swallow EACCES / EPERM exceptions, see: http://mail.python.org/pipermail/python-dev/2012-June/120787.html """ try: os.stat(path) except OSError as err: if err.errno in (errno.EPERM, errno.EACCES): raise return False else: return True def supports_ipv6(): """Return True if IPv6 is supported on this platform.""" if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"): return False try: sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) with contextlib.closing(sock): sock.bind(("::1", 0)) return True except socket.error: return False def sockfam_to_enum(num): """Convert a numeric socket family value to an IntEnum member. If it's not a known member, return the numeric value itself. """ if enum is None: return num try: return socket.AddressFamily(num) except (ValueError, AttributeError): return num def socktype_to_enum(num): """Convert a numeric socket type value to an IntEnum member. If it's not a known member, return the numeric value itself. """ if enum is None: return num try: return socket.AddressType(num) except (ValueError, AttributeError): return num # --- Process.connections() 'kind' parameter mapping 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 # --- namedtuples for psutil.* system-related functions # psutil.swap_memory() sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin', 'sout']) # psutil.disk_usage() sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent']) # psutil.disk_io_counters() sdiskio = namedtuple('sdiskio', ['read_count', 'write_count', 'read_bytes', 'write_bytes', 'read_time', 'write_time']) # psutil.disk_partitions() sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts']) # psutil.net_io_counters() snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv', 'packets_sent', 'packets_recv', 'errin', 'errout', 'dropin', 'dropout']) # psutil.users() suser = namedtuple('suser', ['name', 'terminal', 'host', 'started']) # psutil.net_connections() sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr', 'status', 'pid']) # psutil.net_if_addrs() snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp']) # psutil.net_if_stats() snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) # --- namedtuples for psutil.Process methods # psutil.Process.memory_info() pmem = namedtuple('pmem', ['rss', 'vms']) # psutil.Process.cpu_times() pcputimes = namedtuple('pcputimes', ['user', 'system']) # psutil.Process.open_files() popenfile = namedtuple('popenfile', ['path', 'fd']) # psutil.Process.threads() pthread = namedtuple('pthread', ['id', 'user_time', 'system_time']) # psutil.Process.uids() puids = namedtuple('puids', ['real', 'effective', 'saved']) # psutil.Process.gids() pgids = namedtuple('pgids', ['real', 'effective', 'saved']) # psutil.Process.io_counters() pio = namedtuple('pio', ['read_count', 'write_count', 'read_bytes', 'write_bytes']) # psutil.Process.ionice() pionice = namedtuple('pionice', ['ioclass', 'value']) # psutil.Process.ctx_switches() pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary']) # psutil.Process.connections() pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr', 'status']) psutil-3.4.2/psutil/_psutil_linux.c0000664000175000017500000004476112645372437021417 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include // see: https://github.com/giampaolo/psutil/issues/659 #ifdef PSUTIL_ETHTOOL_MISSING_TYPES #include typedef __u64 u64; typedef __u32 u32; typedef __u16 u16; typedef __u8 u8; #endif #include #include "_psutil_linux.h" /* The minimum number of CPUs allocated in a cpu_set_t */ static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT; // Linux >= 2.6.13 #define PSUTIL_HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set) // Linux >= 2.6.36 (supposedly) and glibc >= 13 #define PSUTIL_HAVE_PRLIMIT \ (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \ (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \ defined(__NR_prlimit64) #if PSUTIL_HAVE_PRLIMIT #define _FILE_OFFSET_BITS 64 #include #include #endif // May happen on old RedHat versions, see: // https://github.com/giampaolo/psutil/issues/607 #ifndef DUPLEX_UNKNOWN #define DUPLEX_UNKNOWN 0xff #endif #if PSUTIL_HAVE_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 * psutil_proc_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 * psutil_proc_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_RETURN_NONE; } #endif #if PSUTIL_HAVE_PRLIMIT /* * A wrapper around prlimit(2); sets process resource limits. * This can be used for both get and set, in which case extra * 'soft' and 'hard' args must be provided. */ static PyObject * psutil_linux_prlimit(PyObject *self, PyObject *args) { long pid; int ret, resource; struct rlimit old, new; struct rlimit *newp = NULL; PyObject *py_soft = NULL; PyObject *py_hard = NULL; if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &py_soft, &py_hard)) return NULL; // get if (py_soft == NULL && py_hard == NULL) { ret = prlimit(pid, resource, NULL, &old); if (ret == -1) return PyErr_SetFromErrno(PyExc_OSError); #if defined(PSUTIL_HAVE_LONG_LONG) if (sizeof(old.rlim_cur) > sizeof(long)) { return Py_BuildValue("LL", (PY_LONG_LONG)old.rlim_cur, (PY_LONG_LONG)old.rlim_max); } #endif return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max); } // set else { #if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT) new.rlim_cur = PyLong_AsLongLong(py_soft); if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred()) return NULL; new.rlim_max = PyLong_AsLongLong(py_hard); if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred()) return NULL; #else new.rlim_cur = PyLong_AsLong(py_soft); if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred()) return NULL; new.rlim_max = PyLong_AsLong(py_hard); if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred()) return NULL; #endif newp = &new; ret = prlimit(pid, resource, newp, &old); if (ret == -1) return PyErr_SetFromErrno(PyExc_OSError); Py_RETURN_NONE; } } #endif /* * Return disk mounted partitions as a list of tuples including device, * mount point and filesystem type */ static PyObject * psutil_disk_partitions(PyObject *self, PyObject *args) { FILE *file = NULL; struct mntent *entry; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return 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_SetFromErrnoWithFilename(PyExc_OSError, MOUNTED); 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 * psutil_linux_sysinfo(PyObject *self, PyObject *args) { struct sysinfo info; if (sysinfo(&info) != 0) return PyErr_SetFromErrno(PyExc_OSError); // note: boot time might also be determined from here 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 } /* * Return process CPU affinity as a Python list * The dual implementation exists because of: * https://github.com/giampaolo/psutil/issues/536 */ #ifdef CPU_ALLOC static PyObject * psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { int cpu, ncpus, count, cpucount_s; long pid; size_t setsize; cpu_set_t *mask = NULL; PyObject *py_list = NULL; if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; ncpus = NCPUS_START; while (1) { setsize = CPU_ALLOC_SIZE(ncpus); mask = CPU_ALLOC(ncpus); if (mask == NULL) return PyErr_NoMemory(); if (sched_getaffinity(pid, setsize, mask) == 0) break; CPU_FREE(mask); if (errno != EINVAL) return PyErr_SetFromErrno(PyExc_OSError); if (ncpus > INT_MAX / 2) { PyErr_SetString(PyExc_OverflowError, "could not allocate " "a large enough CPU set"); return NULL; } ncpus = ncpus * 2; } py_list = PyList_New(0); if (py_list == NULL) goto error; cpucount_s = CPU_COUNT_S(setsize, mask); for (cpu = 0, count = cpucount_s; count; cpu++) { if (CPU_ISSET_S(cpu, setsize, mask)) { #if PY_MAJOR_VERSION >= 3 PyObject *cpu_num = PyLong_FromLong(cpu); #else PyObject *cpu_num = PyInt_FromLong(cpu); #endif if (cpu_num == NULL) goto error; if (PyList_Append(py_list, cpu_num)) { Py_DECREF(cpu_num); goto error; } Py_DECREF(cpu_num); --count; } } CPU_FREE(mask); return py_list; error: if (mask) CPU_FREE(mask); Py_XDECREF(py_list); return NULL; } #else /* * Alternative implementation in case CPU_ALLOC is not defined. */ static PyObject * psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { cpu_set_t cpuset; unsigned int len = sizeof(cpu_set_t); long pid; int i; PyObject* py_retlist = NULL; PyObject *py_cpu_num = NULL; if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; CPU_ZERO(&cpuset); if (sched_getaffinity(pid, len, &cpuset) < 0) return PyErr_SetFromErrno(PyExc_OSError); py_retlist = PyList_New(0); if (py_retlist == NULL) goto error; for (i = 0; i < CPU_SETSIZE; ++i) { if (CPU_ISSET(i, &cpuset)) { py_cpu_num = Py_BuildValue("i", i); if (py_cpu_num == NULL) goto error; if (PyList_Append(py_retlist, py_cpu_num)) goto error; Py_DECREF(py_cpu_num); } } return py_retlist; error: Py_XDECREF(py_cpu_num); Py_DECREF(py_retlist); return NULL; } #endif /* * Set process CPU affinity; expects a bitmask */ static PyObject * psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { cpu_set_t cpu_set; size_t len; long pid; int i, seq_len; PyObject *py_cpu_set; PyObject *py_cpu_seq = NULL; if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) return NULL; if (!PySequence_Check(py_cpu_set)) { PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s", Py_TYPE(py_cpu_set)->tp_name); goto error; } py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); if (!py_cpu_seq) goto error; seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); CPU_ZERO(&cpu_set); for (i = 0; i < seq_len; i++) { PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); #if PY_MAJOR_VERSION >= 3 long value = PyLong_AsLong(item); #else long value = PyInt_AsLong(item); #endif if (value == -1 && PyErr_Occurred()) goto error; CPU_SET(value, &cpu_set); } len = sizeof(cpu_set); if (sched_setaffinity(pid, len, &cpu_set)) { PyErr_SetFromErrno(PyExc_OSError); goto error; } Py_DECREF(py_cpu_seq); Py_RETURN_NONE; error: if (py_cpu_seq != NULL) Py_DECREF(py_cpu_seq); return NULL; } /* * Return currently connected users as a list of tuples. */ static PyObject * psutil_users(PyObject *self, PyObject *args) { struct utmp *ut; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_user_proc = NULL; if (py_retlist == NULL) return NULL; setutent(); while (NULL != (ut = getutent())) { py_tuple = NULL; py_user_proc = NULL; if (ut->ut_type == USER_PROCESS) py_user_proc = Py_True; else py_user_proc = Py_False; py_tuple = Py_BuildValue( "(sssfO)", ut->ut_user, // username ut->ut_line, // tty ut->ut_host, // hostname (float)ut->ut_tv.tv_sec, // tstamp py_user_proc // (bool) user process ); if (! py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } endutent(); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_user_proc); Py_DECREF(py_retlist); endutent(); return NULL; } /* * Return stats about a particular network * interface. References: * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py * http://www.i-scream.org/libstatgrab/ */ static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args) { char *nic_name; int sock = 0; int ret; int duplex; int speed; int mtu; struct ifreq ifr; struct ethtool_cmd ethcmd; PyObject *py_is_up = NULL; PyObject *py_retlist = NULL; if (! PyArg_ParseTuple(args, "s", &nic_name)) return NULL; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) goto error; strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name)); // is up? ret = ioctl(sock, SIOCGIFFLAGS, &ifr); if (ret == -1) goto error; if ((ifr.ifr_flags & IFF_UP) != 0) py_is_up = Py_True; else py_is_up = Py_False; Py_INCREF(py_is_up); // MTU ret = ioctl(sock, SIOCGIFMTU, &ifr); if (ret == -1) goto error; mtu = ifr.ifr_mtu; // duplex and speed memset(ðcmd, 0, sizeof ethcmd); ethcmd.cmd = ETHTOOL_GSET; ifr.ifr_data = (void *)ðcmd; ret = ioctl(sock, SIOCETHTOOL, &ifr); if (ret != -1) { duplex = ethcmd.duplex; speed = ethcmd.speed; } else { if (errno == EOPNOTSUPP) { // we typically get here in case of wi-fi cards duplex = DUPLEX_UNKNOWN; speed = 0; } else { goto error; } } close(sock); py_retlist = Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu); if (!py_retlist) goto error; Py_DECREF(py_is_up); return py_retlist; error: Py_XDECREF(py_is_up); if (sock != 0) close(sock); PyErr_SetFromErrno(PyExc_OSError); return NULL; } /* * Define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions #if PSUTIL_HAVE_IOPRIO {"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS, "Get process I/O priority"}, {"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS, "Set process I/O priority"}, #endif {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, "Return process CPU affinity as a Python long (the bitmask)."}, {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, "Set process CPU affinity; expects a bitmask."}, // --- system related functions {"disk_partitions", psutil_disk_partitions, METH_VARARGS, "Return disk mounted partitions as a list of tuples including " "device, mount point and filesystem type"}, {"users", psutil_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NIC stats (isup, duplex, speed, mtu)"}, // --- linux specific {"linux_sysinfo", psutil_linux_sysinfo, METH_VARARGS, "A wrapper around sysinfo(), return system memory usage statistics"}, #if PSUTIL_HAVE_PRLIMIT {"linux_prlimit", psutil_linux_prlimit, METH_VARARGS, "Get or set process resource limits."}, #endif {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 PyMODINIT_FUNC PyInit__psutil_linux(void) #else #define INITERROR return void init_psutil_linux(void) #endif { PyObject *v; #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods); #endif PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); #if PSUTIL_HAVE_PRLIMIT PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS); PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE); PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU); PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA); PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE); PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS); PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK); PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE); PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC); PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS); PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK); #if defined(HAVE_LONG_LONG) if (sizeof(RLIM_INFINITY) > sizeof(long)) { v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY); } else #endif { v = PyLong_FromLong((long) RLIM_INFINITY); } if (v) { PyModule_AddObject(module, "RLIM_INFINITY", v); } #ifdef RLIMIT_MSGQUEUE PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE); #endif #ifdef RLIMIT_NICE PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE); #endif #ifdef RLIMIT_RTPRIO PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO); #endif #ifdef RLIMIT_RTTIME PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME); #endif #ifdef RLIMIT_SIGPENDING PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING); #endif #endif PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF); PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL); PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN); if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_psutil_osx.h0000664000175000017500000000447412572074510021061 0ustar giampaologiampaolo00000000000000/* * 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 // --- per-process functions static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args); static PyObject* psutil_proc_connections(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args); static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); static PyObject* psutil_proc_exe(PyObject* self, PyObject* args); static PyObject* psutil_proc_gids(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); static PyObject* psutil_proc_name(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args); static PyObject* psutil_proc_status(PyObject* self, PyObject* args); static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args); static PyObject* psutil_proc_uids(PyObject* self, PyObject* args); // --- system-related functions static PyObject* psutil_boot_time(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); static PyObject* psutil_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); psutil-3.4.2/psutil/_psutil_bsd.h0000664000175000017500000000330412621171150021000 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 // --- per-process functions static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args); static PyObject* psutil_proc_gids(PyObject* self, PyObject* args); static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_name(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args); static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args); static PyObject* psutil_proc_status(PyObject* self, PyObject* args); static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args); static PyObject* psutil_proc_uids(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); #endif // --- system-related functions static PyObject* psutil_boot_time(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args); static PyObject* psutil_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); psutil-3.4.2/psutil/_psosx.py0000664000175000017500000002462712633663044020233 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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 functools import os from collections import namedtuple from . import _common from . import _psposix from . import _psutil_osx as cext from . import _psutil_posix as cext_posix from ._common import conn_tmap from ._common import isfile_strict from ._common import sockfam_to_enum from ._common import socktype_to_enum from ._common import usage_percent __extra__all__ = [] # --- constants PAGESIZE = os.sysconf("SC_PAGE_SIZE") AF_LINK = cext_posix.AF_LINK # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV, cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, cext.TCPS_CLOSED: _common.CONN_CLOSE, cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, cext.TCPS_LISTEN: _common.CONN_LISTEN, cext.TCPS_CLOSING: _common.CONN_CLOSING, cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } PROC_STATUSES = { cext.SIDL: _common.STATUS_IDLE, cext.SRUN: _common.STATUS_RUNNING, cext.SSLEEP: _common.STATUS_SLEEPING, cext.SSTOP: _common.STATUS_STOPPED, cext.SZOMB: _common.STATUS_ZOMBIE, } scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle']) svmem = namedtuple( 'svmem', ['total', 'available', 'percent', 'used', 'free', 'active', 'inactive', 'wired']) pextmem = namedtuple('pextmem', ['rss', 'vms', 'pfaults', 'pageins']) pmmap_grouped = namedtuple( 'pmmap_grouped', 'path rss private swapped dirtied ref_count shadow_depth') pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) # set later from __init__.py NoSuchProcess = None ZombieProcess = None AccessDenied = None TimeoutExpired = None # --- functions def virtual_memory(): """System virtual memory as a namedtuple.""" total, active, inactive, wired, free = cext.virtual_mem() avail = inactive + free used = active + inactive + wired percent = usage_percent((total - avail), total, _round=1) return svmem(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 = cext.swap_mem() percent = usage_percent(used, total, _round=1) return _common.sswap(total, used, free, percent, sin, sout) def cpu_times(): """Return system CPU times as a namedtuple.""" user, nice, system, idle = cext.cpu_times() return scputimes(user, nice, system, idle) def per_cpu_times(): """Return system CPU times as a named tuple""" ret = [] for cpu_t in cext.per_cpu_times(): user, nice, system, idle = cpu_t item = scputimes(user, nice, system, idle) ret.append(item) return ret def cpu_count_logical(): """Return the number of logical CPUs in the system.""" return cext.cpu_count_logical() def cpu_count_physical(): """Return the number of physical CPUs in the system.""" return cext.cpu_count_phys() def boot_time(): """The system boot time expressed in seconds since the epoch.""" return cext.boot_time() def disk_partitions(all=False): retlist = [] partitions = cext.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 = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def users(): retlist = [] rawlist = cext.users() for item in rawlist: user, tty, hostname, tstamp = item if tty == '~': continue # reboot or shutdown if not tstamp: continue nt = _common.suser(user, tty or None, hostname or None, tstamp) retlist.append(nt) return retlist def net_connections(kind='inet'): # Note: on OSX this will fail with AccessDenied unless # the process is owned by root. ret = [] for pid in pids(): try: cons = Process(pid).connections(kind) except NoSuchProcess: continue else: if cons: for c in cons: c = list(c) + [pid] ret.append(_common.sconn(*c)) return ret def net_if_stats(): """Get NIC stats (isup, duplex, speed, mtu).""" names = net_io_counters().keys() ret = {} for name in names: isup, duplex, speed, mtu = cext_posix.net_if_stats(name) if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret pids = cext.pids pid_exists = _psposix.pid_exists disk_usage = _psposix.disk_usage net_io_counters = cext.net_io_counters disk_io_counters = cext.disk_io_counters net_if_addrs = cext_posix.net_if_addrs def wrap_exceptions(fun): """Decorator which translates bare OSError exceptions into NoSuchProcess and AccessDenied. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError as err: # support for private module import if (NoSuchProcess is None or AccessDenied is None or ZombieProcess is None): raise if err.errno == errno.ESRCH: if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None self._ppid = None @wrap_exceptions def name(self): return cext.proc_name(self.pid) @wrap_exceptions def exe(self): return cext.proc_exe(self.pid) @wrap_exceptions def cmdline(self): if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) return cext.proc_cmdline(self.pid) @wrap_exceptions def ppid(self): return cext.proc_ppid(self.pid) @wrap_exceptions def cwd(self): return cext.proc_cwd(self.pid) @wrap_exceptions def uids(self): real, effective, saved = cext.proc_uids(self.pid) return _common.puids(real, effective, saved) @wrap_exceptions def gids(self): real, effective, saved = cext.proc_gids(self.pid) return _common.pgids(real, effective, saved) @wrap_exceptions def terminal(self): tty_nr = cext.proc_tty_nr(self.pid) tmap = _psposix._get_terminal_map() try: return tmap[tty_nr] except KeyError: return None @wrap_exceptions def memory_info(self): rss, vms = cext.proc_memory_info(self.pid)[:2] return _common.pmem(rss, vms) @wrap_exceptions def memory_info_ex(self): rss, vms, pfaults, pageins = cext.proc_memory_info(self.pid) return pextmem(rss, vms, pfaults * PAGESIZE, pageins * PAGESIZE) @wrap_exceptions def cpu_times(self): user, system = cext.proc_cpu_times(self.pid) return _common.pcputimes(user, system) @wrap_exceptions def create_time(self): return cext.proc_create_time(self.pid) @wrap_exceptions def num_ctx_switches(self): return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid)) @wrap_exceptions def num_threads(self): return cext.proc_num_threads(self.pid) @wrap_exceptions def open_files(self): if self.pid == 0: return [] files = [] rawlist = cext.proc_open_files(self.pid) for path, fd in rawlist: if isfile_strict(path): ntuple = _common.popenfile(path, fd) files.append(ntuple) return files @wrap_exceptions def 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] rawlist = cext.proc_connections(self.pid, families, types) ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] fam = sockfam_to_enum(fam) type = socktype_to_enum(type) nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret @wrap_exceptions def num_fds(self): if self.pid == 0: return 0 return cext.proc_num_fds(self.pid) @wrap_exceptions def wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except _psposix.TimeoutExpired: # support for private module import if TimeoutExpired is None: raise raise TimeoutExpired(timeout, self.pid, self._name) @wrap_exceptions def nice_get(self): return cext_posix.getpriority(self.pid) @wrap_exceptions def nice_set(self, value): return cext_posix.setpriority(self.pid, value) @wrap_exceptions def status(self): code = cext.proc_status(self.pid) # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(code, '?') @wrap_exceptions def threads(self): rawlist = cext.proc_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = _common.pthread(thread_id, utime, stime) retlist.append(ntuple) return retlist @wrap_exceptions def memory_maps(self): return cext.proc_memory_maps(self.pid) psutil-3.4.2/psutil/_pssunos.py0000664000175000017500000004766612647703522020602 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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. """Sun OS Solaris platform implementation.""" import errno import os import socket import subprocess import sys from collections import namedtuple from . import _common from . import _psposix from . import _psutil_posix as cext_posix from . import _psutil_sunos as cext from ._common import isfile_strict from ._common import sockfam_to_enum from ._common import socktype_to_enum from ._common import usage_percent from ._compat import b from ._compat import PY3 __extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"] PAGE_SIZE = os.sysconf('SC_PAGE_SIZE') AF_LINK = cext_posix.AF_LINK CONN_IDLE = "IDLE" CONN_BOUND = "BOUND" PROC_STATUSES = { cext.SSLEEP: _common.STATUS_SLEEPING, cext.SRUN: _common.STATUS_RUNNING, cext.SZOMB: _common.STATUS_ZOMBIE, cext.SSTOP: _common.STATUS_STOPPED, cext.SIDL: _common.STATUS_IDLE, cext.SONPROC: _common.STATUS_RUNNING, # same as run cext.SWAIT: _common.STATUS_WAITING, } TCP_STATUSES = { cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV, cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, cext.TCPS_CLOSED: _common.CONN_CLOSE, cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, cext.TCPS_LISTEN: _common.CONN_LISTEN, cext.TCPS_CLOSING: _common.CONN_CLOSING, cext.PSUTIL_CONN_NONE: _common.CONN_NONE, cext.TCPS_IDLE: CONN_IDLE, # sunos specific cext.TCPS_BOUND: CONN_BOUND, # sunos specific } scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait']) svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) pextmem = namedtuple('pextmem', ['rss', 'vms']) pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked']) pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) # set later from __init__.py NoSuchProcess = None ZombieProcess = None AccessDenied = None TimeoutExpired = None # --- utils def get_procfs_path(): return sys.modules['psutil'].PROCFS_PATH # --- functions disk_io_counters = cext.disk_io_counters net_io_counters = cext.net_io_counters disk_usage = _psposix.disk_usage net_if_addrs = cext_posix.net_if_addrs def virtual_memory(): # we could have done this with kstat, but imho this is good enough total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE # note: there's no difference on Solaris free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE used = total - free percent = usage_percent(used, total, _round=1) return svmem(total, avail, percent, used, free) def swap_memory(): sin, sout = cext.swap_mem() # XXX # we are supposed to get total/free by doing so: # http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/ # usr/src/cmd/swap/swap.c # ...nevertheless I can't manage to obtain the same numbers as 'swap' # cmdline utility, so let's parse its output (sigh!) p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' % os.environ['PATH'], 'swap', '-l'], stdout=subprocess.PIPE) stdout, stderr = p.communicate() if PY3: stdout = stdout.decode(sys.stdout.encoding) if p.returncode != 0: raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode) lines = stdout.strip().split('\n')[1:] if not lines: raise RuntimeError('no swap device(s) configured') total = free = 0 for line in lines: line = line.split() t, f = line[-2:] total += int(int(t) * 512) free += int(int(f) * 512) used = total - free percent = usage_percent(used, total, _round=1) return _common.sswap(total, used, free, percent, sin * PAGE_SIZE, sout * PAGE_SIZE) def pids(): """Returns a list of PIDs currently running on the system.""" return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] def pid_exists(pid): """Check for the existence of a unix pid.""" return _psposix.pid_exists(pid) def cpu_times(): """Return system-wide CPU times as a named tuple""" ret = cext.per_cpu_times() return scputimes(*[sum(x) for x in zip(*ret)]) def per_cpu_times(): """Return system per-CPU times as a list of named tuples""" ret = cext.per_cpu_times() return [scputimes(*x) for x in ret] def cpu_count_logical(): """Return the number of logical CPUs in the system.""" try: return os.sysconf("SC_NPROCESSORS_ONLN") except ValueError: # mimic os.cpu_count() behavior return None def cpu_count_physical(): """Return the number of physical CPUs in the system.""" return cext.cpu_count_phys() def boot_time(): """The system boot time expressed in seconds since the epoch.""" return cext.boot_time() def users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = cext.users() localhost = (':0.0', ':0') for item in rawlist: user, tty, hostname, tstamp, user_process = item # note: 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 in localhost: hostname = 'localhost' nt = _common.suser(user, tty, hostname, tstamp) retlist.append(nt) return retlist def disk_partitions(all=False): """Return system disk partitions.""" # TODO - the filtering logic should be better checked so that # it tries to reflect 'df' as much as possible retlist = [] partitions = cext.disk_partitions() for partition in partitions: device, mountpoint, fstype, opts = partition if device == 'none': device = '' if not all: # Differently from, say, Linux, we don't have a list of # common fs types so the best we can do, AFAIK, is to # filter by filesystem having a total size > 0. if not disk_usage(mountpoint).total: continue ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def net_connections(kind, _pid=-1): """Return socket connections. If pid == -1 return system-wide connections (as opposed to connections opened by one process only). Only INET sockets are returned (UNIX are not). """ cmap = _common.conn_tmap.copy() if _pid == -1: cmap.pop('unix', 0) if kind not in cmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in cmap]))) families, types = _common.conn_tmap[kind] rawlist = cext.net_connections(_pid) ret = set() for item in rawlist: fd, fam, type_, laddr, raddr, status, pid = item if fam not in families: continue if type_ not in types: continue status = TCP_STATUSES[status] fam = sockfam_to_enum(fam) type_ = socktype_to_enum(type_) if _pid == -1: nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type_, laddr, raddr, status) ret.add(nt) return list(ret) def net_if_stats(): """Get NIC stats (isup, duplex, speed, mtu).""" ret = cext.net_if_stats() for name, items in ret.items(): isup, duplex, speed, mtu = items if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret def wrap_exceptions(fun): """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 fun(self, *args, **kwargs) except EnvironmentError as err: # support for private module import if (NoSuchProcess is None or AccessDenied is None or ZombieProcess is None): raise # 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. if err.errno in (errno.ENOENT, errno.ESRCH): if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None self._ppid = None @wrap_exceptions def name(self): # note: max len == 15 return cext.proc_name_and_args(self.pid, get_procfs_path())[0] @wrap_exceptions def exe(self): try: return os.readlink( "%s/%s/path/a.out" % (get_procfs_path(), self.pid)) except OSError: pass # continue and guess the exe name from the cmdline # Will be guessed later from cmdline but we want to explicitly # invoke cmdline here in order to get an AccessDenied # exception if the user has not enough privileges. self.cmdline() return "" @wrap_exceptions def cmdline(self): return cext.proc_name_and_args( self.pid, get_procfs_path())[1].split(' ') @wrap_exceptions def create_time(self): return cext.proc_basic_info(self.pid, get_procfs_path())[3] @wrap_exceptions def num_threads(self): return cext.proc_basic_info(self.pid, get_procfs_path())[5] @wrap_exceptions def nice_get(self): # For some reason getpriority(3) return ESRCH (no such process) # for certain low-pid processes, no matter what (even as root). # The process actually exists though, as it has a name, # creation time, etc. # The best thing we can do here appears to be raising AD. # Note: tested on Solaris 11; on Open Solaris 5 everything is # fine. try: return cext_posix.getpriority(self.pid) except EnvironmentError as err: # 48 is 'operation not supported' but errno does not expose # it. It occurs for low system pids. if err.errno in (errno.ENOENT, errno.ESRCH, 48): if pid_exists(self.pid): raise AccessDenied(self.pid, self._name) raise @wrap_exceptions def nice_set(self, value): if self.pid in (2, 3): # Special case PIDs: internally setpriority(3) return ESRCH # (no such process), no matter what. # The process actually exists though, as it has a name, # creation time, etc. raise AccessDenied(self.pid, self._name) return cext_posix.setpriority(self.pid, value) @wrap_exceptions def ppid(self): return cext.proc_basic_info(self.pid, get_procfs_path())[0] @wrap_exceptions def uids(self): real, effective, saved, _, _, _ = \ cext.proc_cred(self.pid, get_procfs_path()) return _common.puids(real, effective, saved) @wrap_exceptions def gids(self): _, _, _, real, effective, saved = \ cext.proc_cred(self.pid, get_procfs_path()) return _common.puids(real, effective, saved) @wrap_exceptions def cpu_times(self): user, system = cext.proc_cpu_times(self.pid, get_procfs_path()) return _common.pcputimes(user, system) @wrap_exceptions def terminal(self): procfs_path = get_procfs_path() hit_enoent = False tty = wrap_exceptions( cext.proc_basic_info(self.pid, get_procfs_path())[0]) if tty != cext.PRNODEV: for x in (0, 1, 2, 255): try: return os.readlink( '%s/%d/path/%d' % (procfs_path, self.pid, x)) except OSError as err: if err.errno == errno.ENOENT: hit_enoent = True continue raise if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (procfs_path, self.pid)) @wrap_exceptions def cwd(self): # /proc/PID/path/cwd may not be resolved by readlink() even if # it exists (ls shows it). If that's the case and the process # is still alive return None (we can return None also on BSD). # Reference: http://goo.gl/55XgO procfs_path = get_procfs_path() try: return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid)) except OSError as err: if err.errno == errno.ENOENT: os.stat("%s/%s" % (procfs_path, self.pid)) return None raise @wrap_exceptions def memory_info(self): ret = cext.proc_basic_info(self.pid, get_procfs_path()) rss, vms = ret[1] * 1024, ret[2] * 1024 return _common.pmem(rss, vms) # it seems Solaris uses rss and vms only memory_info_ex = memory_info @wrap_exceptions def status(self): code = cext.proc_basic_info(self.pid, get_procfs_path())[6] # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(code, '?') @wrap_exceptions def threads(self): procfs_path = get_procfs_path() ret = [] tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid)) hit_enoent = False for tid in tids: tid = int(tid) try: utime, stime = cext.query_process_thread( self.pid, tid, procfs_path) except EnvironmentError as err: # ENOENT == thread gone in meantime if err.errno == errno.ENOENT: hit_enoent = True continue raise else: nt = _common.pthread(tid, utime, stime) ret.append(nt) if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (procfs_path, self.pid)) return ret @wrap_exceptions def open_files(self): retlist = [] hit_enoent = False procfs_path = get_procfs_path() pathdir = '%s/%d/path' % (procfs_path, self.pid) for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)): path = os.path.join(pathdir, fd) if os.path.islink(path): try: file = os.readlink(path) except OSError as err: # ENOENT == file which is gone in the meantime if err.errno == errno.ENOENT: hit_enoent = True continue raise else: if isfile_strict(file): retlist.append(_common.popenfile(file, int(fd))) if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (procfs_path, self.pid)) return retlist def _get_unix_sockets(self, pid): """Get UNIX sockets used by process by parsing 'pfiles' output.""" # TODO: rewrite this in C (...but the damn netstat source code # does not include this part! Argh!!) cmd = "pfiles %s" % pid p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if PY3: stdout, stderr = [x.decode(sys.stdout.encoding) for x in (stdout, stderr)] if p.returncode != 0: if 'permission denied' in stderr.lower(): raise AccessDenied(self.pid, self._name) if 'no such process' in stderr.lower(): raise NoSuchProcess(self.pid, self._name) raise RuntimeError("%r command error\n%s" % (cmd, stderr)) lines = stdout.split('\n')[2:] for i, line in enumerate(lines): line = line.lstrip() if line.startswith('sockname: AF_UNIX'): path = line.split(' ', 2)[2] type = lines[i - 2].strip() if type == 'SOCK_STREAM': type = socket.SOCK_STREAM elif type == 'SOCK_DGRAM': type = socket.SOCK_DGRAM else: type = -1 yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE) @wrap_exceptions def connections(self, kind='inet'): ret = net_connections(kind, _pid=self.pid) # The underlying C implementation retrieves all OS connections # and filters them by PID. At this point we can't tell whether # an empty list means there were no connections for process or # process is no longer active so we force NSP in case the PID # is no longer there. if not ret: # will raise NSP if process is gone os.stat('%s/%s' % (get_procfs_path(), self.pid)) # UNIX sockets if kind in ('all', 'unix'): ret.extend([_common.pconn(*conn) for conn in self._get_unix_sockets(self.pid)]) return ret nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked') nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked') @wrap_exceptions def memory_maps(self): def toaddr(start, end): return '%s-%s' % (hex(start)[2:].strip('L'), hex(end)[2:].strip('L')) procfs_path = get_procfs_path() retlist = [] rawlist = cext.proc_memory_maps(self.pid, procfs_path) hit_enoent = False for item in rawlist: addr, addrsize, perm, name, rss, anon, locked = item addr = toaddr(addr, addrsize) if not name.startswith('['): try: name = os.readlink( '%s/%s/path/%s' % (procfs_path, self.pid, name)) except OSError as err: if err.errno == errno.ENOENT: # sometimes the link may not be resolved by # readlink() even if it exists (ls shows it). # If that's the case we just return the # unresolved link path. # This seems an incosistency with /proc similar # to: http://goo.gl/55XgO name = '%s/%s/path/%s' % (procfs_path, self.pid, name) hit_enoent = True else: raise retlist.append((addr, perm, name, rss, anon, locked)) if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (procfs_path, self.pid)) return retlist @wrap_exceptions def num_fds(self): return len(os.listdir("%s/%s/fd" % (get_procfs_path(), self.pid))) @wrap_exceptions def num_ctx_switches(self): return _common.pctxsw( *cext.proc_num_ctx_switches(self.pid, get_procfs_path())) @wrap_exceptions def wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except _psposix.TimeoutExpired: # support for private module import if TimeoutExpired is None: raise raise TimeoutExpired(timeout, self.pid, self._name) psutil-3.4.2/psutil/_psutil_windows.h0000664000175000017500000000701212572074510021731 0ustar giampaologiampaolo00000000000000/* * 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 #include // --- per-process functions static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args); static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); static PyObject* psutil_proc_exe(PyObject* self, PyObject* args); static PyObject* psutil_proc_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_proc_is_suspended(PyObject* self, PyObject* args); static PyObject* psutil_proc_kill(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_info_2(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); static PyObject* psutil_proc_name(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_handles(PyObject* self, PyObject* args); static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args); static PyObject* psutil_proc_priority_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_priority_set(PyObject* self, PyObject* args); static PyObject* psutil_proc_resume(PyObject* self, PyObject* args); static PyObject* psutil_proc_suspend(PyObject* self, PyObject* args); static PyObject* psutil_proc_threads(PyObject* self, PyObject* args); static PyObject* psutil_proc_username(PyObject* self, PyObject* args); static PyObject* psutil_proc_wait(PyObject* self, PyObject* args); #if (PSUTIL_WINVER >= 0x0600) // Windows Vista static PyObject* psutil_proc_io_priority_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_io_priority_set(PyObject* self, PyObject* args); #endif // --- system-related functions static PyObject* psutil_boot_time(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); static PyObject* psutil_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_disk_usage(PyObject* self, PyObject* args); static PyObject* psutil_net_connections(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_pid_exists(PyObject* self, PyObject* args); static PyObject* psutil_pids(PyObject* self, PyObject* args); static PyObject* psutil_ppid_map(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args); static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); // --- windows API bindings static PyObject* psutil_win32_QueryDosDevice(PyObject* self, PyObject* args); // --- internal int psutil_proc_suspend_or_resume(DWORD pid, int suspend); psutil-3.4.2/psutil/_psutil_windows.c0000664000175000017500000030457012572613063021737 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Windows platform-specific module methods for _psutil_windows */ // Fixes clash between winsock2.h and windows.h #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include #include #include #include #include // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") #include "_psutil_windows.h" #include "_psutil_common.h" #include "arch/windows/security.h" #include "arch/windows/process_info.h" #include "arch/windows/process_handles.h" #include "arch/windows/ntextapi.h" #include "arch/windows/inet_ntop.h" #ifdef __MINGW32__ #include "arch/windows/glpi.h" #endif /* * ============================================================================ * Utilities * ============================================================================ */ // a flag for connections without an actual status static int PSUTIL_CONN_NONE = 128; #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define LO_T ((float)1e-7) #define HI_T (LO_T*4294967296.0) #define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) #ifndef AF_INET6 #define AF_INET6 23 #endif #define _psutil_conn_decref_objs() \ Py_DECREF(_AF_INET); \ Py_DECREF(_AF_INET6);\ Py_DECREF(_SOCK_STREAM);\ Py_DECREF(_SOCK_DGRAM); typedef BOOL (WINAPI *LPFN_GLPI) (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); // fix for mingw32, see // https://github.com/giampaolo/psutil/issues/351#c2 typedef struct _DISK_PERFORMANCE_WIN_2008 { LARGE_INTEGER BytesRead; LARGE_INTEGER BytesWritten; LARGE_INTEGER ReadTime; LARGE_INTEGER WriteTime; LARGE_INTEGER IdleTime; DWORD ReadCount; DWORD WriteCount; DWORD QueueDepth; DWORD SplitCount; LARGE_INTEGER QueryTime; DWORD StorageDeviceNumber; WCHAR StorageManagerName[8]; } DISK_PERFORMANCE_WIN_2008; // --- network connections mingw32 support #ifndef _IPRTRMIB_H typedef struct _MIB_TCP6ROW_OWNER_PID { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; UCHAR ucRemoteAddr[16]; DWORD dwRemoteScopeId; DWORD dwRemotePort; DWORD dwState; DWORD dwOwningPid; } MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; typedef struct _MIB_TCP6TABLE_OWNER_PID { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; #endif #ifndef __IPHLPAPI_H__ typedef struct in6_addr { union { UCHAR Byte[16]; USHORT Word[8]; } u; } IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; typedef enum _UDP_TABLE_CLASS { UDP_TABLE_BASIC, UDP_TABLE_OWNER_PID, UDP_TABLE_OWNER_MODULE } UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; typedef struct _MIB_UDPROW_OWNER_PID { DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; typedef struct _MIB_UDPTABLE_OWNER_PID { DWORD dwNumEntries; MIB_UDPROW_OWNER_PID table[ANY_SIZE]; } MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; #endif typedef struct _MIB_UDP6ROW_OWNER_PID { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; typedef struct _MIB_UDP6TABLE_OWNER_PID { DWORD dwNumEntries; MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; } MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; PIP_ADAPTER_ADDRESSES psutil_get_nic_addresses() { // allocate a 15 KB buffer to start with int outBufLen = 15000; DWORD dwRetVal = 0; ULONG attempts = 0; PIP_ADAPTER_ADDRESSES pAddresses = NULL; do { pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); if (pAddresses == NULL) { PyErr_NoMemory(); return NULL; } dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { free(pAddresses); pAddresses = NULL; } else { break; } attempts++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); if (dwRetVal != NO_ERROR) { PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); return NULL; } return pAddresses; } /* * ============================================================================ * Public Python API * ============================================================================ */ /* * Return a Python float representing the system uptime expressed in seconds * since the epoch. */ static PyObject * psutil_boot_time(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 * psutil_pid_exists(PyObject *self, PyObject *args) { long pid; int status; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; status = psutil_pid_is_running(pid); if (-1 == status) return NULL; // exception raised in psutil_pid_is_running() return PyBool_FromLong(status); } /* * Return a Python list of all the PIDs running on the system. */ static PyObject * psutil_pids(PyObject *self, PyObject *args) { DWORD *proclist = NULL; DWORD numberOfReturnedPIDs; DWORD i; PyObject *py_pid = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; proclist = psutil_get_pids(&numberOfReturnedPIDs); if (proclist == NULL) goto error; for (i = 0; i < numberOfReturnedPIDs; i++) { py_pid = Py_BuildValue("I", proclist[i]); if (!py_pid) goto error; if (PyList_Append(py_retlist, py_pid)) goto error; Py_DECREF(py_pid); } // free C array allocated for PIDs free(proclist); return py_retlist; error: Py_XDECREF(py_pid); Py_DECREF(py_retlist); if (proclist != NULL) free(proclist); return NULL; } /* * Kill a process given its PID. */ static PyObject * psutil_proc_kill(PyObject *self, PyObject *args) { HANDLE hProcess; long pid; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (pid == 0) return AccessDenied(); hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { // see https://github.com/giampaolo/psutil/issues/24 NoSuchProcess(); } else { PyErr_SetFromWindowsErr(0); } return NULL; } // kill the process if (! TerminateProcess(hProcess, 0)) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); Py_RETURN_NONE; } /* * Wait for process to terminate and return its exit code. */ static PyObject * psutil_proc_wait(PyObject *self, PyObject *args) { HANDLE hProcess; DWORD ExitCode; DWORD retVal; long pid; long timeout; if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) return NULL; if (pid == 0) return AccessDenied(); hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { // no such process; we do not want to raise NSP but // return None instead. Py_RETURN_NONE; } else { 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 * psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; HANDLE hProcess; FILETIME ftCreate, ftExit, ftKernel, ftUser; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); 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) ); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject * psutil_proc_create_time(PyObject *self, PyObject *args) { long pid; long long unix_time; 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 system boot time if (0 == pid || 4 == pid) return psutil_boot_time(NULL, NULL); hProcess = psutil_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); } /* * Return the number of logical CPUs. */ static PyObject * psutil_cpu_count_logical(PyObject *self, PyObject *args) { SYSTEM_INFO system_info; system_info.dwNumberOfProcessors = 0; GetSystemInfo(&system_info); if (system_info.dwNumberOfProcessors == 0) Py_RETURN_NONE; // mimic os.cpu_count() else return Py_BuildValue("I", system_info.dwNumberOfProcessors); } /* * Return the number of physical CPU cores. */ static PyObject * psutil_cpu_count_phys(PyObject *self, PyObject *args) { LPFN_GLPI glpi; DWORD rc; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL; PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL; DWORD length = 0; DWORD offset = 0; int ncpus = 0; glpi = (LPFN_GLPI)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation"); if (glpi == NULL) goto return_none; while (1) { rc = glpi(buffer, &length); if (rc == FALSE) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { if (buffer) free(buffer); buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc( length); if (NULL == buffer) { PyErr_NoMemory(); return NULL; } } else { goto return_none; } } else { break; } } ptr = buffer; while (offset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= length) { if (ptr->Relationship == RelationProcessorCore) ncpus += 1; offset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ptr++; } free(buffer); if (ncpus == 0) goto return_none; else return Py_BuildValue("i", ncpus); return_none: // mimic os.cpu_count() if (buffer != NULL) free(buffer); Py_RETURN_NONE; } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject * psutil_proc_cmdline(PyObject *self, PyObject *args) { long pid; int pid_return; PyObject *py_retlist; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if ((pid == 0) || (pid == 4)) return Py_BuildValue("[]"); pid_return = psutil_pid_is_running(pid); if (pid_return == 0) return NoSuchProcess(); if (pid_return == -1) return NULL; // 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. py_retlist = psutil_get_cmdline(pid); if ( NULL == py_retlist ) { // carry on anyway, clear any exceptions too PyErr_Clear(); return Py_BuildValue("[]"); } return py_retlist; } /* * Return process executable path. */ static PyObject * psutil_proc_exe(PyObject *self, PyObject *args) { long pid; HANDLE hProcess; wchar_t exe[MAX_PATH]; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); if (NULL == hProcess) return NULL; if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) { CloseHandle(hProcess); PyErr_SetFromWindowsErr(0); return NULL; } CloseHandle(hProcess); return Py_BuildValue("u", exe); } /* * Return process base name. * Note: psutil_proc_exe() is attempted first because it's faster * but it raise AccessDenied for processes owned by other users * in which case we fall back on using this. */ static PyObject * psutil_proc_name(PyObject *self, PyObject *args) { long pid; int ok; PROCESSENTRY32W pentry; HANDLE hSnapShot; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid); if (hSnapShot == INVALID_HANDLE_VALUE) { PyErr_SetFromWindowsErr(0); return NULL; } pentry.dwSize = sizeof(PROCESSENTRY32W); ok = Process32FirstW(hSnapShot, &pentry); if (! ok) { CloseHandle(hSnapShot); PyErr_SetFromWindowsErr(0); return NULL; } while (ok) { if (pentry.th32ProcessID == pid) { CloseHandle(hSnapShot); return PyUnicode_FromWideChar( pentry.szExeFile, wcslen(pentry.szExeFile)); } ok = Process32NextW(hSnapShot, &pentry); } CloseHandle(hSnapShot); NoSuchProcess(); return NULL; } /* * Return process memory information as a Python tuple. */ static PyObject * psutil_proc_memory_info(PyObject *self, PyObject *args) { HANDLE hProcess; DWORD pid; #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 PROCESS_MEMORY_COUNTERS_EX cnt; #else PROCESS_MEMORY_COUNTERS cnt; #endif SIZE_T private = 0; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) return NULL; if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt, sizeof(cnt))) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 private = cnt.PrivateUsage; #endif CloseHandle(hProcess); // PROCESS_MEMORY_COUNTERS values are defined as SIZE_T which on 64bits // is an (unsigned long long) and on 32bits is an (unsigned int). // "_WIN64" is defined if we're running a 64bit Python interpreter not // exclusively if the *system* is 64bit. #if defined(_WIN64) return Py_BuildValue( "(kKKKKKKKKK)", cnt.PageFaultCount, // unsigned long (unsigned long long)cnt.PeakWorkingSetSize, (unsigned long long)cnt.WorkingSetSize, (unsigned long long)cnt.QuotaPeakPagedPoolUsage, (unsigned long long)cnt.QuotaPagedPoolUsage, (unsigned long long)cnt.QuotaPeakNonPagedPoolUsage, (unsigned long long)cnt.QuotaNonPagedPoolUsage, (unsigned long long)cnt.PagefileUsage, (unsigned long long)cnt.PeakPagefileUsage, (unsigned long long)private); #else return Py_BuildValue( "(kIIIIIIIII)", cnt.PageFaultCount, // unsigned long (unsigned int)cnt.PeakWorkingSetSize, (unsigned int)cnt.WorkingSetSize, (unsigned int)cnt.QuotaPeakPagedPoolUsage, (unsigned int)cnt.QuotaPagedPoolUsage, (unsigned int)cnt.QuotaPeakNonPagedPoolUsage, (unsigned int)cnt.QuotaNonPagedPoolUsage, (unsigned int)cnt.PagefileUsage, (unsigned int)cnt.PeakPagefileUsage, (unsigned int)private); #endif } /* * Alternative implementation of the one above but bypasses ACCESS DENIED. */ static PyObject * psutil_proc_memory_info_2(PyObject *self, PyObject *args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; SIZE_T private; unsigned long pfault_count; #if defined(_WIN64) unsigned long long m1, m2, m3, m4, m5, m6, m7, m8; #else unsigned int m1, m2, m3, m4, m5, m6, m7, m8; #endif if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_get_proc_info(pid, &process, &buffer)) return NULL; #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 private = process->PrivatePageCount; #else private = 0; #endif pfault_count = 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; free(buffer); // SYSTEM_PROCESS_INFORMATION values are defined as SIZE_T which on 64 // bits is an (unsigned long long) and on 32bits is an (unsigned int). // "_WIN64" is defined if we're running a 64bit Python interpreter not // exclusively if the *system* is 64bit. #if defined(_WIN64) return Py_BuildValue("(kKKKKKKKKK)", #else return Py_BuildValue("(kIIIIIIIII)", #endif pfault_count, m1, m2, m3, m4, m5, m6, m7, m8, private); } /* * Return a Python integer indicating the total amount of physical memory * in bytes. */ static PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { MEMORYSTATUSEX memInfo; memInfo.dwLength = sizeof(MEMORYSTATUSEX); if (! GlobalMemoryStatusEx(&memInfo)) return PyErr_SetFromWindowsErr(0); return Py_BuildValue("(LLLLLL)", memInfo.ullTotalPhys, // total memInfo.ullAvailPhys, // avail memInfo.ullTotalPageFile, // total page file memInfo.ullAvailPageFile, // avail page file memInfo.ullTotalVirtual, // total virtual memInfo.ullAvailVirtual); // avail virtual } /* * Retrieves system CPU timing information as a (user, system, idle) * tuple. On a multiprocessor system, the values returned are the * sum of the designated times across all processors. */ static PyObject * psutil_cpu_times(PyObject *self, PyObject *args) { float idle, kernel, user, system; FILETIME idle_time, kernel_time, user_time; if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) return PyErr_SetFromWindowsErr(0); idle = (float)((HI_T * idle_time.dwHighDateTime) + \ (LO_T * idle_time.dwLowDateTime)); user = (float)((HI_T * user_time.dwHighDateTime) + \ (LO_T * user_time.dwLowDateTime)); kernel = (float)((HI_T * kernel_time.dwHighDateTime) + \ (LO_T * kernel_time.dwLowDateTime)); // Kernel time includes idle time. // We return only busy kernel time subtracting idle time from // kernel time. system = (kernel - idle); return Py_BuildValue("(fff)", user, system, idle); } /* * Same as above but for all system CPUs. */ static PyObject * psutil_per_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 *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; // 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++) { py_tuple = 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 py_tuple = Py_BuildValue("(ddd)", user, kernel - idle, idle); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(sppi); FreeLibrary(hNtDll); return py_retlist; } // END NtQuerySystemInformation } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION } // END GetProcAddress } // END LoadLibrary goto error; error: Py_XDECREF(py_tuple); Py_DECREF(py_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 * psutil_proc_cwd(PyObject *self, PyObject *args) { long pid; HANDLE processHandle = NULL; PVOID pebAddress; PVOID rtlUserProcParamsAddress; UNICODE_STRING currentDirectory; WCHAR *currentDirectoryContent = NULL; PyObject *py_unicode = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; processHandle = psutil_handle_from_pid(pid); if (processHandle == NULL) return NULL; pebAddress = psutil_get_peb_address(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); if (currentDirectoryContent == NULL) { PyErr_NoMemory(); goto error; } // 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 py_unicode = PyUnicode_FromWideChar( currentDirectoryContent, wcslen(currentDirectoryContent)); if (py_unicode == NULL) goto error; CloseHandle(processHandle); free(currentDirectoryContent); return py_unicode; error: Py_XDECREF(py_unicode); if (currentDirectoryContent != NULL) free(currentDirectoryContent); if (processHandle != NULL) CloseHandle(processHandle); return NULL; } /* * Resume or suspends a process */ int psutil_proc_suspend_or_resume(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 * psutil_proc_suspend(PyObject *self, PyObject *args) { long pid; int suspend = 1; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_suspend_or_resume(pid, suspend)) return NULL; Py_RETURN_NONE; } static PyObject * psutil_proc_resume(PyObject *self, PyObject *args) { long pid; int suspend = 0; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_proc_suspend_or_resume(pid, suspend)) return NULL; Py_RETURN_NONE; } static PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { HANDLE hThread; THREADENTRY32 te32 = {0}; long pid; int pid_return; int rc; FILETIME ftDummy, ftKernel, ftUser; HANDLE hThreadSnap = NULL; PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (pid == 0) { // raise AD instead of returning 0 as procexp is able to // retrieve useful information somehow AccessDenied(); goto error; } pid_return = psutil_pid_is_running(pid); if (pid_return == 0) { NoSuchProcess(); goto error; } if (pid_return == -1) goto error; hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) { PyErr_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) { py_tuple = NULL; hThread = NULL; hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID); if (hThread == NULL) { // thread has disappeared on us continue; } rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser); if (rc == 0) { PyErr_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 */ py_tuple = Py_BuildValue( "kdd", te32.th32ThreadID, (double)(ftUser.dwHighDateTime * 429.4967296 + \ ftUser.dwLowDateTime * 1e-7), (double)(ftKernel.dwHighDateTime * 429.4967296 + \ ftKernel.dwLowDateTime * 1e-7)); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); CloseHandle(hThread); } } while (Thread32Next(hThreadSnap, &te32)); CloseHandle(hThreadSnap); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (hThread != NULL) CloseHandle(hThread); if (hThreadSnap != NULL) CloseHandle(hThreadSnap); return NULL; } static PyObject * psutil_proc_open_files(PyObject *self, PyObject *args) { long pid; HANDLE processHandle; DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; PyObject *py_retlist; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; processHandle = psutil_handle_from_pid_waccess(pid, access); if (processHandle == NULL) return NULL; py_retlist = psutil_get_open_files(pid, processHandle); CloseHandle(processHandle); if (py_retlist == NULL) return PyErr_SetFromWindowsErr(0); return py_retlist; } /* Accept a filename's drive in native format like "\Device\HarddiskVolume1\" and return the corresponding drive letter (e.g. "C:\\"). If no match is found return an empty string. */ static PyObject * psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) { LPCTSTR lpDevicePath; TCHAR d = TEXT('A'); TCHAR szBuff[5]; if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) return NULL; while (d <= TEXT('Z')) { TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')}; TCHAR szTarget[512] = {0}; if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) { if (_tcscmp(lpDevicePath, szTarget) == 0) { _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d); return Py_BuildValue("s", szBuff); } } d++; } return Py_BuildValue("s", ""); } /* * Return process username as a "DOMAIN//USERNAME" string. */ static PyObject * psutil_proc_username(PyObject *self, PyObject *args) { long pid; HANDLE processHandle; HANDLE tokenHandle; PTOKEN_USER user; ULONG bufferSize; PTSTR name; ULONG nameSize; PTSTR domainName; ULONG domainNameSize; SID_NAME_USE nameUse; PTSTR fullName; PyObject *py_unicode; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; processHandle = psutil_handle_from_pid_waccess( pid, PROCESS_QUERY_INFORMATION); if (processHandle == NULL) return NULL; if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) { CloseHandle(processHandle); return PyErr_SetFromWindowsErr(0); } CloseHandle(processHandle); // Get the user SID. bufferSize = 0x100; user = malloc(bufferSize); if (user == NULL) return PyErr_NoMemory(); if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, &bufferSize)) { free(user); user = malloc(bufferSize); if (user == NULL) { CloseHandle(tokenHandle); return PyErr_NoMemory(); } if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize, &bufferSize)) { free(user); CloseHandle(tokenHandle); return PyErr_SetFromWindowsErr(0); } } CloseHandle(tokenHandle); // resolve the SID to a name nameSize = 0x100; domainNameSize = 0x100; name = malloc(nameSize * sizeof(TCHAR)); if (name == NULL) return PyErr_NoMemory(); domainName = malloc(domainNameSize * sizeof(TCHAR)); if (domainName == NULL) return PyErr_NoMemory(); if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName, &domainNameSize, &nameUse)) { free(name); free(domainName); name = malloc(nameSize * sizeof(TCHAR)); if (name == NULL) return PyErr_NoMemory(); domainName = malloc(domainNameSize * sizeof(TCHAR)); if (domainName == NULL) return PyErr_NoMemory(); if (!LookupAccountSid(NULL, user->User.Sid, name, &nameSize, domainName, &domainNameSize, &nameUse)) { free(name); free(domainName); free(user); return PyErr_SetFromWindowsErr(0); } } nameSize = _tcslen(name); domainNameSize = _tcslen(domainName); // build the full username string fullName = malloc((domainNameSize + 1 + nameSize + 1) * sizeof(TCHAR)); if (fullName == NULL) { free(name); free(domainName); free(user); return PyErr_NoMemory(); } memcpy(fullName, domainName, domainNameSize); fullName[domainNameSize] = '\\'; memcpy(&fullName[domainNameSize + 1], name, nameSize); fullName[domainNameSize + 1 + nameSize] = '\0'; py_unicode = PyUnicode_Decode( fullName, _tcslen(fullName), Py_FileSystemDefaultEncoding, "replace"); free(fullName); free(name); free(domainName); free(user); return py_unicode; } /* * Return a list of network connections opened by a process */ static PyObject * psutil_net_connections(PyObject *self, PyObject *args) { static long null_address[4] = { 0, 0, 0, 0 }; unsigned long pid; typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(struct in_addr *, PSTR); _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR); _RtlIpv6AddressToStringA rtlIpv6AddressToStringA; typedef DWORD (WINAPI * _GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, TCP_TABLE_CLASS, ULONG); _GetExtendedTcpTable getExtendedTcpTable; typedef DWORD (WINAPI * _GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG, UDP_TABLE_CLASS, ULONG); _GetExtendedUdpTable getExtendedUdpTable; PVOID table = NULL; DWORD tableSize; PMIB_TCPTABLE_OWNER_PID tcp4Table; PMIB_UDPTABLE_OWNER_PID udp4Table; PMIB_TCP6TABLE_OWNER_PID tcp6Table; PMIB_UDP6TABLE_OWNER_PID udp6Table; ULONG i; CHAR addressBufferLocal[65]; CHAR addressBufferRemote[65]; PyObject *py_retlist; PyObject *py_conn_tuple = NULL; PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; PyObject *py_addr_tuple_local = NULL; PyObject *py_addr_tuple_remote = NULL; PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) { _psutil_conn_decref_objs(); return NULL; } if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { _psutil_conn_decref_objs(); PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); return NULL; } if (pid != -1) { if (psutil_pid_is_running(pid) == 0) { _psutil_conn_decref_objs(); return NoSuchProcess(); } } // Import some functions. { HMODULE ntdll; HMODULE iphlpapi; ntdll = LoadLibrary(TEXT("ntdll.dll")); rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress( ntdll, "RtlIpv4AddressToStringA"); rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress( ntdll, "RtlIpv6AddressToStringA"); /* TODO: Check these two function pointers */ iphlpapi = LoadLibrary(TEXT("iphlpapi.dll")); getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi, "GetExtendedTcpTable"); getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi, "GetExtendedUdpTable"); FreeLibrary(ntdll); FreeLibrary(iphlpapi); } if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) { PyErr_SetString(PyExc_NotImplementedError, "feature not supported on this Windows version"); _psutil_conn_decref_objs(); return NULL; } py_retlist = PyList_New(0); if (py_retlist == NULL) { _psutil_conn_decref_objs(); return NULL; } // TCP IPv4 if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); table = malloc(tableSize); if (table == NULL) { PyErr_NoMemory(); goto error; } if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) == 0) { tcp4Table = table; for (i = 0; i < tcp4Table->dwNumEntries; i++) { if (pid != -1) { if (tcp4Table->table[i].dwOwningPid != pid) { continue; } } if (tcp4Table->table[i].dwLocalAddr != 0 || tcp4Table->table[i].dwLocalPort != 0) { struct in_addr addr; addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; rtlIpv4AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; // On Windows <= XP, remote addr is filled even if socket // is in LISTEN mode in which case we just ignore it. if ((tcp4Table->table[i].dwRemoteAddr != 0 || tcp4Table->table[i].dwRemotePort != 0) && (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) { struct in_addr addr; addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; rtlIpv4AddressToStringA(&addr, addressBufferRemote); py_addr_tuple_remote = Py_BuildValue( "(si)", addressBufferRemote, BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); } else { py_addr_tuple_remote = PyTuple_New(0); } if (py_addr_tuple_remote == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET, SOCK_STREAM, py_addr_tuple_local, py_addr_tuple_remote, tcp4Table->table[i].dwState, tcp4Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } } free(table); } // TCP IPv6 if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0); table = malloc(tableSize); if (table == NULL) { PyErr_NoMemory(); goto error; } if (getExtendedTcpTable(table, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) == 0) { tcp6Table = table; for (i = 0; i < tcp6Table->dwNumEntries; i++) { if (pid != -1) { if (tcp6Table->table[i].dwOwningPid != pid) { continue; } } if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || tcp6Table->table[i].dwLocalPort != 0) { struct in6_addr addr; memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; // On Windows <= XP, remote addr is filled even if socket // is in LISTEN mode in which case we just ignore it. if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) != 0 || tcp6Table->table[i].dwRemotePort != 0) && (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) { struct in6_addr addr; memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferRemote); py_addr_tuple_remote = Py_BuildValue( "(si)", addressBufferRemote, BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); } else { py_addr_tuple_remote = PyTuple_New(0); } if (py_addr_tuple_remote == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET6, SOCK_STREAM, py_addr_tuple_local, py_addr_tuple_remote, tcp6Table->table[i].dwState, tcp6Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } } free(table); } // UDP IPv4 if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) && (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0); table = malloc(tableSize); if (table == NULL) { PyErr_NoMemory(); goto error; } if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0) == 0) { udp4Table = table; for (i = 0; i < udp4Table->dwNumEntries; i++) { if (pid != -1) { if (udp4Table->table[i].dwOwningPid != pid) { continue; } } if (udp4Table->table[i].dwLocalAddr != 0 || udp4Table->table[i].dwLocalPort != 0) { struct in_addr addr; addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; rtlIpv4AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET, SOCK_DGRAM, py_addr_tuple_local, PyTuple_New(0), PSUTIL_CONN_NONE, udp4Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } } free(table); } // UDP IPv6 if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) && (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1)) { table = NULL; py_conn_tuple = NULL; py_addr_tuple_local = NULL; py_addr_tuple_remote = NULL; tableSize = 0; getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_PID, 0); table = malloc(tableSize); if (table == NULL) { PyErr_NoMemory(); goto error; } if (getExtendedUdpTable(table, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_PID, 0) == 0) { udp6Table = table; for (i = 0; i < udp6Table->dwNumEntries; i++) { if (pid != -1) { if (udp6Table->table[i].dwOwningPid != pid) { continue; } } if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || udp6Table->table[i].dwLocalPort != 0) { struct in6_addr addr; memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferLocal); py_addr_tuple_local = Py_BuildValue( "(si)", addressBufferLocal, BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); } else { py_addr_tuple_local = PyTuple_New(0); } if (py_addr_tuple_local == NULL) goto error; py_conn_tuple = Py_BuildValue( "(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM, py_addr_tuple_local, PyTuple_New(0), PSUTIL_CONN_NONE, udp6Table->table[i].dwOwningPid); if (!py_conn_tuple) goto error; if (PyList_Append(py_retlist, py_conn_tuple)) goto error; Py_DECREF(py_conn_tuple); } } free(table); } _psutil_conn_decref_objs(); return py_retlist; error: _psutil_conn_decref_objs(); Py_XDECREF(py_conn_tuple); Py_XDECREF(py_addr_tuple_local); Py_XDECREF(py_addr_tuple_remote); Py_DECREF(py_retlist); if (table != NULL) free(table); return NULL; } /* * Get process priority as a Python integer. */ static PyObject * psutil_proc_priority_get(PyObject *self, PyObject *args) { long pid; DWORD priority; HANDLE hProcess; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) return NULL; priority = GetPriorityClass(hProcess); CloseHandle(hProcess); if (priority == 0) { PyErr_SetFromWindowsErr(0); return NULL; } return Py_BuildValue("i", priority); } /* * Set process priority. */ static PyObject * psutil_proc_priority_set(PyObject *self, PyObject *args) { long pid; int priority; int retval; HANDLE hProcess; DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; if (! PyArg_ParseTuple(args, "li", &pid, &priority)) return NULL; hProcess = psutil_handle_from_pid_waccess(pid, access); if (hProcess == NULL) return NULL; retval = SetPriorityClass(hProcess, priority); CloseHandle(hProcess); if (retval == 0) { PyErr_SetFromWindowsErr(0); return NULL; } Py_RETURN_NONE; } #if (_WIN32_WINNT >= 0x0600) // Windows Vista /* * Get process IO priority as a Python integer. */ static PyObject * psutil_proc_io_priority_get(PyObject *self, PyObject *args) { long pid; HANDLE hProcess; PULONG IoPriority; _NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) return NULL; NtQueryInformationProcess( hProcess, ProcessIoPriority, &IoPriority, sizeof(ULONG), NULL ); CloseHandle(hProcess); return Py_BuildValue("i", IoPriority); } /* * Set process IO priority. */ static PyObject * psutil_proc_io_priority_set(PyObject *self, PyObject *args) { long pid; int prio; HANDLE hProcess; _NtSetInformationProcess NtSetInformationProcess = (_NtSetInformationProcess)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtSetInformationProcess"); if (NtSetInformationProcess == NULL) { PyErr_SetString(PyExc_RuntimeError, "couldn't get NtSetInformationProcess"); return NULL; } if (! PyArg_ParseTuple(args, "li", &pid, &prio)) return NULL; hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_ALL_ACCESS); if (hProcess == NULL) return NULL; NtSetInformationProcess( hProcess, ProcessIoPriority, (PVOID)&prio, sizeof((PVOID)prio) ); CloseHandle(hProcess); Py_RETURN_NONE; } #endif /* * Return a Python tuple referencing process I/O counters. */ static PyObject * psutil_proc_io_counters(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; IO_COUNTERS IoCounters; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) return NULL; if (! GetProcessIoCounters(hProcess, &IoCounters)) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); return Py_BuildValue("(KKKK)", IoCounters.ReadOperationCount, IoCounters.WriteOperationCount, IoCounters.ReadTransferCount, IoCounters.WriteTransferCount); } /* * Return process CPU affinity as a bitmask */ static PyObject * psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; DWORD_PTR proc_mask; DWORD_PTR system_mask; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) { return NULL; } if (GetProcessAffinityMask(hProcess, &proc_mask, &system_mask) == 0) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); #ifdef _WIN64 return Py_BuildValue("K", (unsigned long long)proc_mask); #else return Py_BuildValue("k", (unsigned long)proc_mask); #endif } /* * Set process CPU affinity */ static PyObject * psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; DWORD dwDesiredAccess = \ PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; DWORD_PTR mask; #ifdef _WIN64 if (! PyArg_ParseTuple(args, "lK", &pid, &mask)) #else if (! PyArg_ParseTuple(args, "lk", &pid, &mask)) #endif { return NULL; } hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); if (hProcess == NULL) return NULL; if (SetProcessAffinityMask(hProcess, mask) == 0) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); Py_RETURN_NONE; } /* * Return True if one of the process threads is in a waiting or * suspended status. */ static PyObject * psutil_proc_is_suspended(PyObject *self, PyObject *args) { DWORD pid; ULONG i; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_get_proc_info(pid, &process, &buffer)) { return NULL; } for (i = 0; i < process->NumberOfThreads; i++) { if (process->Threads[i].ThreadState != Waiting || process->Threads[i].WaitReason != Suspended) { free(buffer); Py_RETURN_FALSE; } } free(buffer); Py_RETURN_TRUE; } /* * Return path's disk total and free as a Python tuple. */ static PyObject * psutil_disk_usage(PyObject *self, PyObject *args) { BOOL retval; ULARGE_INTEGER _, total, free; char *path; if (PyArg_ParseTuple(args, "u", &path)) { Py_BEGIN_ALLOW_THREADS retval = GetDiskFreeSpaceExW((LPCWSTR)path, &_, &total, &free); Py_END_ALLOW_THREADS goto return_; } // on Python 2 we also want to accept plain strings other // than Unicode #if PY_MAJOR_VERSION <= 2 PyErr_Clear(); // drop the argument parsing error if (PyArg_ParseTuple(args, "s", &path)) { Py_BEGIN_ALLOW_THREADS retval = GetDiskFreeSpaceEx(path, &_, &total, &free); Py_END_ALLOW_THREADS goto return_; } #endif return NULL; return_: if (retval == 0) return PyErr_SetFromWindowsErr(0); else return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); } /* * Return a Python list of named tuples with overall network I/O information */ static PyObject * psutil_net_io_counters(PyObject *self, PyObject *args) { DWORD dwRetVal = 0; MIB_IFROW *pIfRow = NULL; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PyObject *py_retdict = PyDict_New(); PyObject *py_nic_info = NULL; PyObject *py_nic_name = NULL; if (py_retdict == NULL) return NULL; pAddresses = psutil_get_nic_addresses(); if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; while (pCurrAddresses) { py_nic_name = NULL; py_nic_info = NULL; pIfRow = (MIB_IFROW *) malloc(sizeof(MIB_IFROW)); if (pIfRow == NULL) { PyErr_NoMemory(); goto error; } pIfRow->dwIndex = pCurrAddresses->IfIndex; dwRetVal = GetIfEntry(pIfRow); if (dwRetVal != NO_ERROR) { PyErr_SetString(PyExc_RuntimeError, "GetIfEntry() failed."); goto error; } py_nic_info = Py_BuildValue("(kkkkkkkk)", pIfRow->dwOutOctets, pIfRow->dwInOctets, pIfRow->dwOutUcastPkts, pIfRow->dwInUcastPkts, pIfRow->dwInErrors, pIfRow->dwOutErrors, pIfRow->dwInDiscards, pIfRow->dwOutDiscards); if (!py_nic_info) goto error; py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); if (py_nic_name == NULL) goto error; if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info)) goto error; Py_XDECREF(py_nic_name); Py_XDECREF(py_nic_info); free(pIfRow); pCurrAddresses = pCurrAddresses->Next; } free(pAddresses); return py_retdict; error: Py_XDECREF(py_nic_name); Py_XDECREF(py_nic_info); Py_DECREF(py_retdict); if (pAddresses != NULL) free(pAddresses); if (pIfRow != NULL) free(pIfRow); return NULL; } /* * Return a Python dict of tuples for disk I/O information */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { DISK_PERFORMANCE_WIN_2008 diskPerformance; DWORD dwSize; HANDLE hDevice = NULL; char szDevice[MAX_PATH]; char szDeviceDisplay[MAX_PATH]; int devNum; PyObject *py_retdict = PyDict_New(); PyObject *py_tuple = NULL; if (py_retdict == NULL) return NULL; // Apparently there's no way to figure out how many times we have // to iterate in order to find valid drives. // Let's assume 32, which is higher than 26, the number of letters // in the alphabet (from A:\ to Z:\). for (devNum = 0; devNum <= 32; ++devNum) { py_tuple = NULL; sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum); hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) continue; if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance, sizeof(diskPerformance), &dwSize, NULL)) { sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum); py_tuple = Py_BuildValue( "(IILLKK)", diskPerformance.ReadCount, diskPerformance.WriteCount, diskPerformance.BytesRead, diskPerformance.BytesWritten, (unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000, (unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000); if (!py_tuple) goto error; if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_tuple)) { goto error; } Py_XDECREF(py_tuple); } else { // XXX we might get here with ERROR_INSUFFICIENT_BUFFER when // compiling with mingw32; not sure what to do. // return PyErr_SetFromWindowsErr(0); ;; } CloseHandle(hDevice); } return py_retdict; error: Py_XDECREF(py_tuple); Py_DECREF(py_retdict); if (hDevice != NULL) CloseHandle(hDevice); return NULL; } static char *psutil_get_drive_type(int type) { switch (type) { case DRIVE_FIXED: return "fixed"; case DRIVE_CDROM: return "cdrom"; case DRIVE_REMOVABLE: return "removable"; case DRIVE_UNKNOWN: return "unknown"; case DRIVE_NO_ROOT_DIR: return "unmounted"; case DRIVE_REMOTE: return "remote"; case DRIVE_RAMDISK: return "ramdisk"; default: return "?"; } } #ifndef _ARRAYSIZE #define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif /* * Return disk partitions as a list of tuples such as * (drive_letter, drive_letter, type, "") */ static PyObject * psutil_disk_partitions(PyObject *self, PyObject *args) { DWORD num_bytes; char drive_strings[255]; char *drive_letter = drive_strings; int all; int type; int ret; char opts[20]; LPTSTR fs_type[MAX_PATH + 1] = { 0 }; DWORD pflags = 0; PyObject *py_all; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) { return NULL; } // avoid to visualize a message box in case something goes wrong // see https://github.com/giampaolo/psutil/issues/264 SetErrorMode(SEM_FAILCRITICALERRORS); if (! PyArg_ParseTuple(args, "O", &py_all)) goto error; all = PyObject_IsTrue(py_all); Py_BEGIN_ALLOW_THREADS num_bytes = GetLogicalDriveStrings(254, drive_letter); Py_END_ALLOW_THREADS if (num_bytes == 0) { PyErr_SetFromWindowsErr(0); goto error; } while (*drive_letter != 0) { py_tuple = NULL; opts[0] = 0; fs_type[0] = 0; Py_BEGIN_ALLOW_THREADS type = GetDriveType(drive_letter); Py_END_ALLOW_THREADS // by default we only show hard drives and cd-roms if (all == 0) { if ((type == DRIVE_UNKNOWN) || (type == DRIVE_NO_ROOT_DIR) || (type == DRIVE_REMOTE) || (type == DRIVE_RAMDISK)) { goto next; } // floppy disk: skip it by default as it introduces a // considerable slowdown. if ((type == DRIVE_REMOVABLE) && (strcmp(drive_letter, "A:\\") == 0)) { goto next; } } ret = GetVolumeInformation( (LPCTSTR)drive_letter, NULL, _ARRAYSIZE(drive_letter), NULL, NULL, &pflags, (LPTSTR)fs_type, _ARRAYSIZE(fs_type)); if (ret == 0) { // We might get here in case of a floppy hard drive, in // which case the error is (21, "device not ready"). // Let's pretend it didn't happen as we already have // the drive name and type ('removable'). strcat_s(opts, _countof(opts), ""); SetLastError(0); } else { if (pflags & FILE_READ_ONLY_VOLUME) strcat_s(opts, _countof(opts), "ro"); else strcat_s(opts, _countof(opts), "rw"); if (pflags & FILE_VOLUME_IS_COMPRESSED) strcat_s(opts, _countof(opts), ",compressed"); } if (strlen(opts) > 0) strcat_s(opts, _countof(opts), ","); strcat_s(opts, _countof(opts), psutil_get_drive_type(type)); py_tuple = Py_BuildValue( "(ssss)", drive_letter, drive_letter, fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS opts); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); goto next; next: drive_letter = strchr(drive_letter, 0) + 1; } SetErrorMode(0); return py_retlist; error: SetErrorMode(0); Py_XDECREF(py_tuple); Py_DECREF(py_retlist); return NULL; } /* * Return a Python dict of tuples for disk I/O information */ static PyObject * psutil_users(PyObject *self, PyObject *args) { HANDLE hServer = NULL; LPTSTR buffer_user = NULL; LPTSTR buffer_addr = NULL; PWTS_SESSION_INFO sessions = NULL; DWORD count; DWORD i; DWORD sessionId; DWORD bytes; PWTS_CLIENT_ADDRESS address; char address_str[50]; long long unix_time; PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW; WINSTATION_INFO station_info; HINSTANCE hInstWinSta = NULL; ULONG returnLen; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_address = NULL; PyObject *py_buffer_user_encoded = NULL; if (py_retlist == NULL) return NULL; hInstWinSta = LoadLibraryA("winsta.dll"); WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) \ GetProcAddress(hInstWinSta, "WinStationQueryInformationW"); hServer = WTSOpenServer('\0'); if (hServer == NULL) { PyErr_SetFromWindowsErr(0); goto error; } if (WTSEnumerateSessions(hServer, 0, 1, &sessions, &count) == 0) { PyErr_SetFromWindowsErr(0); goto error; } for (i = 0; i < count; i++) { py_address = NULL; py_tuple = NULL; sessionId = sessions[i].SessionId; if (buffer_user != NULL) WTSFreeMemory(buffer_user); if (buffer_addr != NULL) WTSFreeMemory(buffer_addr); buffer_user = NULL; buffer_addr = NULL; // username bytes = 0; if (WTSQuerySessionInformation(hServer, sessionId, WTSUserName, &buffer_user, &bytes) == 0) { PyErr_SetFromWindowsErr(0); goto error; } if (bytes == 1) continue; // address bytes = 0; if (WTSQuerySessionInformation(hServer, sessionId, WTSClientAddress, &buffer_addr, &bytes) == 0) { PyErr_SetFromWindowsErr(0); goto error; } address = (PWTS_CLIENT_ADDRESS)buffer_addr; if (address->AddressFamily == 0) { // AF_INET sprintf_s(address_str, _countof(address_str), "%u.%u.%u.%u", address->Address[0], address->Address[1], address->Address[2], address->Address[3]); py_address = Py_BuildValue("s", address_str); if (!py_address) goto error; } else { py_address = Py_None; } // login time if (!WinStationQueryInformationW(hServer, sessionId, WinStationInformation, &station_info, sizeof(station_info), &returnLen)) { goto error; } unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; unix_time += \ station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; unix_time /= 10000000; py_buffer_user_encoded = PyUnicode_Decode( buffer_user, _tcslen(buffer_user), Py_FileSystemDefaultEncoding, "replace"); py_tuple = Py_BuildValue("OOd", py_buffer_user_encoded, py_address, (double)unix_time); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_XDECREF(py_buffer_user_encoded); Py_XDECREF(py_address); Py_XDECREF(py_tuple); } WTSCloseServer(hServer); WTSFreeMemory(sessions); WTSFreeMemory(buffer_user); WTSFreeMemory(buffer_addr); FreeLibrary(hInstWinSta); return py_retlist; error: Py_XDECREF(py_buffer_user_encoded); Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_DECREF(py_retlist); if (hInstWinSta != NULL) FreeLibrary(hInstWinSta); if (hServer != NULL) WTSCloseServer(hServer); if (sessions != NULL) WTSFreeMemory(sessions); if (buffer_user != NULL) WTSFreeMemory(buffer_user); if (buffer_addr != NULL) WTSFreeMemory(buffer_addr); return NULL; } /* * Return the number of handles opened by process. */ static PyObject * psutil_proc_num_handles(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess; DWORD handleCount; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) return NULL; if (! GetProcessHandleCount(hProcess, &handleCount)) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } CloseHandle(hProcess); return Py_BuildValue("k", handleCount); } /* * Get various process information by using NtQuerySystemInformation. * We use this as a fallback when faster functions fail with access * denied. This is slower because it iterates over all processes. * Returned tuple includes the following process info: * * - num_threads * - ctx_switches * - num_handles (fallback) * - user/kernel times (fallback) * - create time (fallback) * - io counters (fallback) */ static PyObject * psutil_proc_info(PyObject *self, PyObject *args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; ULONG num_handles; ULONG i; ULONG ctx_switches = 0; double user_time; double kernel_time; long long create_time; int num_threads; LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (! psutil_get_proc_info(pid, &process, &buffer)) return NULL; num_handles = process->HandleCount; for (i = 0; i < process->NumberOfThreads; i++) ctx_switches += process->Threads[i].ContextSwitches; user_time = (double)process->UserTime.HighPart * 429.4967296 + \ (double)process->UserTime.LowPart * 1e-7; kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \ (double)process->KernelTime.LowPart * 1e-7; // Convert the LARGE_INTEGER union to a Unix time. // It's the best I could find by googling and borrowing code here // and there. The time returned has a precision of 1 second. if (0 == pid || 4 == pid) { // the python module will translate this into BOOT_TIME later create_time = 0; } else { create_time = ((LONGLONG)process->CreateTime.HighPart) << 32; create_time += process->CreateTime.LowPart - 116444736000000000LL; create_time /= 10000000; } num_threads = (int)process->NumberOfThreads; io_rcount = process->ReadOperationCount.QuadPart; io_wcount = process->WriteOperationCount.QuadPart; io_rbytes = process->ReadTransferCount.QuadPart; io_wbytes = process->WriteTransferCount.QuadPart; free(buffer); return Py_BuildValue( "kkdddiKKKK", num_handles, ctx_switches, user_time, kernel_time, (double)create_time, num_threads, io_rcount, io_wcount, io_rbytes, io_wbytes ); } static char *get_region_protection_string(ULONG protection) { switch (protection & 0xff) { case PAGE_NOACCESS: return ""; case PAGE_READONLY: return "r"; case PAGE_READWRITE: return "rw"; case PAGE_WRITECOPY: return "wc"; case PAGE_EXECUTE: return "x"; case PAGE_EXECUTE_READ: return "xr"; case PAGE_EXECUTE_READWRITE: return "xrw"; case PAGE_EXECUTE_WRITECOPY: return "xwc"; default: return "?"; } } /* * Return a list of process's memory mappings. */ static PyObject * psutil_proc_memory_maps(PyObject *self, PyObject *args) { DWORD pid; HANDLE hProcess = NULL; MEMORY_BASIC_INFORMATION basicInfo; PVOID baseAddress; PVOID previousAllocationBase; CHAR mappedFileName[MAX_PATH]; SYSTEM_INFO system_info; LPVOID maxAddr; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) goto error; GetSystemInfo(&system_info); maxAddr = system_info.lpMaximumApplicationAddress; baseAddress = NULL; previousAllocationBase = NULL; while (VirtualQueryEx(hProcess, baseAddress, &basicInfo, sizeof(MEMORY_BASIC_INFORMATION))) { py_tuple = NULL; if (baseAddress > maxAddr) break; if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName, sizeof(mappedFileName))) { py_tuple = Py_BuildValue( "(kssI)", (unsigned long)baseAddress, get_region_protection_string(basicInfo.Protect), mappedFileName, basicInfo.RegionSize); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } previousAllocationBase = basicInfo.AllocationBase; baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; } CloseHandle(hProcess); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (hProcess != NULL) CloseHandle(hProcess); return NULL; } /* * Return a {pid:ppid, ...} dict for all running processes. */ static PyObject * psutil_ppid_map(PyObject *self, PyObject *args) { PyObject *py_pid = NULL; PyObject *py_ppid = NULL; PyObject *py_retdict = PyDict_New(); HANDLE handle = NULL; PROCESSENTRY32 pe = {0}; pe.dwSize = sizeof(PROCESSENTRY32); if (py_retdict == NULL) return NULL; handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (handle == INVALID_HANDLE_VALUE) { PyErr_SetFromWindowsErr(0); Py_DECREF(py_retdict); return NULL; } if (Process32First(handle, &pe)) { do { py_pid = Py_BuildValue("I", pe.th32ProcessID); if (py_pid == NULL) goto error; py_ppid = Py_BuildValue("I", pe.th32ParentProcessID); if (py_ppid == NULL) goto error; if (PyDict_SetItem(py_retdict, py_pid, py_ppid)) goto error; Py_DECREF(py_pid); Py_DECREF(py_ppid); } while (Process32Next(handle, &pe)); } CloseHandle(handle); return py_retdict; error: Py_XDECREF(py_pid); Py_XDECREF(py_ppid); Py_DECREF(py_retdict); CloseHandle(handle); return NULL; } /* * Return NICs addresses. */ static PyObject * psutil_net_if_addrs(PyObject *self, PyObject *args) { unsigned int i = 0; ULONG family; PCTSTR intRet; char *ptr; char buff[100]; DWORD bufflen = 100; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_address = NULL; PyObject *py_mac_address = NULL; PyObject *py_nic_name = NULL; if (py_retlist == NULL) return NULL; pAddresses = psutil_get_nic_addresses(); if (pAddresses == NULL) goto error; pCurrAddresses = pAddresses; while (pCurrAddresses) { pUnicast = pCurrAddresses->FirstUnicastAddress; py_nic_name = NULL; py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); if (py_nic_name == NULL) goto error; // MAC address if (pCurrAddresses->PhysicalAddressLength != 0) { ptr = buff; *ptr = '\0'; for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) { if (i == (pCurrAddresses->PhysicalAddressLength - 1)) { sprintf_s(ptr, _countof(buff), "%.2X\n", (int)pCurrAddresses->PhysicalAddress[i]); } else { sprintf_s(ptr, _countof(buff), "%.2X-", (int)pCurrAddresses->PhysicalAddress[i]); } ptr += 3; } *--ptr = '\0'; #if PY_MAJOR_VERSION >= 3 py_mac_address = PyUnicode_FromString(buff); #else py_mac_address = PyString_FromString(buff); #endif if (py_mac_address == NULL) goto error; Py_INCREF(Py_None); Py_INCREF(Py_None); Py_INCREF(Py_None); py_tuple = Py_BuildValue( "(OiOOOO)", py_nic_name, -1, // this will be converted later to AF_LINK py_mac_address, Py_None, // netmask (not supported) Py_None, // broadcast (not supported) Py_None // ptp (not supported on Windows) ); if (! py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_DECREF(py_mac_address); } // find out the IP address associated with the NIC if (pUnicast != NULL) { for (i = 0; pUnicast != NULL; i++) { family = pUnicast->Address.lpSockaddr->sa_family; if (family == AF_INET) { struct sockaddr_in *sa_in = (struct sockaddr_in *) pUnicast->Address.lpSockaddr; intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen); } else if (family == AF_INET6) { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) pUnicast->Address.lpSockaddr; intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr), buff, bufflen); } else { // we should never get here pUnicast = pUnicast->Next; continue; } if (intRet == NULL) { PyErr_SetFromWindowsErr(GetLastError()); goto error; } #if PY_MAJOR_VERSION >= 3 py_address = PyUnicode_FromString(buff); #else py_address = PyString_FromString(buff); #endif if (py_address == NULL) goto error; Py_INCREF(Py_None); Py_INCREF(Py_None); Py_INCREF(Py_None); py_tuple = Py_BuildValue( "(OiOOOO)", py_nic_name, family, py_address, Py_None, // netmask (not supported) Py_None, // broadcast (not supported) Py_None // ptp (not supported on Windows) ); if (! py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_DECREF(py_address); pUnicast = pUnicast->Next; } } Py_DECREF(py_nic_name); pCurrAddresses = pCurrAddresses->Next; } free(pAddresses); return py_retlist; error: if (pAddresses) free(pAddresses); Py_DECREF(py_retlist); Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_XDECREF(py_nic_name); return NULL; } /* * Provides stats about NIC interfaces installed on the system. * TODO: get 'duplex' (currently it's hard coded to '2', aka 'full duplex') */ static PyObject * psutil_net_if_stats(PyObject *self, PyObject *args) { int i; DWORD dwSize = 0; DWORD dwRetVal = 0; MIB_IFTABLE *pIfTable; MIB_IFROW *pIfRow; PIP_ADAPTER_ADDRESSES pAddresses = NULL; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; char descr[MAX_PATH]; int ifname_found; PyObject *py_nic_name = NULL; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; PyObject *py_is_up = NULL; if (py_retdict == NULL) return NULL; pAddresses = psutil_get_nic_addresses(); if (pAddresses == NULL) goto error; pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE)); if (pIfTable == NULL) { PyErr_NoMemory(); goto error; } dwSize = sizeof(MIB_IFTABLE); if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { free(pIfTable); pIfTable = (MIB_IFTABLE *) malloc(dwSize); if (pIfTable == NULL) { PyErr_NoMemory(); goto error; } } // Make a second call to GetIfTable to get the actual // data we want. if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) { PyErr_SetString(PyExc_RuntimeError, "GetIfTable() failed"); goto error; } for (i = 0; i < (int) pIfTable->dwNumEntries; i++) { pIfRow = (MIB_IFROW *) & pIfTable->table[i]; // GetIfTable is not able to give us NIC with "friendly names" // so we determine them via GetAdapterAddresses() which // provides friendly names *and* descriptions and find the // ones that match. ifname_found = 0; pCurrAddresses = pAddresses; while (pCurrAddresses) { sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description); if (lstrcmp(descr, pIfRow->bDescr) == 0) { py_nic_name = PyUnicode_FromWideChar( pCurrAddresses->FriendlyName, wcslen(pCurrAddresses->FriendlyName)); if (py_nic_name == NULL) goto error; ifname_found = 1; break; } pCurrAddresses = pCurrAddresses->Next; } if (ifname_found == 0) { // Name not found means GetAdapterAddresses() doesn't list // this NIC, only GetIfTable, meaning it's not really a NIC // interface so we skip it. continue; } // is up? if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) && pIfRow->dwAdminStatus == 1 ) { py_is_up = Py_True; } else { py_is_up = Py_False; } Py_INCREF(py_is_up); py_ifc_info = Py_BuildValue( "(Oikk)", py_is_up, 2, // there's no way to know duplex so let's assume 'full' pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb pIfRow->dwMtu ); if (!py_ifc_info) goto error; if (PyDict_SetItemString(py_retdict, py_nic_name, py_ifc_info)) goto error; Py_DECREF(py_nic_name); Py_DECREF(py_ifc_info); } free(pIfTable); free(pAddresses); return py_retdict; error: Py_XDECREF(py_is_up); Py_XDECREF(py_ifc_info); Py_XDECREF(py_nic_name); Py_DECREF(py_retdict); if (pIfTable != NULL) free(pIfTable); if (pAddresses != NULL) free(pAddresses); return NULL; } // ------------------------ Python init --------------------------- static PyMethodDef PsutilMethods[] = { // --- per-process functions {"proc_cmdline", psutil_proc_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"proc_exe", psutil_proc_exe, METH_VARARGS, "Return path of the process executable"}, {"proc_name", psutil_proc_name, METH_VARARGS, "Return process name"}, {"proc_kill", psutil_proc_kill, METH_VARARGS, "Kill the process identified by the given PID"}, {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"proc_create_time", psutil_proc_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"proc_memory_info", psutil_proc_memory_info, METH_VARARGS, "Return a tuple of process memory information"}, {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS, "Alternate implementation"}, {"proc_cwd", psutil_proc_cwd, METH_VARARGS, "Return process current working directory"}, {"proc_suspend", psutil_proc_suspend, METH_VARARGS, "Suspend a process"}, {"proc_resume", psutil_proc_resume, METH_VARARGS, "Resume a process"}, {"proc_open_files", psutil_proc_open_files, METH_VARARGS, "Return files opened by process"}, {"proc_username", psutil_proc_username, METH_VARARGS, "Return the username of a process"}, {"proc_threads", psutil_proc_threads, METH_VARARGS, "Return process threads information as a list of tuple"}, {"proc_wait", psutil_proc_wait, METH_VARARGS, "Wait for process to terminate and return its exit code."}, {"proc_priority_get", psutil_proc_priority_get, METH_VARARGS, "Return process priority."}, {"proc_priority_set", psutil_proc_priority_set, METH_VARARGS, "Set process priority."}, #if (_WIN32_WINNT >= 0x0600) // Windows Vista {"proc_io_priority_get", psutil_proc_io_priority_get, METH_VARARGS, "Return process IO priority."}, {"proc_io_priority_set", psutil_proc_io_priority_set, METH_VARARGS, "Set process IO priority."}, #endif {"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS, "Return process CPU affinity as a bitmask."}, {"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS, "Set process CPU affinity."}, {"proc_io_counters", psutil_proc_io_counters, METH_VARARGS, "Get process I/O counters."}, {"proc_is_suspended", psutil_proc_is_suspended, METH_VARARGS, "Return True if one of the process threads is in a suspended state"}, {"proc_num_handles", psutil_proc_num_handles, METH_VARARGS, "Return the number of handles opened by process."}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return a list of process's memory mappings"}, // --- alternative pinfo interface {"proc_info", psutil_proc_info, METH_VARARGS, "Various process information"}, // --- system-related functions {"pids", psutil_pids, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"ppid_map", psutil_ppid_map, METH_VARARGS, "Return a {pid:ppid, ...} dict for all running processes"}, {"pid_exists", psutil_pid_exists, METH_VARARGS, "Determine if the process exists in the current process list."}, {"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS, "Returns the number of logical CPUs on the system"}, {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Returns the number of physical CPUs on the system"}, {"boot_time", psutil_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"virtual_mem", psutil_virtual_mem, METH_VARARGS, "Return the total amount of physical memory, in bytes"}, {"cpu_times", psutil_cpu_times, METH_VARARGS, "Return system cpu times as a list"}, {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, {"disk_usage", psutil_disk_usage, METH_VARARGS, "Return path's disk total and free as a Python tuple."}, {"net_io_counters", psutil_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, "Return dict of tuples of disks I/O information."}, {"users", psutil_users, METH_VARARGS, "Return a list of currently connected users."}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS, "Return disk partitions."}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return system-wide connections"}, {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS, "Return NICs addresses."}, {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NICs stats."}, // --- windows API bindings {"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS, "QueryDosDevice binding"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) static struct module_state _state; #endif #if PY_MAJOR_VERSION >= 3 static int psutil_windows_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_windows_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_windows", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_windows_traverse, psutil_windows_clear, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__psutil_windows(void) #else #define INITERROR return void init_psutil_windows(void) #endif { struct module_state *st = NULL; #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_windows", PsutilMethods); #endif if (module == NULL) { INITERROR; } st = GETSTATE(module); st->error = PyErr_NewException("_psutil_windows.Error", NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); // process status constants // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx PyModule_AddIntConstant( module, "ABOVE_NORMAL_PRIORITY_CLASS", ABOVE_NORMAL_PRIORITY_CLASS); PyModule_AddIntConstant( module, "BELOW_NORMAL_PRIORITY_CLASS", BELOW_NORMAL_PRIORITY_CLASS); PyModule_AddIntConstant( module, "HIGH_PRIORITY_CLASS", HIGH_PRIORITY_CLASS); PyModule_AddIntConstant( module, "IDLE_PRIORITY_CLASS", IDLE_PRIORITY_CLASS); PyModule_AddIntConstant( module, "NORMAL_PRIORITY_CLASS", NORMAL_PRIORITY_CLASS); PyModule_AddIntConstant( module, "REALTIME_PRIORITY_CLASS", REALTIME_PRIORITY_CLASS); // connection status constants // http://msdn.microsoft.com/en-us/library/cc669305.aspx PyModule_AddIntConstant( module, "MIB_TCP_STATE_CLOSED", MIB_TCP_STATE_CLOSED); PyModule_AddIntConstant( module, "MIB_TCP_STATE_CLOSING", MIB_TCP_STATE_CLOSING); PyModule_AddIntConstant( module, "MIB_TCP_STATE_CLOSE_WAIT", MIB_TCP_STATE_CLOSE_WAIT); PyModule_AddIntConstant( module, "MIB_TCP_STATE_LISTEN", MIB_TCP_STATE_LISTEN); PyModule_AddIntConstant( module, "MIB_TCP_STATE_ESTAB", MIB_TCP_STATE_ESTAB); PyModule_AddIntConstant( module, "MIB_TCP_STATE_SYN_SENT", MIB_TCP_STATE_SYN_SENT); PyModule_AddIntConstant( module, "MIB_TCP_STATE_SYN_RCVD", MIB_TCP_STATE_SYN_RCVD); PyModule_AddIntConstant( module, "MIB_TCP_STATE_FIN_WAIT1", MIB_TCP_STATE_FIN_WAIT1); PyModule_AddIntConstant( module, "MIB_TCP_STATE_FIN_WAIT2", MIB_TCP_STATE_FIN_WAIT2); PyModule_AddIntConstant( module, "MIB_TCP_STATE_LAST_ACK", MIB_TCP_STATE_LAST_ACK); PyModule_AddIntConstant( module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); PyModule_AddIntConstant( module, "MIB_TCP_STATE_TIME_WAIT", MIB_TCP_STATE_TIME_WAIT); PyModule_AddIntConstant( module, "MIB_TCP_STATE_DELETE_TCB", MIB_TCP_STATE_DELETE_TCB); PyModule_AddIntConstant( module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); // ...for internal use in _psutil_windows.py PyModule_AddIntConstant( module, "INFINITE", INFINITE); PyModule_AddIntConstant( module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); // set SeDebug for the current process psutil_set_se_debug(); #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_psutil_common.h0000664000175000017500000000040112572074510021522 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 PyObject* AccessDenied(void); PyObject* NoSuchProcess(void); psutil-3.4.2/psutil/_psutil_sunos.c0000664000175000017500000012151012647703522021406 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Functions specific to Sun OS Solaris platforms. * * Thanks to Justin Venus who originally wrote a consistent part of * this in Cython which I later on translated in C. */ #include // fix for "Cannot use procfs in the large file compilation environment" // error, see: // http://sourceware.org/ml/gdb-patches/2010-11/msg00336.html #undef _FILE_OFFSET_BITS #define _STRUCTURED_PROC 1 // fix compilation issue on SunOS 5.10, see: // https://github.com/giampaolo/psutil/issues/421 #define NEW_MIB_COMPLIANT #include #include #include #include #include #include // for MNTTAB #include #include #include #include #include #include #include #include #include #include #include #include #include #include "_psutil_sunos.h" #define PSUTIL_TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec) #ifndef EXPER_IP_AND_ALL_IRES #define EXPER_IP_AND_ALL_IRES (1024+4) #endif // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; /* * Read a file content and fills a C structure with it. */ int psutil_file_to_struct(char *path, void *fstruct, size_t size) { int fd; size_t nbytes; fd = open(path, O_RDONLY); if (fd == -1) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); return 0; } nbytes = read(fd, fstruct, size); if (nbytes <= 0) { close(fd); PyErr_SetFromErrno(PyExc_OSError); return 0; } if (nbytes != size) { close(fd); PyErr_SetString(PyExc_RuntimeError, "structure size mismatch"); return 0; } close(fd); return nbytes; } /* * Return process ppid, rss, vms, ctime, nice, nthreads, status and tty * as a Python tuple. */ static PyObject * psutil_proc_basic_info(PyObject *self, PyObject *args) { int pid; char path[1000]; psinfo_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/psinfo", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("ikkdiiik", info.pr_ppid, // parent pid info.pr_rssize, // rss info.pr_size, // vms PSUTIL_TV2DOUBLE(info.pr_start), // create time info.pr_lwp.pr_nice, // nice info.pr_nlwp, // no. of threads info.pr_lwp.pr_state, // status code info.pr_ttydev // tty nr ); } /* * Return process name and args as a Python tuple. */ static PyObject * psutil_proc_name_and_args(PyObject *self, PyObject *args) { int pid; char path[1000]; psinfo_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/psinfo", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("ss", info.pr_fname, info.pr_psargs); } /* * Return process user and system CPU times as a Python tuple. */ static PyObject * psutil_proc_cpu_times(PyObject *self, PyObject *args) { int pid; char path[1000]; pstatus_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/status", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; // results are more precise than os.times() return Py_BuildValue("dd", PSUTIL_TV2DOUBLE(info.pr_utime), PSUTIL_TV2DOUBLE(info.pr_stime)); } /* * Return process uids/gids as a Python tuple. */ static PyObject * psutil_proc_cred(PyObject *self, PyObject *args) { int pid; char path[1000]; prcred_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/cred", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("iiiiii", info.pr_ruid, info.pr_euid, info.pr_suid, info.pr_rgid, info.pr_egid, info.pr_sgid); } /* * Return process uids/gids as a Python tuple. */ static PyObject * psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { int pid; char path[1000]; prusage_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/usage", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("kk", info.pr_vctx, info.pr_ictx); } /* * Process IO counters. * * Commented out and left here as a reminder. Apparently we cannot * retrieve process IO stats because: * - 'pr_ioch' is a sum of chars read and written, with no distinction * - 'pr_inblk' and 'pr_oublk', which should be the number of bytes * read and written, hardly increase and according to: * http://www.brendangregg.com/Perf/paper_diskubyp1.pdf * ...they should be meaningless anyway. * static PyObject* proc_io_counters(PyObject* self, PyObject* args) { int pid; char path[1000]; prusage_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) return NULL; sprintf(path, "%s/%i/usage", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; // On Solaris we only have 'pr_ioch' which accounts for bytes read // *and* written. // 'pr_inblk' and 'pr_oublk' should be expressed in blocks of // 8KB according to: // http://www.brendangregg.com/Perf/paper_diskubyp1.pdf (pag. 8) return Py_BuildValue("kkkk", info.pr_ioch, info.pr_ioch, info.pr_inblk, info.pr_oublk); } */ /* * Return information about a given process thread. */ static PyObject * psutil_proc_query_thread(PyObject *self, PyObject *args) { int pid, tid; char path[1000]; lwpstatus_t info; const char *procfs_path; if (! PyArg_ParseTuple(args, "iis", &pid, &tid, &procfs_path)) return NULL; sprintf(path, "%s/%i/lwp/%i/lwpstatus", procfs_path, pid, tid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("dd", PSUTIL_TV2DOUBLE(info.pr_utime), PSUTIL_TV2DOUBLE(info.pr_stime)); } /* * Return information about system virtual memory. */ static PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { // XXX (arghhh!) // total/free swap mem: commented out as for some reason I can't // manage to get the same results shown by "swap -l", despite the // code below is exactly the same as: // http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/ // cmd/swap/swap.c // We're going to parse "swap -l" output from Python (sigh!) /* struct swaptable *st; struct swapent *swapent; int i; struct stat64 statbuf; char *path; char fullpath[MAXPATHLEN+1]; int num; if ((num = swapctl(SC_GETNSWP, NULL)) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (num == 0) { PyErr_SetString(PyExc_RuntimeError, "no swap devices configured"); return NULL; } if ((st = malloc(num * sizeof(swapent_t) + sizeof (int))) == NULL) { PyErr_SetString(PyExc_RuntimeError, "malloc failed"); return NULL; } if ((path = malloc(num * MAXPATHLEN)) == NULL) { PyErr_SetString(PyExc_RuntimeError, "malloc failed"); return NULL; } swapent = st->swt_ent; for (i = 0; i < num; i++, swapent++) { swapent->ste_path = path; path += MAXPATHLEN; } st->swt_n = num; if ((num = swapctl(SC_LIST, st)) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } swapent = st->swt_ent; long t = 0, f = 0; for (i = 0; i < num; i++, swapent++) { int diskblks_per_page =(int)(sysconf(_SC_PAGESIZE) >> DEV_BSHIFT); t += (long)swapent->ste_pages; f += (long)swapent->ste_free; } free(st); return Py_BuildValue("(kk)", t, f); */ kstat_ctl_t *kc; kstat_t *k; cpu_stat_t *cpu; int cpu_count = 0; int flag = 0; uint_t sin = 0; uint_t sout = 0; kc = kstat_open(); if (kc == NULL) return PyErr_SetFromErrno(PyExc_OSError);; k = kc->kc_chain; while (k != NULL) { if ((strncmp(k->ks_name, "cpu_stat", 8) == 0) && \ (kstat_read(kc, k, NULL) != -1) ) { flag = 1; cpu = (cpu_stat_t *) k->ks_data; sin += cpu->cpu_vminfo.pgswapin; // num pages swapped in sout += cpu->cpu_vminfo.pgswapout; // num pages swapped out } cpu_count += 1; k = k->ks_next; } kstat_close(kc); if (!flag) { PyErr_SetString(PyExc_RuntimeError, "no swap device was found"); return NULL; } return Py_BuildValue("(II)", sin, sout); } /* * Return users currently connected on the system. */ static PyObject * psutil_users(PyObject *self, PyObject *args) { struct utmpx *ut; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_user_proc = NULL; if (py_retlist == NULL) return NULL; while (NULL != (ut = getutxent())) { if (ut->ut_type == USER_PROCESS) py_user_proc = Py_True; else py_user_proc = Py_False; py_tuple = Py_BuildValue( "(sssfO)", ut->ut_user, // username ut->ut_line, // tty ut->ut_host, // hostname (float)ut->ut_tv.tv_sec, // tstamp py_user_proc); // (bool) user process if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } endutent(); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (ut != NULL) endutent(); return NULL; } /* * Return disk mounted partitions as a list of tuples including device, * mount point and filesystem type. */ static PyObject * psutil_disk_partitions(PyObject *self, PyObject *args) { FILE *file; struct mnttab mt; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; file = fopen(MNTTAB, "rb"); if (file == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } while (getmntent(file, &mt) == 0) { py_tuple = Py_BuildValue( "(ssss)", mt.mnt_special, // device mt.mnt_mountp, // mount point mt.mnt_fstype, // fs type mt.mnt_mntopts); // options if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } fclose(file); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (file != NULL) fclose(file); return NULL; } /* * Return system-wide CPU times. */ static PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; PyObject *py_retlist = PyList_New(0); PyObject *py_cputime = NULL; if (py_retlist == NULL) return NULL; kc = kstat_open(); if (kc == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { if (strcmp(ksp->ks_module, "cpu_stat") == 0) { if (kstat_read(kc, ksp, &cs) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } py_cputime = Py_BuildValue("ffff", (float)cs.cpu_sysinfo.cpu[CPU_USER], (float)cs.cpu_sysinfo.cpu[CPU_KERNEL], (float)cs.cpu_sysinfo.cpu[CPU_IDLE], (float)cs.cpu_sysinfo.cpu[CPU_WAIT]); if (py_cputime == NULL) goto error; if (PyList_Append(py_retlist, py_cputime)) goto error; Py_DECREF(py_cputime); py_cputime = NULL; } } kstat_close(kc); return py_retlist; error: Py_XDECREF(py_cputime); Py_DECREF(py_retlist); if (kc != NULL) kstat_close(kc); return NULL; } /* * Return disk IO statistics. */ static PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { kstat_ctl_t *kc; kstat_t *ksp; kstat_io_t kio; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; kc = kstat_open(); if (kc == NULL) { PyErr_SetFromErrno(PyExc_OSError);; goto error; } ksp = kc->kc_chain; while (ksp != NULL) { if (ksp->ks_type == KSTAT_TYPE_IO) { if (strcmp(ksp->ks_class, "disk") == 0) { if (kstat_read(kc, ksp, &kio) == -1) { kstat_close(kc); return PyErr_SetFromErrno(PyExc_OSError);; } py_disk_info = Py_BuildValue( "(IIKKLL)", kio.reads, kio.writes, kio.nread, kio.nwritten, kio.rtime / 1000 / 1000, // from nano to milli secs kio.wtime / 1000 / 1000 // from nano to milli secs ); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } } ksp = ksp->ks_next; } kstat_close(kc); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (kc != NULL) kstat_close(kc); return NULL; } /* * Return process memory mappings. */ static PyObject * psutil_proc_memory_maps(PyObject *self, PyObject *args) { int pid; int fd = -1; char path[1000]; char perms[10]; char *name; struct stat st; pstatus_t status; prxmap_t *xmap = NULL, *p; off_t size; size_t nread; int nmap; uintptr_t pr_addr_sz; uintptr_t stk_base_sz, brk_base_sz; const char *procfs_path; PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "is", &pid, &procfs_path)) goto error; sprintf(path, "%s/%i/status", procfs_path, pid); if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) goto error; sprintf(path, "%s/%i/xmap", procfs_path, pid); if (stat(path, &st) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } size = st.st_size; fd = open(path, O_RDONLY); if (fd == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } xmap = (prxmap_t *)malloc(size); if (xmap == NULL) { PyErr_NoMemory(); goto error; } nread = pread(fd, xmap, size, 0); nmap = nread / sizeof(prxmap_t); p = xmap; while (nmap) { nmap -= 1; if (p == NULL) { p += 1; continue; } perms[0] = '\0'; pr_addr_sz = p->pr_vaddr + p->pr_size; // perms sprintf(perms, "%c%c%c%c%c%c", p->pr_mflags & MA_READ ? 'r' : '-', p->pr_mflags & MA_WRITE ? 'w' : '-', p->pr_mflags & MA_EXEC ? 'x' : '-', p->pr_mflags & MA_SHARED ? 's' : '-', p->pr_mflags & MA_NORESERVE ? 'R' : '-', p->pr_mflags & MA_RESERVED1 ? '*' : ' '); // name if (strlen(p->pr_mapname) > 0) { name = p->pr_mapname; } else { if ((p->pr_mflags & MA_ISM) || (p->pr_mflags & MA_SHM)) { name = "[shmid]"; } else { stk_base_sz = status.pr_stkbase + status.pr_stksize; brk_base_sz = status.pr_brkbase + status.pr_brksize; if ((pr_addr_sz > status.pr_stkbase) && (p->pr_vaddr < stk_base_sz)) { name = "[stack]"; } else if ((p->pr_mflags & MA_ANON) && \ (pr_addr_sz > status.pr_brkbase) && \ (p->pr_vaddr < brk_base_sz)) { name = "[heap]"; } else { name = "[anon]"; } } } py_tuple = Py_BuildValue( "iisslll", p->pr_vaddr, pr_addr_sz, perms, name, (long)p->pr_rss * p->pr_pagesize, (long)p->pr_anon * p->pr_pagesize, (long)p->pr_locked * p->pr_pagesize); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); // increment pointer p += 1; } close(fd); free(xmap); return py_retlist; error: if (fd != -1) close(fd); Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (xmap != NULL) free(xmap); return NULL; } /* * Return a list of tuples for network I/O statistics. */ static PyObject * psutil_net_io_counters(PyObject *self, PyObject *args) { kstat_ctl_t *kc = NULL; kstat_t *ksp; kstat_named_t *rbytes, *wbytes, *rpkts, *wpkts, *ierrs, *oerrs; int ret; int sock = -1; struct lifreq ifr; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; if (py_retdict == NULL) return NULL; kc = kstat_open(); if (kc == NULL) goto error; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } ksp = kc->kc_chain; while (ksp != NULL) { if (ksp->ks_type != KSTAT_TYPE_NAMED) goto next; if (strcmp(ksp->ks_class, "net") != 0) goto next; // skip 'lo' (localhost) because it doesn't have the statistics we need // and it makes kstat_data_lookup() fail if (strcmp(ksp->ks_module, "lo") == 0) goto next; // check if this is a network interface by sending a ioctl strncpy(ifr.lifr_name, ksp->ks_name, sizeof(ifr.lifr_name)); ret = ioctl(sock, SIOCGLIFFLAGS, &ifr); if (ret == -1) goto next; if (kstat_read(kc, ksp, NULL) == -1) { errno = 0; goto next; } rbytes = (kstat_named_t *)kstat_data_lookup(ksp, "rbytes"); wbytes = (kstat_named_t *)kstat_data_lookup(ksp, "obytes"); rpkts = (kstat_named_t *)kstat_data_lookup(ksp, "ipackets"); wpkts = (kstat_named_t *)kstat_data_lookup(ksp, "opackets"); ierrs = (kstat_named_t *)kstat_data_lookup(ksp, "ierrors"); oerrs = (kstat_named_t *)kstat_data_lookup(ksp, "oerrors"); if ((rbytes == NULL) || (wbytes == NULL) || (rpkts == NULL) || (wpkts == NULL) || (ierrs == NULL) || (oerrs == NULL)) { PyErr_SetString(PyExc_RuntimeError, "kstat_data_lookup() failed"); goto error; } if (rbytes->data_type == KSTAT_DATA_UINT64) { py_ifc_info = Py_BuildValue("(KKKKIIii)", wbytes->value.ui64, rbytes->value.ui64, wpkts->value.ui64, rpkts->value.ui64, ierrs->value.ui32, oerrs->value.ui32, 0, // dropin not supported 0 // dropout not supported ); } else { py_ifc_info = Py_BuildValue("(IIIIIIii)", wbytes->value.ui32, rbytes->value.ui32, wpkts->value.ui32, rpkts->value.ui32, ierrs->value.ui32, oerrs->value.ui32, 0, // dropin not supported 0 // dropout not supported ); } if (!py_ifc_info) goto error; if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) goto error; Py_DECREF(py_ifc_info); goto next; next: ksp = ksp->ks_next; } kstat_close(kc); close(sock); return py_retdict; error: Py_XDECREF(py_ifc_info); Py_DECREF(py_retdict); if (kc != NULL) kstat_close(kc); if (sock != -1) { close(sock); } return NULL; } /* * Return TCP and UDP connections opened by process. * UNIX sockets are excluded. * * Thanks to: * https://github.com/DavidGriffith/finx/blob/master/ * nxsensor-3.5.0-1/src/sysdeps/solaris.c * ...and: * https://hg.java.net/hg/solaris~on-src/file/tip/usr/src/cmd/ * cmd-inet/usr.bin/netstat/netstat.c */ static PyObject * psutil_net_connections(PyObject *self, PyObject *args) { long pid; int sd = 0; mib2_tcpConnEntry_t *tp = NULL; mib2_udpEntry_t *ude; #if defined(AF_INET6) mib2_tcp6ConnEntry_t *tp6; mib2_udp6Entry_t *ude6; #endif char buf[512]; int i, flags, getcode, num_ent, state; char lip[200], rip[200]; int lport, rport; int processed_pid; int databuf_init = 0; struct strbuf ctlbuf, databuf; struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; struct T_error_ack *tea = (struct T_error_ack *)buf; struct opthdr *mibhdr; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; sd = open("/dev/arp", O_RDWR); if (sd == -1) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/dev/arp"); goto error; } /* XXX - These 2 are used in ifconfig.c but they seem unnecessary ret = ioctl(sd, I_PUSH, "tcp"); if (ret == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } ret = ioctl(sd, I_PUSH, "udp"); if (ret == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } */ // OK, this mess is basically copied and pasted from nxsensor project // which copied and pasted it from netstat source code, mibget() // function. Also see: // http://stackoverflow.com/questions/8723598/ tor->PRIM_type = T_SVR4_OPTMGMT_REQ; tor->OPT_offset = sizeof (struct T_optmgmt_req); tor->OPT_length = sizeof (struct opthdr); tor->MGMT_flags = T_CURRENT; mibhdr = (struct opthdr *)&tor[1]; mibhdr->level = EXPER_IP_AND_ALL_IRES; mibhdr->name = 0; mibhdr->len = 0; ctlbuf.buf = buf; ctlbuf.len = tor->OPT_offset + tor->OPT_length; flags = 0; // request to be sent in non-priority if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } mibhdr = (struct opthdr *)&toa[1]; ctlbuf.maxlen = sizeof (buf); for (;;) { flags = 0; getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags); if (getcode != MOREDATA || ctlbuf.len < sizeof (struct T_optmgmt_ack) || toa->PRIM_type != T_OPTMGMT_ACK || toa->MGMT_flags != T_SUCCESS) { break; } if (ctlbuf.len >= sizeof (struct T_error_ack) && tea->PRIM_type == T_ERROR_ACK) { PyErr_SetString(PyExc_RuntimeError, "ERROR_ACK"); goto error; } if (getcode == 0 && ctlbuf.len >= sizeof (struct T_optmgmt_ack) && toa->PRIM_type == T_OPTMGMT_ACK && toa->MGMT_flags == T_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "ERROR_T_OPTMGMT_ACK"); goto error; } databuf.maxlen = mibhdr->len; databuf.len = 0; databuf.buf = (char *)malloc((int)mibhdr->len); if (!databuf.buf) { PyErr_NoMemory(); goto error; } databuf_init = 1; flags = 0; getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags); if (getcode < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } // TCPv4 if (mibhdr->level == MIB2_TCP && mibhdr->name == MIB2_TCP_13) { tp = (mib2_tcpConnEntry_t *)databuf.buf; num_ent = mibhdr->len / sizeof(mib2_tcpConnEntry_t); for (i = 0; i < num_ent; i++, tp++) { processed_pid = tp->tcpConnCreationProcess; if (pid != -1 && processed_pid != pid) continue; // construct local/remote addresses inet_ntop(AF_INET, &tp->tcpConnLocalAddress, lip, sizeof(lip)); inet_ntop(AF_INET, &tp->tcpConnRemAddress, rip, sizeof(rip)); lport = tp->tcpConnLocalPort; rport = tp->tcpConnRemPort; // contruct python tuple/list py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); else { py_raddr = Py_BuildValue("()"); } if (!py_raddr) goto error; state = tp->tcpConnEntryInfo.ce_state; // add item py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM, py_laddr, py_raddr, state, processed_pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #if defined(AF_INET6) // TCPv6 else if (mibhdr->level == MIB2_TCP6 && mibhdr->name == MIB2_TCP6_CONN) { tp6 = (mib2_tcp6ConnEntry_t *)databuf.buf; num_ent = mibhdr->len / sizeof(mib2_tcp6ConnEntry_t); for (i = 0; i < num_ent; i++, tp6++) { processed_pid = tp6->tcp6ConnCreationProcess; if (pid != -1 && processed_pid != pid) continue; // construct local/remote addresses inet_ntop(AF_INET6, &tp6->tcp6ConnLocalAddress, lip, sizeof(lip)); inet_ntop(AF_INET6, &tp6->tcp6ConnRemAddress, rip, sizeof(rip)); lport = tp6->tcp6ConnLocalPort; rport = tp6->tcp6ConnRemPort; // contruct python tuple/list py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; state = tp6->tcp6ConnEntryInfo.ce_state; // add item py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM, py_laddr, py_raddr, state, processed_pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #endif // UDPv4 else if (mibhdr->level == MIB2_UDP || mibhdr->level == MIB2_UDP_ENTRY) { ude = (mib2_udpEntry_t *)databuf.buf; num_ent = mibhdr->len / sizeof(mib2_udpEntry_t); for (i = 0; i < num_ent; i++, ude++) { processed_pid = ude->udpCreationProcess; if (pid != -1 && processed_pid != pid) continue; // XXX Very ugly hack! It seems we get here only the first // time we bump into a UDPv4 socket. PID is a very high // number (clearly impossible) and the address does not // belong to any valid interface. Not sure what else // to do other than skipping. if (processed_pid > 131072) continue; inet_ntop(AF_INET, &ude->udpLocalAddress, lip, sizeof(lip)); lport = ude->udpLocalPort; py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE, processed_pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #if defined(AF_INET6) // UDPv6 else if (mibhdr->level == MIB2_UDP6 || mibhdr->level == MIB2_UDP6_ENTRY) { ude6 = (mib2_udp6Entry_t *)databuf.buf; num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t); for (i = 0; i < num_ent; i++, ude6++) { processed_pid = ude6->udp6CreationProcess; if (pid != -1 && processed_pid != pid) continue; inet_ntop(AF_INET6, &ude6->udp6LocalAddress, lip, sizeof(lip)); lport = ude6->udp6LocalPort; py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE, processed_pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #endif free(databuf.buf); } close(sd); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); Py_DECREF(py_retlist); if (databuf_init == 1) free(databuf.buf); if (sd != 0) close(sd); return NULL; } static PyObject * psutil_boot_time(PyObject *self, PyObject *args) { float boot_time = 0.0; struct utmpx *ut; while (NULL != (ut = getutxent())) { if (ut->ut_type == BOOT_TIME) { boot_time = (float)ut->ut_tv.tv_sec; break; } } endutent(); if (boot_time != 0.0) { return Py_BuildValue("f", boot_time); } else { PyErr_SetString(PyExc_RuntimeError, "can't determine boot time"); return NULL; } } /* * Return the number of physical CPU cores on the system. */ static PyObject * psutil_cpu_count_phys(PyObject *self, PyObject *args) { kstat_ctl_t *kc; kstat_t *ksp; int ncpus = 0; kc = kstat_open(); if (kc == NULL) goto error; ksp = kstat_lookup(kc, "cpu_info", -1, NULL); if (ksp == NULL) goto error; for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_module, "cpu_info") != 0) continue; if (kstat_read(kc, ksp, NULL) == -1) goto error; ncpus += 1; } kstat_close(kc); if (ncpus > 0) return Py_BuildValue("i", ncpus); else goto error; error: // mimic os.cpu_count() if (kc != NULL) kstat_close(kc); Py_RETURN_NONE; } /* * Return stats about a particular network * interface. References: * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py * http://www.i-scream.org/libstatgrab/ */ static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args) { kstat_ctl_t *kc = NULL; kstat_t *ksp; kstat_named_t *knp; int ret; int sock = -1; int duplex; int speed; PyObject *py_retdict = PyDict_New(); PyObject *py_ifc_info = NULL; PyObject *py_is_up = NULL; if (py_retdict == NULL) return NULL; kc = kstat_open(); if (kc == NULL) goto error; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { if (strcmp(ksp->ks_class, "net") == 0) { struct lifreq ifr; kstat_read(kc, ksp, NULL); if (ksp->ks_type != KSTAT_TYPE_NAMED) continue; if (strcmp(ksp->ks_class, "net") != 0) continue; strncpy(ifr.lifr_name, ksp->ks_name, sizeof(ifr.lifr_name)); ret = ioctl(sock, SIOCGLIFFLAGS, &ifr); if (ret == -1) continue; // not a network interface // is up? if ((ifr.lifr_flags & IFF_UP) != 0) { if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) { if (knp->value.ui32 != 0u) py_is_up = Py_True; else py_is_up = Py_False; } else { py_is_up = Py_True; } } else { py_is_up = Py_False; } Py_INCREF(py_is_up); // duplex duplex = 0; // unknown if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) { if (knp->value.ui32 == 1) duplex = 1; // half else if (knp->value.ui32 == 2) duplex = 2; // full } // speed if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) // expressed in bits per sec, we want mega bits per sec speed = (int)knp->value.ui64 / 1000000; else speed = 0; // mtu ret = ioctl(sock, SIOCGLIFMTU, &ifr); if (ret == -1) goto error; py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed, ifr.lifr_mtu); if (!py_ifc_info) goto error; if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info)) goto error; Py_DECREF(py_ifc_info); } } close(sock); kstat_close(kc); return py_retdict; error: Py_XDECREF(py_is_up); Py_XDECREF(py_ifc_info); Py_DECREF(py_retdict); if (sock != -1) close(sock); if (kc != NULL) kstat_close(kc); PyErr_SetFromErrno(PyExc_OSError); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- process-related functions {"proc_basic_info", psutil_proc_basic_info, METH_VARARGS, "Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"}, {"proc_name_and_args", psutil_proc_name_and_args, METH_VARARGS, "Return process name and args."}, {"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS, "Return process user and system CPU times."}, {"proc_cred", psutil_proc_cred, METH_VARARGS, "Return process uids/gids."}, {"query_process_thread", psutil_proc_query_thread, METH_VARARGS, "Return info about a process thread"}, {"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS, "Return process memory mappings"}, {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, // --- system-related functions {"swap_mem", psutil_swap_mem, METH_VARARGS, "Return information about system swap memory."}, {"users", psutil_users, METH_VARARGS, "Return currently connected users."}, {"disk_partitions", psutil_disk_partitions, METH_VARARGS, "Return disk partitions."}, {"per_cpu_times", psutil_per_cpu_times, METH_VARARGS, "Return system per-CPU times."}, {"disk_io_counters", psutil_disk_io_counters, METH_VARARGS, "Return a Python dict of tuples for disk I/O statistics."}, {"net_io_counters", psutil_net_io_counters, METH_VARARGS, "Return a Python dict of tuples for network I/O statistics."}, {"boot_time", psutil_boot_time, METH_VARARGS, "Return system boot time in seconds since the EPOCH."}, {"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS, "Return the number of physical CPUs on the system."}, {"net_connections", psutil_net_connections, METH_VARARGS, "Return TCP and UDP syste-wide open connections."}, {"net_if_stats", psutil_net_if_stats, METH_VARARGS, "Return NIC stats (isup, duplex, speed, mtu)"}, {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_sunos_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_sunos_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_sunos", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_sunos_traverse, psutil_sunos_clear, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit__psutil_sunos(void) #else #define INITERROR return void init_psutil_sunos(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_sunos", PsutilMethods); #endif PyModule_AddIntConstant(module, "version", PSUTIL_VERSION); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SZOMB", SZOMB); PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SONPROC", SONPROC); PyModule_AddIntConstant(module, "SWAIT", SWAIT); PyModule_AddIntConstant(module, "PRNODEV", PRNODEV); // for process tty PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED); PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING); PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT); PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN); PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED); PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT); PyModule_AddIntConstant(module, "TCPS_SYN_RCVD", TCPS_SYN_RCVD); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1); PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2); PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK); PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT); // sunos specific PyModule_AddIntConstant(module, "TCPS_IDLE", TCPS_IDLE); // sunos specific PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND); PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); if (module == NULL) INITERROR; #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-3.4.2/psutil/_psbsd.py0000664000175000017500000005415512646160647020176 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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, OpenBSD and NetBSD platforms implementation.""" import contextlib import errno import functools import os import sys import xml.etree.ElementTree as ET from collections import namedtuple from . import _common from . import _psposix from . import _psutil_bsd as cext from . import _psutil_posix as cext_posix from ._common import conn_tmap from ._common import sockfam_to_enum from ._common import socktype_to_enum from ._common import usage_percent from ._compat import which __extra__all__ = [] # --- constants FREEBSD = sys.platform.startswith("freebsd") OPENBSD = sys.platform.startswith("openbsd") NETBSD = sys.platform.startswith("netbsd") if FREEBSD: PROC_STATUSES = { cext.SIDL: _common.STATUS_IDLE, cext.SRUN: _common.STATUS_RUNNING, cext.SSLEEP: _common.STATUS_SLEEPING, cext.SSTOP: _common.STATUS_STOPPED, cext.SZOMB: _common.STATUS_ZOMBIE, cext.SWAIT: _common.STATUS_WAITING, cext.SLOCK: _common.STATUS_LOCKED, } elif OPENBSD or NETBSD: PROC_STATUSES = { cext.SIDL: _common.STATUS_IDLE, cext.SSLEEP: _common.STATUS_SLEEPING, cext.SSTOP: _common.STATUS_STOPPED, # According to /usr/include/sys/proc.h SZOMB is unused. # test_zombie_process() shows that SDEAD is the right # equivalent. Also it appears there's no equivalent of # psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE. # cext.SZOMB: _common.STATUS_ZOMBIE, cext.SDEAD: _common.STATUS_ZOMBIE, cext.SZOMB: _common.STATUS_ZOMBIE, # From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt # OpenBSD has SRUN and SONPROC: SRUN indicates that a process # is runnable but *not* yet running, i.e. is on a run queue. # SONPROC indicates that the process is actually executing on # a CPU, i.e. it is no longer on a run queue. # As such we'll map SRUN to STATUS_WAKING and SONPROC to # STATUS_RUNNING cext.SRUN: _common.STATUS_WAKING, cext.SONPROC: _common.STATUS_RUNNING, } elif NETBSD: PROC_STATUSES = { cext.SIDL: _common.STATUS_IDLE, cext.SACTIVE: _common.STATUS_RUNNING, cext.SDYING: _common.STATUS_ZOMBIE, cext.SSTOP: _common.STATUS_STOPPED, cext.SZOMB: _common.STATUS_ZOMBIE, cext.SDEAD: _common.STATUS_DEAD, cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD } TCP_STATUSES = { cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED, cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT, cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV, cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1, cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2, cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT, cext.TCPS_CLOSED: _common.CONN_CLOSE, cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK, cext.TCPS_LISTEN: _common.CONN_LISTEN, cext.TCPS_CLOSING: _common.CONN_CLOSING, cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } if NETBSD: PAGESIZE = os.sysconf("SC_PAGESIZE") else: PAGESIZE = os.sysconf("SC_PAGE_SIZE") AF_LINK = cext_posix.AF_LINK # extend base mem ntuple with BSD-specific memory metrics svmem = namedtuple( 'svmem', ['total', 'available', 'percent', 'used', 'free', 'active', 'inactive', 'buffers', 'cached', 'shared', 'wired']) scputimes = namedtuple( 'scputimes', ['user', 'nice', 'system', 'idle', 'irq']) pextmem = namedtuple('pextmem', ['rss', 'vms', 'text', 'data', 'stack']) pmmap_grouped = namedtuple( 'pmmap_grouped', 'path rss, private, ref_count, shadow_count') pmmap_ext = namedtuple( 'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count') # set later from __init__.py NoSuchProcess = None ZombieProcess = None AccessDenied = None TimeoutExpired = None def virtual_memory(): """System virtual memory as a namedtuple.""" mem = cext.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 svmem(total, avail, percent, used, free, active, inactive, buffers, cached, shared, wired) def swap_memory(): """System swap memory as (total, used, free, sin, sout) namedtuple.""" pagesize = 1 if OPENBSD else PAGESIZE total, used, free, sin, sout = [x * pagesize for x in cext.swap_mem()] percent = usage_percent(used, total, _round=1) return _common.sswap(total, used, free, percent, sin, sout) def cpu_times(): """Return system per-CPU times as a namedtuple""" user, nice, system, idle, irq = cext.cpu_times() return scputimes(user, nice, system, idle, irq) if hasattr(cext, "per_cpu_times"): def per_cpu_times(): """Return system CPU times as a namedtuple""" ret = [] for cpu_t in cext.per_cpu_times(): user, nice, system, idle, irq = cpu_t item = scputimes(user, nice, system, idle, irq) ret.append(item) return ret else: # XXX # Ok, this is very dirty. # On FreeBSD < 8 we cannot gather per-cpu information, see: # https://github.com/giampaolo/psutil/issues/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 def per_cpu_times(): if cpu_count_logical() == 1: return [cpu_times()] if per_cpu_times.__called__: raise NotImplementedError("supported only starting from FreeBSD 8") per_cpu_times.__called__ = True return [cpu_times()] per_cpu_times.__called__ = False def cpu_count_logical(): """Return the number of logical CPUs in the system.""" return cext.cpu_count_logical() if OPENBSD or NETBSD: def cpu_count_physical(): # OpenBSD and NetBSD do not implement this. return 1 if cpu_count_logical() == 1 else None else: def cpu_count_physical(): """Return the number of physical CPUs in the system.""" # From the C module we'll get an XML string similar to this: # http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html # We may get None in case "sysctl kern.sched.topology_spec" # is not supported on this BSD version, in which case we'll mimic # os.cpu_count() and return None. ret = None s = cext.cpu_count_phys() if s is not None: # get rid of padding chars appended at the end of the string index = s.rfind("") if index != -1: s = s[:index + 9] root = ET.fromstring(s) try: ret = len(root.findall('group/children/group/cpu')) or None finally: # needed otherwise it will memleak root.clear() if not ret: # If logical CPUs are 1 it's obvious we'll have only 1 # physical CPU. if cpu_count_logical() == 1: return 1 return ret def boot_time(): """The system boot time expressed in seconds since the epoch.""" return cext.boot_time() def disk_partitions(all=False): retlist = [] partitions = cext.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 = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def users(): retlist = [] rawlist = cext.users() for item in rawlist: user, tty, hostname, tstamp = item if tty == '~': continue # reboot or shutdown nt = _common.suser(user, tty or None, hostname, tstamp) retlist.append(nt) return retlist def net_connections(kind): if OPENBSD: ret = [] for pid in pids(): try: cons = Process(pid).connections(kind) except (NoSuchProcess, ZombieProcess): continue else: for conn in cons: conn = list(conn) conn.append(pid) ret.append(_common.sconn(*conn)) return ret if kind not in _common.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 = set() rawlist = cext.net_connections() for item in rawlist: fd, fam, type, laddr, raddr, status, pid = item # TODO: apply filter at C level if fam in families and type in types: try: status = TCP_STATUSES[status] except KeyError: # XXX: Not sure why this happens. I saw this occurring # with IPv6 sockets opened by 'vim'. Those sockets # have a very short lifetime so maybe the kernel # can't initialize their status? status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] fam = sockfam_to_enum(fam) type = socktype_to_enum(type) nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) ret.add(nt) return list(ret) def net_if_stats(): """Get NIC stats (isup, duplex, speed, mtu).""" names = net_io_counters().keys() ret = {} for name in names: isup, duplex, speed, mtu = cext_posix.net_if_stats(name) if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret if OPENBSD or NETBSD: def pid_exists(pid): exists = _psposix.pid_exists(pid) if not exists: # We do this because _psposix.pid_exists() lies in case of # zombie processes. return pid in pids() else: return True else: pid_exists = _psposix.pid_exists pids = cext.pids disk_usage = _psposix.disk_usage net_io_counters = cext.net_io_counters disk_io_counters = cext.disk_io_counters net_if_addrs = cext_posix.net_if_addrs def wrap_exceptions(fun): """Decorator which translates bare OSError exceptions into NoSuchProcess and AccessDenied. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError as err: # support for private module import if (NoSuchProcess is None or AccessDenied is None or ZombieProcess is None): raise if err.errno == errno.ESRCH: if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise return wrapper @contextlib.contextmanager def wrap_exceptions_procfs(inst): try: yield except EnvironmentError as err: # support for private module import if NoSuchProcess is None or AccessDenied is None: raise # 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. if err.errno in (errno.ENOENT, errno.ESRCH): if not pid_exists(inst.pid): raise NoSuchProcess(inst.pid, inst._name) else: raise ZombieProcess(inst.pid, inst._name, inst._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(inst.pid, inst._name) raise class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None self._ppid = None @wrap_exceptions def name(self): return cext.proc_name(self.pid) @wrap_exceptions def exe(self): if FREEBSD: return cext.proc_exe(self.pid) elif NETBSD: if self.pid == 0: # /proc/0 dir exists but /proc/0/exe doesn't return "" with wrap_exceptions_procfs(self): return os.readlink("/proc/%s/exe" % self.pid) else: # OpenBSD: exe cannot be determined; references: # https://chromium.googlesource.com/chromium/src/base/+/ # master/base_paths_posix.cc # We try our best guess by using which against the first # cmdline arg (may return None). cmdline = self.cmdline() if cmdline: return which(cmdline[0]) else: return "" @wrap_exceptions def cmdline(self): if OPENBSD and self.pid == 0: return None # ...else it crashes elif NETBSD: # XXX - most of the times the underlying sysctl() call on Net # and Open BSD returns a truncated string. # Also /proc/pid/cmdline behaves the same so it looks # like this is a kernel bug. try: return cext.proc_cmdline(self.pid) except OSError as err: if err.errno == errno.EINVAL: if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) else: raise else: return cext.proc_cmdline(self.pid) @wrap_exceptions def terminal(self): tty_nr = cext.proc_tty_nr(self.pid) tmap = _psposix._get_terminal_map() try: return tmap[tty_nr] except KeyError: return None @wrap_exceptions def ppid(self): return cext.proc_ppid(self.pid) @wrap_exceptions def uids(self): real, effective, saved = cext.proc_uids(self.pid) return _common.puids(real, effective, saved) @wrap_exceptions def gids(self): real, effective, saved = cext.proc_gids(self.pid) return _common.pgids(real, effective, saved) @wrap_exceptions def cpu_times(self): user, system = cext.proc_cpu_times(self.pid) return _common.pcputimes(user, system) @wrap_exceptions def memory_info(self): rss, vms = cext.proc_memory_info(self.pid)[:2] return _common.pmem(rss, vms) @wrap_exceptions def memory_info_ex(self): return pextmem(*cext.proc_memory_info(self.pid)) @wrap_exceptions def create_time(self): return cext.proc_create_time(self.pid) @wrap_exceptions def num_threads(self): if hasattr(cext, "proc_num_threads"): # FreeBSD return cext.proc_num_threads(self.pid) else: return len(self.threads()) @wrap_exceptions def num_ctx_switches(self): return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid)) @wrap_exceptions def threads(self): # Note: on OpenSBD this (/dev/mem) requires root access. rawlist = cext.proc_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = _common.pthread(thread_id, utime, stime) retlist.append(ntuple) if OPENBSD: # On OpenBSD the underlying C function does not raise NSP # in case the process is gone (and the returned list may # incomplete). self.name() # raise NSP if the process disappeared on us return retlist @wrap_exceptions def 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]))) if NETBSD: families, types = conn_tmap[kind] ret = set() rawlist = cext.proc_connections(self.pid) for item in rawlist: fd, fam, type, laddr, raddr, status = item if fam in families and type in types: try: status = TCP_STATUSES[status] except KeyError: status = TCP_STATUSES[cext.PSUTIL_CONN_NONE] fam = sockfam_to_enum(fam) type = socktype_to_enum(type) nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.add(nt) # On NetBSD the underlying C function does not raise NSP # in case the process is gone (and the returned list may # incomplete). self.name() # raise NSP if the process disappeared on us return list(ret) families, types = conn_tmap[kind] rawlist = cext.proc_connections(self.pid, families, types) ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item fam = sockfam_to_enum(fam) type = socktype_to_enum(type) status = TCP_STATUSES[status] nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.append(nt) if OPENBSD: # On OpenBSD the underlying C function does not raise NSP # in case the process is gone (and the returned list may # incomplete). self.name() # raise NSP if the process disappeared on us return ret @wrap_exceptions def wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except _psposix.TimeoutExpired: # support for private module import if TimeoutExpired is None: raise raise TimeoutExpired(timeout, self.pid, self._name) @wrap_exceptions def nice_get(self): return cext_posix.getpriority(self.pid) @wrap_exceptions def nice_set(self, value): return cext_posix.setpriority(self.pid, value) @wrap_exceptions def status(self): code = cext.proc_status(self.pid) # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(code, '?') @wrap_exceptions def io_counters(self): rc, wc, rb, wb = cext.proc_io_counters(self.pid) return _common.pio(rc, wc, rb, wb) @wrap_exceptions def cwd(self): """Return process current working directory.""" # sometimes we get an empty string, in which case we turn # it into None if OPENBSD and self.pid == 0: return None # ...else it would raise EINVAL elif NETBSD: with wrap_exceptions_procfs(self): return os.readlink("/proc/%s/cwd" % self.pid) elif hasattr(cext, 'proc_open_files'): # FreeBSD < 8 does not support functions based on # kinfo_getfile() and kinfo_getvmmap() return cext.proc_cwd(self.pid) or None else: raise NotImplementedError( "supported only starting from FreeBSD 8" if FREEBSD else "") 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') def _not_implemented(self): raise NotImplementedError # FreeBSD < 8 does not support functions based on kinfo_getfile() # and kinfo_getvmmap() if hasattr(cext, 'proc_open_files'): @wrap_exceptions def open_files(self): """Return files opened by process as a list of namedtuples.""" rawlist = cext.proc_open_files(self.pid) return [_common.popenfile(path, fd) for path, fd in rawlist] else: open_files = _not_implemented # FreeBSD < 8 does not support functions based on kinfo_getfile() # and kinfo_getvmmap() if hasattr(cext, 'proc_num_fds'): @wrap_exceptions def num_fds(self): """Return the number of file descriptors opened by this process.""" ret = cext.proc_num_fds(self.pid) if NETBSD: # On NetBSD the underlying C function does not raise NSP # in case the process is gone. self.name() # raise NSP if the process disappeared on us return ret else: num_fds = _not_implemented # --- FreeBSD only APIs if FREEBSD: @wrap_exceptions def cpu_affinity_get(self): return cext.proc_cpu_affinity_get(self.pid) @wrap_exceptions def cpu_affinity_set(self, cpus): # Pre-emptively check if CPUs are valid because the C # function has a weird behavior in case of invalid CPUs, # see: https://github.com/giampaolo/psutil/issues/586 allcpus = tuple(range(len(per_cpu_times()))) for cpu in cpus: if cpu not in allcpus: raise ValueError("invalid CPU #%i (choose between %s)" % (cpu, allcpus)) try: cext.proc_cpu_affinity_set(self.pid, cpus) except OSError as err: # 'man cpuset_setaffinity' about EDEADLK: # <> if err.errno in (errno.EINVAL, errno.EDEADLK): for cpu in cpus: if cpu not in allcpus: raise ValueError( "invalid CPU #%i (choose between %s)" % ( cpu, allcpus)) raise @wrap_exceptions def memory_maps(self): return cext.proc_memory_maps(self.pid) psutil-3.4.2/psutil/_psutil_linux.h0000664000175000017500000000144112572074510021376 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 // process static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args); static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args); // system static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_linux_sysinfo(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); psutil-3.4.2/psutil/arch/0000775000175000017500000000000012647732502017251 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/osx/0000775000175000017500000000000012647732502020062 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/osx/process_info.h0000664000175000017500000000104112572074510022713 0ustar giampaologiampaolo00000000000000/* * 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 typedef struct kinfo_proc kinfo_proc; int psutil_get_argmax(void); int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp); int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); int psutil_pid_exists(long pid); int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size); PyObject* psutil_get_cmdline(long pid); psutil-3.4.2/psutil/arch/osx/process_info.c0000664000175000017500000001621612625154726022727 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Helper functions related to fetching process information. * Used by _psutil_osx module methods. */ #include #include #include #include // for INT_MAX #include #include #include #include #include #include #include "process_info.h" #include "../../_psutil_common.h" /* * Return 1 if PID exists in the current process list, else 0, -1 * on error. * TODO: this should live in _psutil_posix.c but for some reason if I * move it there I get a "include undefined symbol" error. */ int psutil_pid_exists(long pid) { int ret; if (pid < 0) return 0; ret = kill(pid , 0); if (ret == 0) return 1; else { return 0; /* // This is how it is handled on other POSIX systems but it causes // test_halfway_terminated test to fail with AccessDenied. if (ret == ESRCH) return 0; else if (ret == EPERM) return 1; else { PyErr_SetFromErrno(PyExc_OSError); return -1; } */ } } /* * Returns a list of all BSD processes on the system. This routine * allocates the list and puts it in *procList and a count of the * number of entries in *procCount. You are responsible for freeing * this list (use "free" from System framework). * On success, the function returns 0. * On error, the function returns a BSD errno value. */ int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { // Declaring mib as const requires use of a cast since the // sysctl prototype doesn't include the const modifier. static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; size_t size, size2; void *ptr; int err, lim = 8; // some limit assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); *procCount = 0; /* * We start by calling sysctl with ptr == NULL and size == 0. * That will succeed, and set size to the appropriate length. * We then allocate a buffer of at least that size and call * sysctl with that buffer. If that succeeds, we're done. * If that call fails with ENOMEM, we throw the buffer away * and try again. * Note that the loop calls sysctl with NULL again. This is * is necessary because the ENOMEM failure case sets size to * the amount of data returned, not the amount of data that * could have been returned. */ while (lim-- > 0) { size = 0; if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) return errno; size2 = size + (size >> 3); // add some if (size2 > size) { ptr = malloc(size2); if (ptr == NULL) ptr = malloc(size); else size = size2; } else { ptr = malloc(size); } if (ptr == NULL) return ENOMEM; if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) { err = errno; free(ptr); if (err != ENOMEM) return err; } else { *procList = (kinfo_proc *)ptr; *procCount = size / sizeof(kinfo_proc); return 0; } } return ENOMEM; } // Read the maximum argument size for processes int psutil_get_argmax() { int argmax; int mib[] = { CTL_KERN, KERN_ARGMAX }; size_t size = sizeof(argmax); if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) return argmax; return 0; } // return process args as a python list PyObject * psutil_get_cmdline(long pid) { int mib[3]; int nargs; int len; char *procargs = NULL; char *arg_ptr; char *arg_end; char *curr_arg; size_t argmax; PyObject *py_arg = NULL; PyObject *py_retlist = NULL; // special case for PID 0 (kernel_task) where cmdline cannot be fetched if (pid == 0) return Py_BuildValue("[]"); // read argmax and allocate memory for argument space. argmax = psutil_get_argmax(); if (! argmax) { PyErr_SetFromErrno(PyExc_OSError); goto error; } procargs = (char *)malloc(argmax); if (NULL == procargs) { PyErr_SetFromErrno(PyExc_OSError); goto error; } // read argument space mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = pid; if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) { if (EINVAL == errno) { // EINVAL == access denied OR nonexistent PID if (psutil_pid_exists(pid)) AccessDenied(); else NoSuchProcess(); } goto error; } arg_end = &procargs[argmax]; // copy the number of arguments to nargs memcpy(&nargs, procargs, sizeof(nargs)); arg_ptr = procargs + sizeof(nargs); len = strlen(arg_ptr); arg_ptr += len + 1; if (arg_ptr == arg_end) { free(procargs); return Py_BuildValue("[]"); } // skip ahead to the first argument for (; arg_ptr < arg_end; arg_ptr++) { if (*arg_ptr != '\0') break; } // iterate through arguments curr_arg = arg_ptr; py_retlist = Py_BuildValue("[]"); if (!py_retlist) goto error; while (arg_ptr < arg_end && nargs > 0) { if (*arg_ptr++ == '\0') { py_arg = Py_BuildValue("s", curr_arg); if (!py_arg) goto error; if (PyList_Append(py_retlist, py_arg)) goto error; Py_DECREF(py_arg); // iterate to next arg and decrement # of args curr_arg = arg_ptr; nargs--; } } free(procargs); return py_retlist; error: Py_XDECREF(py_arg); Py_XDECREF(py_retlist); if (procargs != NULL) free(procargs); return NULL; } int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) { int mib[4]; size_t len; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; // fetch the info with sysctl() len = sizeof(struct kinfo_proc); // now read the data from sysctl if (sysctl(mib, 4, kp, &len, NULL, 0) == -1) { // raise an exception and throw errno as the error PyErr_SetFromErrno(PyExc_OSError); return -1; } // sysctl succeeds but len is zero, happens when process has gone away if (len == 0) { NoSuchProcess(); return -1; } return 0; } /* * A thin wrapper around proc_pidinfo() */ int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size) { int ret = proc_pidinfo((int)pid, flavor, 0, pti, size); if (ret == 0) { if (! psutil_pid_exists(pid)) { NoSuchProcess(); return 0; } else { AccessDenied(); return 0; } } else if (ret != size) { AccessDenied(); return 0; } else { return 1; } } psutil-3.4.2/psutil/arch/windows/0000775000175000017500000000000012647732502020743 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/windows/ntextapi.h0000664000175000017500000001426712604252103022745 0ustar giampaologiampaolo00000000000000/* * 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. */ #if !defined(__NTEXTAPI_H__) #define __NTEXTAPI_H__ #include typedef enum _KTHREAD_STATE { Initialized, Ready, Running, Standby, Terminated, Waiting, Transition, DeferredReady, GateWait, MaximumThreadState } KTHREAD_STATE, *PKTHREAD_STATE; typedef enum _KWAIT_REASON { Executive = 0, FreePage = 1, PageIn = 2, PoolAllocation = 3, DelayExecution = 4, Suspended = 5, UserRequest = 6, WrExecutive = 7, WrFreePage = 8, WrPageIn = 9, WrPoolAllocation = 10, WrDelayExecution = 11, WrSuspended = 12, WrUserRequest = 13, WrEventPair = 14, WrQueue = 15, WrLpcReceive = 16, WrLpcReply = 17, WrVirtualMemory = 18, WrPageOut = 19, WrRendezvous = 20, Spare2 = 21, Spare3 = 22, Spare4 = 23, Spare5 = 24, WrCalloutStack = 25, WrKernel = 26, WrResource = 27, WrPushLock = 28, WrMutex = 29, WrQuantumEnd = 30, WrDispatchInt = 31, WrPreempted = 32, WrYieldExecution = 33, WrFastMutex = 34, WrGuardedMutex = 35, WrRundown = 36, MaximumWaitReason = 37 } KWAIT_REASON, *PKWAIT_REASON; typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; LONG Priority; LONG BasePriority; ULONG ContextSwitches; ULONG ThreadState; KWAIT_REASON WaitReason; } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; typedef struct _TEB *PTEB; // private typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION { SYSTEM_THREAD_INFORMATION ThreadInfo; PVOID StackBase; PVOID StackLimit; PVOID Win32StartAddress; PTEB TebBase; ULONG_PTR Reserved2; ULONG_PTR Reserved3; ULONG_PTR Reserved4; } SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; typedef struct _SYSTEM_PROCESS_INFORMATION2 { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER SpareLi1; LARGE_INTEGER SpareLi2; LARGE_INTEGER SpareLi3; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; LONG BasePriority; HANDLE UniqueProcessId; HANDLE InheritedFromUniqueProcessId; ULONG HandleCount; ULONG SessionId; ULONG_PTR PageDirectoryBase; SIZE_T PeakVirtualSize; SIZE_T VirtualSize; DWORD PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; SYSTEM_THREAD_INFORMATION Threads[1]; } SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2; #define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2 #define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2 // ================================================ // psutil.users() support // ================================================ typedef struct _WINSTATION_INFO { BYTE Reserved1[72]; ULONG SessionId; BYTE Reserved2[4]; FILETIME ConnectTime; FILETIME DisconnectTime; FILETIME LastInputTime; FILETIME LoginTime; BYTE Reserved3[1096]; FILETIME CurrentTime; } WINSTATION_INFO, *PWINSTATION_INFO; typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW) (HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG); /* * NtQueryInformationProcess code taken from * http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/ * typedefs needed to compile against ntdll functions not exposted in the API */ typedef LONG NTSTATUS; typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)( HANDLE ProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, DWORD ProcessInformationLength, PDWORD ReturnLength ); typedef NTSTATUS (NTAPI *_NtSetInformationProcess)( HANDLE ProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, DWORD ProcessInformationLength ); typedef enum _PROCESSINFOCLASS2 { _ProcessBasicInformation, ProcessQuotaLimits, ProcessIoCounters, ProcessVmCounters, ProcessTimes, ProcessBasePriority, ProcessRaisePriority, _ProcessDebugPort, ProcessExceptionPort, ProcessAccessToken, ProcessLdtInformation, ProcessLdtSize, ProcessDefaultHardErrorMode, ProcessIoPortHandlers, ProcessPooledUsageAndLimits, ProcessWorkingSetWatch, ProcessUserModeIOPL, ProcessEnableAlignmentFaultFixup, ProcessPriorityClass, ProcessWx86Information, ProcessHandleCount, ProcessAffinityMask, ProcessPriorityBoost, ProcessDeviceMap, ProcessSessionInformation, ProcessForegroundInformation, _ProcessWow64Information, /* added after XP+ */ _ProcessImageFileName, ProcessLUIDDeviceMapsEnabled, // MSVC 2015 starts forcing C++11 standard, which does not allow duplicate // unscoped enumerations. It doesn't matter that this is C code, MSVC is a C++ compiler. #if _MSC_VER < 1900 ProcessBreakOnTermination, #endif ProcessDebugObjectHandle=ProcessLUIDDeviceMapsEnabled+2, ProcessDebugFlags, ProcessHandleTracing, ProcessIoPriority, ProcessExecuteFlags, ProcessResourceManagement, ProcessCookie, ProcessImageInformation, MaxProcessInfoClass } PROCESSINFOCLASS2; #define PROCESSINFOCLASS PROCESSINFOCLASS2 #define ProcessBasicInformation _ProcessBasicInformation #define ProcessWow64Information _ProcessWow64Information #define ProcessDebugPort _ProcessDebugPort #define ProcessImageFileName _ProcessImageFileName #endif // __NTEXTAPI_H__ psutil-3.4.2/psutil/arch/windows/inet_ntop.c0000664000175000017500000000225212572074510023102 0ustar giampaologiampaolo00000000000000#include "inet_ntop.h" // From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/ PCSTR WSAAPI inet_ntop(__in INT Family, __in PVOID pAddr, __out_ecount(StringBufSize) PSTR pStringBuf, __in size_t StringBufSize) { DWORD dwAddressLength = 0; struct sockaddr_storage srcaddr; struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr; struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr; memset(&srcaddr, 0, sizeof(struct sockaddr_storage)); srcaddr.ss_family = Family; if (Family == AF_INET) { dwAddressLength = sizeof(struct sockaddr_in); memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr)); } else if (Family == AF_INET6) { dwAddressLength = sizeof(struct sockaddr_in6); memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr)); } else { return NULL; } if (WSAAddressToString((LPSOCKADDR) &srcaddr, dwAddressLength, 0, pStringBuf, (LPDWORD) &StringBufSize) != 0) { return NULL; } return pStringBuf; } psutil-3.4.2/psutil/arch/windows/inet_ntop.h0000664000175000017500000000047212572074510023111 0ustar giampaologiampaolo00000000000000#include PCSTR WSAAPI inet_ntop( __in INT Family, __in PVOID pAddr, __out_ecount(StringBufSize) PSTR pStringBuf, __in size_t StringBufSize );psutil-3.4.2/psutil/arch/windows/security.c0000664000175000017500000001446512572074510022763 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Security related functions for Windows platform (Set privileges such as * SeDebug), as well as security helper functions. */ #include #include /* * Convert a process handle to a process token handle. */ HANDLE psutil_token_from_handle(HANDLE hProcess) { HANDLE hToken = NULL; if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) return PyErr_SetFromWindowsErr(0); return hToken; } /* * http://www.ddj.com/windows/184405986 * * There's a way to determine whether we're running under the Local System * account. However (you guessed it), we have to call more Win32 functions to * determine this. Backing up through the code listing, we need to make another * call to GetTokenInformation, but instead of passing through the TOKEN_USER * constant, we pass through the TOKEN_PRIVILEGES constant. This value returns * an array of privileges that the account has in the environment. Iterating * through the array, we call the function LookupPrivilegeName looking for the * string “SeTcbPrivilege. If the function returns this string, then this * account has Local System privileges */ int psutil_has_system_privilege(HANDLE hProcess) { DWORD i; DWORD dwSize = 0; DWORD dwRetval = 0; TCHAR privName[256]; DWORD dwNameSize = 256; // PTOKEN_PRIVILEGES tp = NULL; BYTE *pBuffer = NULL; TOKEN_PRIVILEGES *tp = NULL; HANDLE hToken = psutil_token_from_handle(hProcess); if (NULL == hToken) return -1; // call GetTokenInformation first to get the buffer size if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) { dwRetval = GetLastError(); // if it failed for a reason other than the buffer, bail out if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) { PyErr_SetFromWindowsErr(dwRetval); return 0; } } // allocate buffer and call GetTokenInformation again // tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize); pBuffer = (BYTE *) malloc(dwSize); if (pBuffer == NULL) { PyErr_NoMemory(); return -1; } if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer, dwSize, &dwSize)) { PyErr_SetFromWindowsErr(0); free(pBuffer); return -1; } // convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer tp = (TOKEN_PRIVILEGES *)pBuffer; // check all the privileges looking for SeTcbPrivilege for (i = 0; i < tp->PrivilegeCount; i++) { // reset the buffer contents and the buffer size strcpy(privName, ""); dwNameSize = sizeof(privName) / sizeof(TCHAR); if (! LookupPrivilegeName(NULL, &tp->Privileges[i].Luid, (LPTSTR)privName, &dwNameSize)) { PyErr_SetFromWindowsErr(0); free(pBuffer); return -1; } // if we find the SeTcbPrivilege then it's a LocalSystem process if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) { free(pBuffer); return 1; } } free(pBuffer); return 0; } BOOL psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) { TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); if (!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; // first pass. get current privilege setting tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0; AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious ); if (GetLastError() != ERROR_SUCCESS) return FALSE; // second pass. set privilege based on previous setting tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; if (bEnablePrivilege) tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); else tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); AdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL ); if (GetLastError() != ERROR_SUCCESS) return FALSE; return TRUE; } int psutil_set_se_debug() { HANDLE hToken; if (! OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ) { if (GetLastError() == ERROR_NO_TOKEN) { if (!ImpersonateSelf(SecurityImpersonation)) { CloseHandle(hToken); return 0; } if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ) { RevertToSelf(); CloseHandle(hToken); return 0; } } } // enable SeDebugPrivilege (open any process) if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE)) { RevertToSelf(); CloseHandle(hToken); return 0; } RevertToSelf(); CloseHandle(hToken); return 1; } int psutil_unset_se_debug() { HANDLE hToken; if (! OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ) { if (GetLastError() == ERROR_NO_TOKEN) { if (! ImpersonateSelf(SecurityImpersonation)) return 0; if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) { return 0; } } } // now disable SeDebug if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) return 0; CloseHandle(hToken); return 1; } psutil-3.4.2/psutil/arch/windows/process_info.h0000664000175000017500000000151312572074510023600 0ustar giampaologiampaolo00000000000000/* * 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. */ #if !defined(__PROCESS_INFO_H) #define __PROCESS_INFO_H #include #include #include "security.h" #include "ntextapi.h" DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); HANDLE psutil_handle_from_pid(DWORD pid); HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess); int psutil_handlep_is_running(HANDLE hProcess); int psutil_pid_in_proclist(DWORD pid); int psutil_pid_is_running(DWORD pid); PVOID psutil_get_peb_address(HANDLE ProcessHandle); PyObject* psutil_get_cmdline(long pid); int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer); #endif psutil-3.4.2/psutil/arch/windows/process_info.c0000664000175000017500000002617712572074510023610 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Helper functions related to fetching process information. Used by * _psutil_windows module methods. */ #include #include #include #include #include "security.h" #include "process_info.h" #include "ntextapi.h" #include "../../_psutil_common.h" /* * A wrapper around OpenProcess setting NSP exception if process * no longer exists. * "pid" is the process pid, "dwDesiredAccess" is the first argument * exptected by OpenProcess. * Return a process handle or NULL. */ HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) { HANDLE hProcess; DWORD processExitCode = 0; if (pid == 0) { // otherwise we'd get NoSuchProcess return AccessDenied(); } hProcess = OpenProcess(dwDesiredAccess, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) NoSuchProcess(); else PyErr_SetFromWindowsErr(0); return NULL; } // make sure the process is running GetExitCodeProcess(hProcess, &processExitCode); if (processExitCode == 0) { NoSuchProcess(); CloseHandle(hProcess); return NULL; } return hProcess; } /* * Same as psutil_handle_from_pid_waccess but implicitly uses * PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as dwDesiredAccess * parameter for OpenProcess. */ HANDLE psutil_handle_from_pid(DWORD pid) { DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; return psutil_handle_from_pid_waccess(pid, dwDesiredAccess); } // fetch the PEB base address from NtQueryInformationProcess() PVOID psutil_get_peb_address(HANDLE ProcessHandle) { _NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); PROCESS_BASIC_INFORMATION pbi; NtQueryInformationProcess(ProcessHandle, 0, &pbi, sizeof(pbi), NULL); return pbi.PebBaseAddress; } DWORD * psutil_get_pids(DWORD *numberOfReturnedPIDs) { // Win32 SDK says the only way to know if our process array // wasn't large enough is to check the returned size and make // sure that it doesn't match the size of the array. // If it does we allocate a larger array and try again // Stores the actual array DWORD *procArray = NULL; DWORD procArrayByteSz; int procArraySz = 0; // Stores the byte size of the returned array from enumprocesses DWORD enumReturnSz = 0; do { procArraySz += 1024; free(procArray); procArrayByteSz = procArraySz * sizeof(DWORD); procArray = malloc(procArrayByteSz); if (procArray == NULL) { PyErr_NoMemory(); return NULL; } if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) { free(procArray); PyErr_SetFromWindowsErr(0); return NULL; } } while (enumReturnSz == procArraySz * sizeof(DWORD)); // The number of elements is the returned size / size of each element *numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD); return procArray; } int psutil_pid_is_running(DWORD pid) { HANDLE hProcess; DWORD exitCode; // Special case for PID 0 System Idle Process if (pid == 0) return 1; if (pid < 0) return 0; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (NULL == hProcess) { // invalid parameter is no such process if (GetLastError() == ERROR_INVALID_PARAMETER) { CloseHandle(hProcess); return 0; } // access denied obviously means there's a process to deny access to... if (GetLastError() == ERROR_ACCESS_DENIED) { CloseHandle(hProcess); return 1; } CloseHandle(hProcess); PyErr_SetFromWindowsErr(0); return -1; } if (GetExitCodeProcess(hProcess, &exitCode)) { CloseHandle(hProcess); return (exitCode == STILL_ACTIVE); } // access denied means there's a process there so we'll assume // it's running if (GetLastError() == ERROR_ACCESS_DENIED) { CloseHandle(hProcess); return 1; } PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return -1; } int psutil_pid_in_proclist(DWORD pid) { DWORD *proclist = NULL; DWORD numberOfReturnedPIDs; DWORD i; proclist = psutil_get_pids(&numberOfReturnedPIDs); if (proclist == NULL) return -1; for (i = 0; i < numberOfReturnedPIDs; i++) { if (pid == proclist[i]) { free(proclist); return 1; } } free(proclist); return 0; } // Check exit code from a process handle. Return FALSE on an error also // XXX - not used anymore int handlep_is_running(HANDLE hProcess) { DWORD dwCode; if (NULL == hProcess) return 0; if (GetExitCodeProcess(hProcess, &dwCode)) { if (dwCode == STILL_ACTIVE) return 1; } return 0; } /* * returns a Python list representing the arguments for the process * with given pid or NULL on error. */ PyObject * psutil_get_cmdline(long pid) { int nArgs, i; LPWSTR *szArglist = NULL; HANDLE hProcess = NULL; PVOID pebAddress; PVOID rtlUserProcParamsAddress; UNICODE_STRING commandLine; WCHAR *commandLineContents = NULL; PyObject *py_unicode = NULL; PyObject *py_retlist = NULL; hProcess = psutil_handle_from_pid(pid); if (hProcess == NULL) return NULL; pebAddress = psutil_get_peb_address(hProcess); // get the address of ProcessParameters #ifdef _WIN64 if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 32, &rtlUserProcParamsAddress, sizeof(PVOID), NULL)) #else if (!ReadProcessMemory(hProcess, (PCHAR)pebAddress + 0x10, &rtlUserProcParamsAddress, sizeof(PVOID), NULL)) #endif { ////printf("Could not read the address of ProcessParameters!\n"); PyErr_SetFromWindowsErr(0); goto error; } // read the CommandLine UNICODE_STRING structure #ifdef _WIN64 if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 112, &commandLine, sizeof(commandLine), NULL)) #else if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x40, &commandLine, sizeof(commandLine), NULL)) #endif { PyErr_SetFromWindowsErr(0); goto error; } // allocate memory to hold the command line commandLineContents = (WCHAR *)malloc(commandLine.Length + 1); if (commandLineContents == NULL) { PyErr_NoMemory(); goto error; } // read the command line if (!ReadProcessMemory(hProcess, commandLine.Buffer, commandLineContents, commandLine.Length, NULL)) { PyErr_SetFromWindowsErr(0); goto error; } // Null-terminate the string to prevent wcslen from returning // incorrect length the length specifier is in characters, but // commandLine.Length is in bytes. commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0'; // attempt to parse the command line using Win32 API, fall back // on string cmdline version otherwise szArglist = CommandLineToArgvW(commandLineContents, &nArgs); if (szArglist == NULL) { PyErr_SetFromWindowsErr(0); goto error; } else { // arglist parsed as array of UNICODE_STRING, so convert each to // Python string object and add to arg list py_retlist = Py_BuildValue("[]"); if (py_retlist == NULL) goto error; for (i = 0; i < nArgs; i++) { py_unicode = PyUnicode_FromWideChar( szArglist[i], wcslen(szArglist[i])); if (py_unicode == NULL) goto error; if (PyList_Append(py_retlist, py_unicode)) goto error; Py_XDECREF(py_unicode); } } if (szArglist != NULL) LocalFree(szArglist); free(commandLineContents); CloseHandle(hProcess); return py_retlist; error: Py_XDECREF(py_unicode); Py_XDECREF(py_retlist); if (hProcess != NULL) CloseHandle(hProcess); if (commandLineContents != NULL) free(commandLineContents); if (szArglist != NULL) LocalFree(szArglist); return NULL; } #define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes)) #define PH_NEXT_PROCESS(Process) ( \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \ (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \ NULL) const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L; /* * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure * fills the structure with various process information by using * NtQuerySystemInformation. * We use this as a fallback when faster functions fail with access * denied. This is slower because it iterates over all processes. * On success return 1, else 0 with Python exception already set. */ int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer) { static ULONG initialBufferSize = 0x4000; NTSTATUS status; PVOID buffer; ULONG bufferSize; PSYSTEM_PROCESS_INFORMATION process; // get NtQuerySystemInformation typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; HINSTANCE hNtDll; hNtDll = LoadLibrary(TEXT("ntdll.dll")); NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( hNtDll, "NtQuerySystemInformation"); bufferSize = initialBufferSize; buffer = malloc(bufferSize); if (buffer == NULL) { PyErr_NoMemory(); goto error; } while (TRUE) { status = NtQuerySystemInformation(SystemProcessInformation, buffer, bufferSize, &bufferSize); if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH) { free(buffer); buffer = malloc(bufferSize); if (buffer == NULL) { PyErr_NoMemory(); goto error; } } else { break; } } if (status != 0) { PyErr_Format(PyExc_RuntimeError, "NtQuerySystemInformation() failed"); goto error; } if (bufferSize <= 0x20000) initialBufferSize = bufferSize; process = PH_FIRST_PROCESS(buffer); do { if (process->UniqueProcessId == (HANDLE)pid) { *retProcess = process; *retBuffer = buffer; return 1; } } while ( (process = PH_NEXT_PROCESS(process)) ); NoSuchProcess(); goto error; error: FreeLibrary(hNtDll); if (buffer != NULL) free(buffer); return 0; } psutil-3.4.2/psutil/arch/windows/process_handles.c0000664000175000017500000003634312572074510024267 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 "process_handles.h" static _NtQuerySystemInformation __NtQuerySystemInformation = NULL; static _NtQueryObject __NtQueryObject = NULL; CRITICAL_SECTION g_cs; BOOL g_initialized = FALSE; NTSTATUS g_status; HANDLE g_hFile = NULL; HANDLE g_hEvtStart = NULL; HANDLE g_hEvtFinish = NULL; HANDLE g_hThread = NULL; PUNICODE_STRING g_pNameBuffer = NULL; ULONG g_dwSize = 0; ULONG g_dwLength = 0; PVOID g_fiber = NULL; PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) { return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); } PyObject * psutil_get_open_files(long dwPid, HANDLE hProcess) { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); // Threaded version only works for Vista+ if (osvi.dwMajorVersion >= 6) return psutil_get_open_files_ntqueryobject(dwPid, hProcess); else return psutil_get_open_files_getmappedfilename(dwPid, hProcess); } VOID psutil_get_open_files_init(BOOL threaded) { if (g_initialized == TRUE) return; // Resolve the Windows API calls __NtQuerySystemInformation = GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); __NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); // Create events for signalling work between threads if (threaded == TRUE) { g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL); g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL); InitializeCriticalSection(&g_cs); } g_initialized = TRUE; } PyObject * psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) { NTSTATUS status; PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; DWORD dwInfoSize = 0x10000; DWORD dwRet = 0; PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; DWORD i = 0; BOOLEAN error = FALSE; DWORD dwWait = 0; PyObject* py_retlist = NULL; PyObject* py_path = NULL; if (g_initialized == FALSE) psutil_get_open_files_init(TRUE); // Due to the use of global variables, ensure only 1 call // to psutil_get_open_files() is running EnterCriticalSection(&g_cs); if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL || g_hEvtStart == NULL || g_hEvtFinish == NULL) { PyErr_SetFromWindowsErr(0); error = TRUE; goto cleanup; } // Py_BuildValue raises an exception if NULL is returned py_retlist = PyList_New(0); if (py_retlist == NULL) { error = TRUE; goto cleanup; } do { if (pHandleInfo != NULL) { HeapFree(GetProcessHeap(), 0, pHandleInfo); pHandleInfo = NULL; } // NtQuerySystemInformation won't give us the correct buffer size, // so we guess by doubling the buffer size. dwInfoSize *= 2; pHandleInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwInfoSize); if (pHandleInfo == NULL) { PyErr_NoMemory(); error = TRUE; goto cleanup; } } while ((status = __NtQuerySystemInformation( SystemExtendedHandleInformation, pHandleInfo, dwInfoSize, &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH if (!NT_SUCCESS(status)) { PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); error = TRUE; goto cleanup; } for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { hHandle = &pHandleInfo->Handles[i]; // Check if this hHandle belongs to the PID the user specified. if (hHandle->UniqueProcessId != (HANDLE)dwPid || hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE) goto loop_cleanup; if (!DuplicateHandle(hProcess, hHandle->HandleValue, GetCurrentProcess(), &g_hFile, 0, TRUE, DUPLICATE_SAME_ACCESS)) { /* printf("[%d] DuplicateHandle (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ goto loop_cleanup; } // Guess buffer size is MAX_PATH + 1 g_dwLength = (MAX_PATH+1) * sizeof(WCHAR); do { // Release any previously allocated buffer if (g_pNameBuffer != NULL) { HeapFree(GetProcessHeap(), 0, g_pNameBuffer); g_pNameBuffer = NULL; g_dwSize = 0; } // NtQueryObject puts the required buffer size in g_dwLength // WinXP edge case puts g_dwLength == 0, just skip this handle if (g_dwLength == 0) goto loop_cleanup; g_dwSize = g_dwLength; if (g_dwSize > 0) { g_pNameBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_dwSize); if (g_pNameBuffer == NULL) goto loop_cleanup; } dwWait = psutil_NtQueryObject(); // If the call does not return, skip this handle if (dwWait != WAIT_OBJECT_0) goto loop_cleanup; } while (g_status == STATUS_INFO_LENGTH_MISMATCH); // NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH if (!NT_SUCCESS(g_status)) goto loop_cleanup; // Convert to PyUnicode and append it to the return list if (g_pNameBuffer->Length > 0) { /* printf("[%d] Filename (%#x) %#d bytes: %S\n", dwPid, hHandle->HandleValue, g_pNameBuffer->Length, g_pNameBuffer->Buffer); */ py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer, g_pNameBuffer->Length/2); if (py_path == NULL) { /* printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ error = TRUE; goto loop_cleanup; } if (PyList_Append(py_retlist, py_path)) { /* printf("[%d] PyList_Append (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ error = TRUE; goto loop_cleanup; } } loop_cleanup: Py_XDECREF(py_path); py_path = NULL; if (g_pNameBuffer != NULL) HeapFree(GetProcessHeap(), 0, g_pNameBuffer); g_pNameBuffer = NULL; g_dwSize = 0; g_dwLength = 0; if (g_hFile != NULL) CloseHandle(g_hFile); g_hFile = NULL; } cleanup: if (g_pNameBuffer != NULL) HeapFree(GetProcessHeap(), 0, g_pNameBuffer); g_pNameBuffer = NULL; g_dwSize = 0; g_dwLength = 0; if (g_hFile != NULL) CloseHandle(g_hFile); g_hFile = NULL; if (pHandleInfo != NULL) HeapFree(GetProcessHeap(), 0, pHandleInfo); pHandleInfo = NULL; if (error) { Py_XDECREF(py_retlist); py_retlist = NULL; } LeaveCriticalSection(&g_cs); return py_retlist; } DWORD psutil_NtQueryObject() { DWORD dwWait = 0; if (g_hThread == NULL) g_hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)psutil_NtQueryObjectThread, NULL, 0, NULL); if (g_hThread == NULL) return GetLastError(); // Signal the worker thread to start SetEvent(g_hEvtStart); // Wait for the worker thread to finish dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT); // If the thread hangs, kill it and cleanup if (dwWait == WAIT_TIMEOUT) { SuspendThread(g_hThread); TerminateThread(g_hThread, 1); WaitForSingleObject(g_hThread, INFINITE); CloseHandle(g_hThread); // Cleanup Fiber if (g_fiber != NULL) DeleteFiber(g_fiber); g_fiber = NULL; g_hThread = NULL; } return dwWait; } void psutil_NtQueryObjectThread() { // Prevent the thread stack from leaking when this // thread gets terminated due to NTQueryObject hanging g_fiber = ConvertThreadToFiber(NULL); // Loop infinitely waiting for work while (TRUE) { WaitForSingleObject(g_hEvtStart, INFINITE); g_status = __NtQueryObject(g_hFile, ObjectNameInformation, g_pNameBuffer, g_dwSize, &g_dwLength); SetEvent(g_hEvtFinish); } } PyObject * psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) { NTSTATUS status; PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL; DWORD dwInfoSize = 0x10000; DWORD dwRet = 0; PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL; HANDLE hFile = NULL; HANDLE hMap = NULL; DWORD i = 0; BOOLEAN error = FALSE; PyObject* py_retlist = NULL; PyObject* py_path = NULL; ULONG dwSize = 0; LPVOID pMem = NULL; TCHAR pszFilename[MAX_PATH+1]; if (g_initialized == FALSE) psutil_get_open_files_init(FALSE); if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) { PyErr_SetFromWindowsErr(0); error = TRUE; goto cleanup; } // Py_BuildValue raises an exception if NULL is returned py_retlist = PyList_New(0); if (py_retlist == NULL) { error = TRUE; goto cleanup; } do { if (pHandleInfo != NULL) { HeapFree(GetProcessHeap(), 0, pHandleInfo); pHandleInfo = NULL; } // NtQuerySystemInformation won't give us the correct buffer size, // so we guess by doubling the buffer size. dwInfoSize *= 2; pHandleInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwInfoSize); if (pHandleInfo == NULL) { PyErr_NoMemory(); error = TRUE; goto cleanup; } } while ((status = __NtQuerySystemInformation( SystemExtendedHandleInformation, pHandleInfo, dwInfoSize, &dwRet)) == STATUS_INFO_LENGTH_MISMATCH); // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH if (!NT_SUCCESS(status)) { PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status)); error = TRUE; goto cleanup; } for (i = 0; i < pHandleInfo->NumberOfHandles; i++) { hHandle = &pHandleInfo->Handles[i]; // Check if this hHandle belongs to the PID the user specified. if (hHandle->UniqueProcessId != (HANDLE)dwPid || hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE) goto loop_cleanup; if (!DuplicateHandle(hProcess, hHandle->HandleValue, GetCurrentProcess(), &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS)) { /* printf("[%d] DuplicateHandle (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ goto loop_cleanup; } hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMap == NULL) { /* printf("[%d] CreateFileMapping (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ goto loop_cleanup; } pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1); if (pMem == NULL) { /* printf("[%d] MapViewOfFile (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ goto loop_cleanup; } dwSize = GetMappedFileName( GetCurrentProcess(), pMem, pszFilename, MAX_PATH); if (dwSize == 0) { /* printf("[%d] GetMappedFileName (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ goto loop_cleanup; } pszFilename[dwSize] = '\0'; /* printf("[%d] Filename (%#x) %#d bytes: %S\n", dwPid, hHandle->HandleValue, dwSize, pszFilename); */ py_path = PyUnicode_FromWideChar(pszFilename, dwSize); if (py_path == NULL) { /* printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ error = TRUE; goto loop_cleanup; } if (PyList_Append(py_retlist, py_path)) { /* printf("[%d] PyList_Append (%#x): %#x \n", dwPid, hHandle->HandleValue, GetLastError()); */ error = TRUE; goto loop_cleanup; } loop_cleanup: Py_XDECREF(py_path); py_path = NULL; if (pMem != NULL) UnmapViewOfFile(pMem); pMem = NULL; if (hMap != NULL) CloseHandle(hMap); hMap = NULL; if (hFile != NULL) CloseHandle(hFile); hFile = NULL; dwSize = 0; } cleanup: if (pMem != NULL) UnmapViewOfFile(pMem); pMem = NULL; if (hMap != NULL) CloseHandle(hMap); hMap = NULL; if (hFile != NULL) CloseHandle(hFile); hFile = NULL; if (pHandleInfo != NULL) HeapFree(GetProcessHeap(), 0, pHandleInfo); pHandleInfo = NULL; if (error) { Py_XDECREF(py_retlist); py_retlist = NULL; } return py_retlist; } psutil-3.4.2/psutil/arch/windows/glpi.h0000664000175000017500000000216412572074510022045 0ustar giampaologiampaolo00000000000000// mingw headers are missing this typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP { RelationProcessorCore, RelationNumaNode, RelationCache, RelationProcessorPackage, RelationGroup, RelationAll=0xffff } LOGICAL_PROCESSOR_RELATIONSHIP; typedef enum _PROCESSOR_CACHE_TYPE { CacheUnified,CacheInstruction,CacheData,CacheTrace } PROCESSOR_CACHE_TYPE; typedef struct _CACHE_DESCRIPTOR { BYTE Level; BYTE Associativity; WORD LineSize; DWORD Size; PROCESSOR_CACHE_TYPE Type; } CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR; typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION { ULONG_PTR ProcessorMask; LOGICAL_PROCESSOR_RELATIONSHIP Relationship; union { struct { BYTE Flags; } ProcessorCore; struct { DWORD NodeNumber; } NumaNode; CACHE_DESCRIPTOR Cache; ULONGLONG Reserved[2]; }; } SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION; WINBASEAPI WINBOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnedLength);psutil-3.4.2/psutil/arch/windows/security.h0000664000175000017500000000110212572074510022750 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Security related functions for Windows platform (Set privileges such as * SeDebug), as well as security helper functions. */ #include BOOL psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege); HANDLE psutil_token_from_handle(HANDLE hProcess); int psutil_has_system_privilege(HANDLE hProcess); int psutil_set_se_debug(); int psutil_unset_se_debug(); psutil-3.4.2/psutil/arch/windows/process_handles.h0000664000175000017500000000620612572074510024267 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef __PROCESS_HANDLES_H__ #define __PROCESS_HANDLES_H__ #ifndef UNICODE #define UNICODE #endif #include #include #include #include #include #include #ifndef NT_SUCCESS #define NT_SUCCESS(x) ((x) >= 0) #endif #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 #define ObjectBasicInformation 0 #define ObjectNameInformation 1 #define ObjectTypeInformation 2 #define HANDLE_TYPE_FILE 28 #define NTQO_TIMEOUT 100 typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); typedef NTSTATUS (NTAPI *_NtQueryObject)( HANDLE ObjectHandle, ULONG ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength ); // Undocumented FILE_INFORMATION_CLASS: FileNameInformation static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64; typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { PVOID Object; HANDLE UniqueProcessId; HANDLE HandleValue; ULONG GrantedAccess; USHORT CreatorBackTraceIndex; USHORT ObjectTypeIndex; ULONG HandleAttributes; ULONG Reserved; } SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; typedef struct _SYSTEM_HANDLE_INFORMATION_EX { ULONG_PTR NumberOfHandles; ULONG_PTR Reserved; SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; } SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; typedef enum _POOL_TYPE { NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, NonPagedPoolCacheAligned, PagedPoolCacheAligned, NonPagedPoolCacheAlignedMustS } POOL_TYPE, *PPOOL_TYPE; typedef struct _OBJECT_TYPE_INFORMATION { UNICODE_STRING Name; ULONG TotalNumberOfObjects; ULONG TotalNumberOfHandles; ULONG TotalPagedPoolUsage; ULONG TotalNonPagedPoolUsage; ULONG TotalNamePoolUsage; ULONG TotalHandleTableUsage; ULONG HighWaterNumberOfObjects; ULONG HighWaterNumberOfHandles; ULONG HighWaterPagedPoolUsage; ULONG HighWaterNonPagedPoolUsage; ULONG HighWaterNamePoolUsage; ULONG HighWaterHandleTableUsage; ULONG InvalidAttributes; GENERIC_MAPPING GenericMapping; ULONG ValidAccess; BOOLEAN SecurityRequired; BOOLEAN MaintainHandleCount; USHORT MaintainTypeList; POOL_TYPE PoolType; ULONG PagedPoolUsage; ULONG NonPagedPoolUsage; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName); VOID psutil_get_open_files_init(BOOL threaded); PyObject* psutil_get_open_files(long pid, HANDLE processHandle); PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess); PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess); DWORD psutil_NtQueryObject(void); void psutil_NtQueryObjectThread(void); #endif // __PROCESS_HANDLES_H__ psutil-3.4.2/psutil/arch/solaris/0000775000175000017500000000000012647732502020725 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/solaris/v10/0000775000175000017500000000000012647732502021333 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/solaris/v10/ifaddrs.c0000664000175000017500000000632012573043720023107 0ustar giampaologiampaolo00000000000000/* Refrences: * https://lists.samba.org/archive/samba-technical/2009-February/063079.html * http://stackoverflow.com/questions/4139405/#4139811 * https://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/getifaddrs.c */ #include #include #include #include #include #include #include #include #include #include "ifaddrs.h" #define MAX(x,y) ((x)>(y)?(x):(y)) #define SIZE(p) MAX((p).ss_len,sizeof(p)) static struct sockaddr * sa_dup (struct sockaddr *sa1) { struct sockaddr *sa2; size_t sz = sizeof(sa1); sa2 = (struct sockaddr *) calloc(1,sz); memcpy(sa2,sa1,sz); return(sa2); } void freeifaddrs (struct ifaddrs *ifp) { if (NULL == ifp) return; free(ifp->ifa_name); free(ifp->ifa_addr); free(ifp->ifa_netmask); free(ifp->ifa_dstaddr); freeifaddrs(ifp->ifa_next); free(ifp); } int getifaddrs (struct ifaddrs **ifap) { int sd = -1; char *ccp, *ecp; struct lifconf ifc; struct lifreq *ifr; struct lifnum lifn; struct ifaddrs *cifa = NULL; /* current */ struct ifaddrs *pifa = NULL; /* previous */ const size_t IFREQSZ = sizeof(struct lifreq); sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) goto error; ifc.lifc_buf = NULL; *ifap = NULL; /* find how much memory to allocate for the SIOCGLIFCONF call */ lifn.lifn_family = AF_UNSPEC; lifn.lifn_flags = 0; if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0) goto error; /* Sun and Apple code likes to pad the interface count here in case interfaces * are coming up between calls */ lifn.lifn_count += 4; ifc.lifc_family = AF_UNSPEC; ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq); ifc.lifc_buf = calloc(1, ifc.lifc_len); if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0) goto error; ccp = (char *)ifc.lifc_req; ecp = ccp + ifc.lifc_len; while (ccp < ecp) { ifr = (struct lifreq *) ccp; cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs)); cifa->ifa_next = NULL; cifa->ifa_name = strdup(ifr->lifr_name); if (pifa == NULL) *ifap = cifa; /* first one */ else pifa->ifa_next = cifa; if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0) goto error; cifa->ifa_addr = sa_dup((struct sockaddr*)&ifr->lifr_addr); if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0) goto error; cifa->ifa_netmask = sa_dup((struct sockaddr*)&ifr->lifr_addr); cifa->ifa_flags = 0; cifa->ifa_dstaddr = NULL; if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */ cifa->ifa_flags = ifr->lifr_flags; if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) { if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ)) cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr); } else cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr); pifa = cifa; ccp += IFREQSZ; } free(ifc.lifc_buf); close(sd); return 0; error: if (ifc.lifc_buf != NULL) free(ifc.lifc_buf); if (sd != -1) close(sd); return (-1); } psutil-3.4.2/psutil/arch/solaris/v10/ifaddrs.h0000664000175000017500000000107012573043720023111 0ustar giampaologiampaolo00000000000000/* Reference: https://lists.samba.org/archive/samba-technical/2009-February/063079.html */ #ifndef __IFADDRS_H___ #define __IFADDRS_H___ #include #include #undef ifa_dstaddr #undef ifa_broadaddr #define ifa_broadaddr ifa_dstaddr struct ifaddrs { struct ifaddrs *ifa_next; char *ifa_name; unsigned int ifa_flags; struct sockaddr *ifa_addr; struct sockaddr *ifa_netmask; struct sockaddr *ifa_dstaddr; }; extern int getifaddrs(struct ifaddrs **); extern void freeifaddrs(struct ifaddrs *); #endifpsutil-3.4.2/psutil/arch/bsd/0000775000175000017500000000000012647732502020021 5ustar giampaologiampaolo00000000000000psutil-3.4.2/psutil/arch/bsd/freebsd.h0000664000175000017500000000252312645372437021613 0ustar giampaologiampaolo00000000000000/* * 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 typedef struct kinfo_proc kinfo_proc; static char *psutil_get_cmd_args(long pid, size_t *argsize); int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc); int psutil_pid_exists(long pid); // PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); PyObject* psutil_get_cmdline(long pid); PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args); PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args); PyObject* psutil_proc_cwd(PyObject* self, PyObject* args); PyObject* psutil_proc_exe(PyObject* self, PyObject* args); PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args); PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); PyObject* psutil_proc_threads(PyObject* self, PyObject* args); PyObject* psutil_swap_mem(PyObject* self, PyObject* args); PyObject* psutil_virtual_mem(PyObject* self, PyObject* args); psutil-3.4.2/psutil/arch/bsd/openbsd.h0000664000175000017500000000211112645372437021624 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include typedef struct kinfo_proc kinfo_proc; int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc); struct kinfo_file * kinfo_getfile(long pid, int* cnt); int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); char **_psutil_get_argv(long pid); PyObject * psutil_get_cmdline(long pid); int psutil_pid_exists(long pid); int psutil_raise_ad_or_nsp(long pid); // PyObject *psutil_proc_threads(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); PyObject *psutil_swap_mem(PyObject *self, PyObject *args); PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); PyObject *psutil_proc_cwd(PyObject *self, PyObject *args); PyObject *psutil_proc_connections(PyObject *self, PyObject *args); PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); psutil-3.4.2/psutil/arch/bsd/netbsd_socks.h0000664000175000017500000000051312645406531022650 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola'. * Copyright (c) 2015, Ryo ONODERA. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ PyObject *psutil_proc_connections(PyObject *, PyObject *); PyObject *psutil_net_connections(PyObject *, PyObject *); psutil-3.4.2/psutil/arch/bsd/netbsd.c0000664000175000017500000004135512646160647021460 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Platform-specific module methods for NetBSD. */ #if defined(__NetBSD__) #define _KMEMUSER #endif #include #include #include #include #include #include #include #include #include #include #include #include #include // for swap_mem #include #include // connection stuff #include // for NI_MAXHOST #include #include // for CPUSTATES & CP_* #define _KERNEL // for DTYPE_* #include #undef _KERNEL #include // struct diskstats #include #include #include "netbsd.h" #include "netbsd_socks.h" #include "../../_psutil_common.h" #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) // ============================================================================ // Utility functions // ============================================================================ int psutil_raise_ad_or_nsp(long pid) { // Set exception to AccessDenied if pid exists else NoSuchProcess. if (psutil_pid_exists(pid) == 0) NoSuchProcess(); else AccessDenied(); } int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) { // Fills a kinfo_proc struct based on process pid. int ret; int mib[6]; size_t size = sizeof(kinfo_proc); mib[0] = CTL_KERN; mib[1] = KERN_PROC2; mib[2] = KERN_PROC_PID; mib[3] = pid; mib[4] = size; mib[5] = 1; ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); if (ret == -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; } struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt) { // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an // int as arg and returns an array with cnt struct kinfo_file. int mib[6]; size_t len; struct kinfo_file* kf; mib[0] = CTL_KERN; mib[1] = KERN_FILE2; mib[2] = KERN_FILE_BYPID; mib[3] = (int) pid; mib[4] = sizeof(struct kinfo_file); mib[5] = 0; // get the size of what would be returned if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if ((kf = malloc(len)) == NULL) { PyErr_NoMemory(); return NULL; } mib[5] = (int)(len / sizeof(struct kinfo_file)); if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } *cnt = (int)(len / sizeof(struct kinfo_file)); return kf; } int psutil_pid_exists(pid_t pid) { // Return 1 if PID exists in the current process list, else 0, -1 // on error. // TODO: this should live in _psutil_posix.c but for some reason if I // move it there I get a "include undefined symbol" error. int ret; if (pid < 0) return 0; ret = kill(pid , 0); if (ret == 0) return 1; else { if (ret == ESRCH) return 0; else if (ret == EPERM) return 1; else { PyErr_SetFromErrno(PyExc_OSError); return -1; } } } // XXX: This is no longer used as per // https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820 // Current implementation uses /proc instead. // Left here just in case. PyObject * psutil_proc_exe(PyObject *self, PyObject *args) { #if __NetBSD_Version__ >= 799000000 pid_t pid; char pathname[MAXPATHLEN]; int error; int mib[4]; int ret; size_t size; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (pid == 0) { // else returns ENOENT return Py_BuildValue("s", ""); } mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; mib[2] = pid; mib[3] = KERN_PROC_PATHNAME; size = sizeof(pathname); error = sysctl(mib, 4, NULL, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } error = sysctl(mib, 4, pathname, &size, NULL, 0); if (error == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (size == 0 || strlen(pathname) == 0) { ret = psutil_pid_exists(pid); if (ret == -1) return NULL; else if (ret == 0) return NoSuchProcess(); else strcpy(pathname, ""); } return Py_BuildValue("s", pathname); #else return Py_BuildValue("s", ""); #endif } PyObject * psutil_proc_num_threads(PyObject *self, PyObject *args) { // Return number of threads used by process as a Python integer. long pid; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("l", (long)kp.p_nlwps); } PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { pid_t pid; int mib[5]; int i, nlwps; ssize_t st; size_t size; struct kinfo_lwp *kl = NULL; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; mib[0] = CTL_KERN; mib[1] = KERN_LWP; mib[2] = pid; mib[3] = sizeof(struct kinfo_lwp); mib[4] = 0; st = sysctl(mib, 5, NULL, &size, NULL, 0); if (st == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(); goto error; } mib[4] = size / sizeof(size_t); kl = malloc(size); if (kl == NULL) { PyErr_NoMemory(); goto error; } st = sysctl(mib, 5, kl, &size, NULL, 0); if (st == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if (size == 0) { NoSuchProcess(); goto error; } nlwps = (int)(size / sizeof(struct kinfo_lwp)); for (i = 0; i < nlwps; i++) { py_tuple = Py_BuildValue("idd", (&kl[i])->l_lid, PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime), PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime)); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(kl); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (kl != NULL) free(kl); return NULL; } // ============================================================================ // APIS // ============================================================================ int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) { // Returns a list of all BSD processes on the system. This routine // allocates the list and puts it in *procList and a count of the // number of entries in *procCount. You are responsible for freeing // this list (use "free" from System framework). // On success, the function returns 0. // On error, the function returns a BSD errno value. kinfo_proc *result; int done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 }; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; char errbuf[_POSIX2_LINE_MAX]; kinfo_proc *x; int cnt; kvm_t *kd; assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); if (kd == NULL) { PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed: %s", errbuf); return errno; } result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt); if (result == NULL) { PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() failed"); kvm_close(kd); return errno; } *procCount = (size_t)cnt; size_t mlen = cnt * sizeof(kinfo_proc); if ((*procList = malloc(mlen)) == NULL) { PyErr_NoMemory(); kvm_close(kd); return errno; } memcpy(*procList, result, mlen); assert(*procList != NULL); kvm_close(kd); return 0; } char * psutil_get_cmd_args(pid_t pid, size_t *argsize) { int mib[4]; ssize_t st; size_t argmax; size_t size; char *procargs = NULL; mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof(argmax); st = sysctl(mib, 2, &argmax, &size, NULL, 0); if (st == -1) { warn("failed to get kern.argmax"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } procargs = (char *)malloc(argmax); if (procargs == NULL) { PyErr_NoMemory(); return NULL; } mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; mib[2] = pid; mib[3] = KERN_PROC_ARGV; st = sysctl(mib, 4, procargs, &argmax, NULL, 0); if (st == -1) { warn("failed to get kern.procargs"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } *argsize = argmax; return procargs; } // Return the command line as a python list object. // XXX - most of the times sysctl() returns a truncated string. // Also /proc/pid/cmdline behaves the same so it looks like this // is a kernel bug. PyObject * psutil_get_cmdline(pid_t pid) { char *argstr = NULL; int pos = 0; size_t argsize = 0; PyObject *py_arg = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (pid == 0) return py_retlist; argstr = psutil_get_cmd_args(pid, &argsize); if (argstr == NULL) goto error; // args are returned as a flattened string with \0 separators between // arguments add each string to the list then step forward to the next // separator if (argsize > 0) { while (pos < argsize) { py_arg = Py_BuildValue("s", &argstr[pos]); if (!py_arg) goto error; if (PyList_Append(py_retlist, py_arg)) goto error; Py_DECREF(py_arg); pos = pos + strlen(&argstr[pos]) + 1; } } free(argstr); return py_retlist; error: Py_XDECREF(py_arg); Py_DECREF(py_retlist); if (argstr != NULL) free(argstr); return NULL; } PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { int64_t total_physmem; size_t size; struct uvmexp_sysctl uv; int physmem_mib[] = {CTL_HW, HW_PHYSMEM64}; int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2}; long pagesize = getpagesize(); size = sizeof(total_physmem); if (sysctl(physmem_mib, 2, &total_physmem, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } size = sizeof(uv); if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("KKKKKKKK", (unsigned long long) total_physmem, // total (unsigned long long) uv.free * pagesize, // free (unsigned long long) uv.active * pagesize, // active (unsigned long long) uv.inactive * pagesize, // inactive (unsigned long long) uv.wired * pagesize, // wired // taken from: // https://github.com/satterly/zabbix-stats/blob/master/src/libs/ // zbxsysinfo/netbsd/memory.c (unsigned long long) uv.filepages + uv.execpages * pagesize, // cached (unsigned long long) 0, // buffers (unsigned long long) 0 // shared ); } PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { uint64_t swap_total, swap_free; struct swapent *swdev; int nswap, i; nswap = swapctl(SWAP_NSWAP, 0, 0); if (nswap == 0) { // This means there's no swap partition. return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0); } swdev = calloc(nswap, sizeof(*swdev)); if (swdev == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (swapctl(SWAP_STATS, swdev, nswap) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } // Total things up. swap_total = swap_free = 0; for (i = 0; i < nswap; i++) { if (swdev[i].se_flags & SWF_ENABLE) { swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); swap_total += swdev[i].se_nblks; } } free(swdev); // Get swap in/out unsigned int total; size_t size = sizeof(total); struct uvmexp_sysctl uv; int mib[] = {CTL_VM, VM_UVMEXP2}; long pagesize = getpagesize(); size = sizeof(uv); if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } return Py_BuildValue("(LLLll)", swap_total * DEV_BSIZE, (swap_total - swap_free) * DEV_BSIZE, swap_free * DEV_BSIZE, (long) uv.pgswapin * pagesize, // swap in (long) uv.pgswapout * pagesize); // swap out error: free(swdev); } PyObject * psutil_proc_num_fds(PyObject *self, PyObject *args) { long pid; int cnt; struct kinfo_file *freep; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; } free(freep); return Py_BuildValue("i", cnt); } PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { static int maxcpus; int mib[3]; int ncpu; size_t len; size_t size; int i; PyObject *py_cputime = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; // 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(PyExc_OSError); goto error; } uint64_t cpu_time[CPUSTATES]; for (i = 0; i < ncpu; i++) { // per-cpu info mib[0] = CTL_KERN; mib[1] = KERN_CP_TIME; mib[2] = i; size = sizeof(cpu_time); if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { warn("failed to get kern.cptime2"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } py_cputime = 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); 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; } PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { int i, dk_ndrive, mib[3]; size_t len; struct io_sysctl *stats; PyObject *py_disk_info = NULL; PyObject *py_retdict = PyDict_New(); if (py_retdict == NULL) return NULL; mib[0] = CTL_HW; mib[1] = HW_IOSTATS; mib[2] = sizeof(struct io_sysctl); len = 0; if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) { warn("can't get HW_IOSTATS"); PyErr_SetFromErrno(PyExc_OSError); goto error; } dk_ndrive = (int)(len / sizeof(struct io_sysctl)); stats = malloc(len); if (stats == NULL) { PyErr_NoMemory(); goto error; } if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (i = 0; i < dk_ndrive; i++) { py_disk_info = Py_BuildValue( "(KKKKLL)", stats[i].rxfer, stats[i].wxfer, stats[i].rbytes, stats[i].wbytes, // assume half read - half writes. // TODO: why? (long long) PSUTIL_KPT2DOUBLE(stats[i].time) / 2, (long long) PSUTIL_KPT2DOUBLE(stats[i].time) / 2); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } free(stats); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (stats != NULL) free(stats); return NULL; } psutil-3.4.2/psutil/arch/bsd/netbsd_socks.c0000664000175000017500000004130512646126646022656 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola'. * Copyright (c) 2015, Ryo ONODERA. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // a signaler for connections without an actual status int PSUTIL_CONN_NONE = 128; // Address family filter enum af_filter { INET, INET4, INET6, TCP, TCP4, TCP6, UDP, UDP4, UDP6, UNIX, ALL, }; // kinfo_file results struct kif { SLIST_ENTRY(kif) kifs; struct kinfo_file *kif; }; // kinfo_file results list SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead); // kinfo_pcb results struct kpcb { SLIST_ENTRY(kpcb) kpcbs; struct kinfo_pcb *kpcb; }; // kinfo_pcb results list SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead); static void kiflist_init(void); static void kiflist_clear(void); static void kpcblist_init(void); static void kpcblist_clear(void); static int get_files(void); static int get_sockets(const char *name); static void get_info(int aff); // Initialize kinfo_file results list static void kiflist_init(void) { SLIST_INIT(&kihead); return; } // Clear kinfo_file results list static void kiflist_clear(void) { while (!SLIST_EMPTY(&kihead)) { SLIST_REMOVE_HEAD(&kihead, kifs); } return; } // Initialize kinof_pcb result list static void kpcblist_init(void) { SLIST_INIT(&kpcbhead); return; } // Clear kinof_pcb result list static void kpcblist_clear(void) { while (!SLIST_EMPTY(&kpcbhead)) { SLIST_REMOVE_HEAD(&kpcbhead, kpcbs); } return; } // Get all open files including socket static int get_files(void) { size_t len; int mib[6]; char *buf; off_t offset; int j; mib[0] = CTL_KERN; mib[1] = KERN_FILE2; mib[2] = KERN_FILE_BYFILE; mib[3] = 0; mib[4] = sizeof(struct kinfo_file); mib[5] = 0; if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) return -1; offset = len % sizeof(off_t); mib[5] = len / sizeof(struct kinfo_file); if ((buf = malloc(len + offset)) == NULL) return -1; if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) { free(buf); return -1; } len /= sizeof(struct kinfo_file); struct kinfo_file *ki = (struct kinfo_file *)(buf + offset); for (j = 0; j < len; j++) { struct kif *kif = malloc(sizeof(struct kif)); kif->kif = &ki[j]; SLIST_INSERT_HEAD(&kihead, kif, kifs); } #if 0 // debug struct kif *k; SLIST_FOREACH(k, &kihead, kifs) { printf("%d\n", k->kif->ki_pid); } #endif return 0; } // Get open sockets static int get_sockets(const char *name) { size_t namelen; int mib[8]; int ret, j; struct kinfo_pcb *pcb; size_t len; memset(mib, 0, sizeof(mib)); if (sysctlnametomib(name, mib, &namelen) == -1) return -1; if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) return -1; if ((pcb = malloc(len)) == NULL) { return -1; } memset(pcb, 0, len); mib[6] = sizeof(*pcb); mib[7] = len / sizeof(*pcb); if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) { free(pcb); return -1; } len /= sizeof(struct kinfo_pcb); struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb; for (j = 0; j < len; j++) { struct kpcb *kpcb = malloc(sizeof(struct kpcb)); kpcb->kpcb = &kp[j]; SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs); } #if 0 // debug struct kif *k; struct kpcb *k; SLIST_FOREACH(k, &kpcbhead, kpcbs) { printf("ki_type: %d\n", k->kpcb->ki_type); printf("ki_family: %d\n", k->kpcb->ki_family); } #endif return 0; } // Collect connections by PID PyObject * psutil_proc_connections(PyObject *self, PyObject *args) { PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; pid_t pid; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; kiflist_init(); kpcblist_init(); get_info(ALL); struct kif *k; SLIST_FOREACH(k, &kihead, kifs) { struct kpcb *kp; if (k->kif->ki_pid == pid) { SLIST_FOREACH(kp, &kpcbhead, kpcbs) { if (k->kif->ki_fdata == kp->kpcb->ki_sockaddr) { pid_t pid; int32_t fd; int32_t family; int32_t type; char laddr[PATH_MAX]; int32_t lport; char raddr[PATH_MAX]; int32_t rport; int32_t status; pid = k->kif->ki_pid; fd = k->kif->ki_fd; family = kp->kpcb->ki_family; type = kp->kpcb->ki_type; if (kp->kpcb->ki_family == AF_INET) { // IPv4 struct sockaddr_in *sin_src = (struct sockaddr_in *)&kp->kpcb->ki_src; struct sockaddr_in *sin_dst = (struct sockaddr_in *)&kp->kpcb->ki_dst; // source addr if (inet_ntop(AF_INET, &sin_src->sin_addr, laddr, sizeof(laddr)) != NULL) lport = ntohs(sin_src->sin_port); py_laddr = Py_BuildValue("(si)", laddr, lport); if (!py_laddr) goto error; // remote addr if (inet_ntop(AF_INET, &sin_dst->sin_addr, raddr, sizeof(raddr)) != NULL) rport = ntohs(sin_dst->sin_port); if (rport != 0) py_raddr = Py_BuildValue("(si)", raddr, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; // status if (kp->kpcb->ki_type == SOCK_STREAM) status = kp->kpcb->ki_tstate; else status = PSUTIL_CONN_NONE; // construct python tuple py_tuple = Py_BuildValue("(iiiNNi)", fd, AF_INET, type, py_laddr, py_raddr, status); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } else if (kp->kpcb->ki_family == AF_INET6) { // IPv6 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)&kp->kpcb->ki_src; struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)&kp->kpcb->ki_dst; // local addr if (inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr, sizeof(laddr)) != NULL) lport = ntohs(sin6_src->sin6_port); py_laddr = Py_BuildValue("(si)", laddr, lport); if (!py_laddr) goto error; // remote addr if (inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr, sizeof(raddr)) != NULL) rport = ntohs(sin6_dst->sin6_port); if (rport != 0) py_raddr = Py_BuildValue("(si)", raddr, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; // status if (kp->kpcb->ki_type == SOCK_STREAM) status = kp->kpcb->ki_tstate; else status = PSUTIL_CONN_NONE; // construct python tuple py_tuple = Py_BuildValue("(iiiNNi)", fd, AF_INET6, type, py_laddr, py_raddr, status); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } else if (kp->kpcb->ki_family == AF_UNIX) { // UNIX sockets struct sockaddr_un *sun_src = (struct sockaddr_un *)&kp->kpcb->ki_src; struct sockaddr_un *sun_dst = (struct sockaddr_un *)&kp->kpcb->ki_dst; strcpy(laddr, sun_src->sun_path); strcpy(raddr, sun_dst->sun_path); status = PSUTIL_CONN_NONE; py_tuple = Py_BuildValue("(iiissi)", fd, AF_UNIX, type, laddr, raddr, status); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } } }} } kiflist_clear(); kpcblist_clear(); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); return 0; } // Collect open file and connections static void get_info(int aff) { get_files(); switch (aff) { case INET: get_sockets("net.inet.tcp.pcblist"); get_sockets("net.inet.udp.pcblist"); get_sockets("net.inet6.tcp6.pcblist"); get_sockets("net.inet6.udp6.pcblist"); break; case INET4: get_sockets("net.inet.tcp.pcblist"); get_sockets("net.inet.udp.pcblist"); break; case INET6: get_sockets("net.inet6.tcp6.pcblist"); get_sockets("net.inet6.udp6.pcblist"); break; case TCP: get_sockets("net.inet.tcp.pcblist"); get_sockets("net.inet6.tcp6.pcblist"); break; case TCP4: get_sockets("net.inet.tcp.pcblist"); break; case TCP6: get_sockets("net.inet6.tcp6.pcblist"); break; case UDP: get_sockets("net.inet.udp.pcblist"); get_sockets("net.inet6.udp6.pcblist"); break; case UDP4: get_sockets("net.inet.udp.pcblist"); break; case UDP6: get_sockets("net.inet6.udp6.pcblist"); break; case UNIX: get_sockets("net.local.stream.pcblist"); get_sockets("net.local.seqpacket.pcblist"); get_sockets("net.local.dgram.pcblist"); break; case ALL: get_sockets("net.inet.tcp.pcblist"); get_sockets("net.inet.udp.pcblist"); get_sockets("net.inet6.tcp6.pcblist"); get_sockets("net.inet6.udp6.pcblist"); get_sockets("net.local.stream.pcblist"); get_sockets("net.local.seqpacket.pcblist"); get_sockets("net.local.dgram.pcblist"); break; } return; } // Collect system wide connections by address family filter PyObject * psutil_net_connections(PyObject *self, PyObject *args) { PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; if (py_retlist == NULL) return NULL; kiflist_init(); kpcblist_init(); get_info(ALL); struct kif *k; SLIST_FOREACH(k, &kihead, kifs) { struct kpcb *kp; SLIST_FOREACH(kp, &kpcbhead, kpcbs) { if (k->kif->ki_fdata == kp->kpcb->ki_sockaddr) { pid_t pid; int32_t fd; int32_t family; int32_t type; char laddr[PATH_MAX]; int32_t lport; char raddr[PATH_MAX]; int32_t rport; int32_t status; pid = k->kif->ki_pid; fd = k->kif->ki_fd; family = kp->kpcb->ki_family; type = kp->kpcb->ki_type; if (kp->kpcb->ki_family == AF_INET) { // IPv4 struct sockaddr_in *sin_src = (struct sockaddr_in *)&kp->kpcb->ki_src; struct sockaddr_in *sin_dst = (struct sockaddr_in *)&kp->kpcb->ki_dst; // local addr if (inet_ntop(AF_INET, &sin_src->sin_addr, laddr, sizeof(laddr)) != NULL) lport = ntohs(sin_src->sin_port); py_laddr = Py_BuildValue("(si)", laddr, lport); if (!py_laddr) goto error; // remote addr if (inet_ntop(AF_INET, &sin_dst->sin_addr, raddr, sizeof(raddr)) != NULL) rport = ntohs(sin_dst->sin_port); if (rport != 0) py_raddr = Py_BuildValue("(si)", raddr, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; // status if (kp->kpcb->ki_type == SOCK_STREAM) status = kp->kpcb->ki_tstate; else status = PSUTIL_CONN_NONE; // construct python tuple py_tuple = Py_BuildValue("(iiiNNii)", fd, AF_INET, type, py_laddr, py_raddr, status, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } else if (kp->kpcb->ki_family == AF_INET6) { // IPv6 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)&kp->kpcb->ki_src; struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)&kp->kpcb->ki_dst; // local addr if (inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr, sizeof(laddr)) != NULL) lport = ntohs(sin6_src->sin6_port); py_laddr = Py_BuildValue("(si)", laddr, lport); if (!py_laddr) goto error; // remote addr if (inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr, sizeof(raddr)) != NULL) rport = ntohs(sin6_dst->sin6_port); if (rport != 0) py_raddr = Py_BuildValue("(si)", raddr, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; // status if (kp->kpcb->ki_type == SOCK_STREAM) status = kp->kpcb->ki_tstate; else status = PSUTIL_CONN_NONE; // construct python tuple py_tuple = Py_BuildValue("(iiiNNii)", fd, AF_INET6, type, py_laddr, py_raddr, status, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } else if (kp->kpcb->ki_family == AF_UNIX) { // UNIX sockets struct sockaddr_un *sun_src = (struct sockaddr_un *)&kp->kpcb->ki_src; struct sockaddr_un *sun_dst = (struct sockaddr_un *)&kp->kpcb->ki_dst; strcpy(laddr, sun_src->sun_path); strcpy(raddr, sun_dst->sun_path); status = PSUTIL_CONN_NONE; py_tuple = Py_BuildValue("(iiissii)", fd, AF_UNIX, type, laddr, raddr, status, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; } } } } kiflist_clear(); kpcblist_clear(); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); return 0; } psutil-3.4.2/psutil/arch/bsd/freebsd_socks.c0000664000175000017500000004367712645372437023027 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 #include #include #include // for struct xsocket #include #include #include #include #include // for xinpcb struct #include #include #include #include #include #include // for struct xtcpcb #include // for TCP connection states #include // for inet_ntop() #include #include #include "freebsd.h" #include "freebsd_socks.h" #define HASHSIZE 1009 // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; static struct xfile *psutil_xfiles; static int psutil_nxfiles; // The tcplist fetching and walking is borrowed from netstat/inet.c. static char * psutil_fetch_tcplist(void) { char *buf; size_t len; for (;;) { if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } buf = malloc(len); if (buf == NULL) { PyErr_NoMemory(); return NULL; } if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) { free(buf); PyErr_SetFromErrno(PyExc_OSError); return NULL; } return buf; } } static int psutil_sockaddr_port(int family, struct sockaddr_storage *ss) { struct sockaddr_in6 *sin6; struct sockaddr_in *sin; if (family == AF_INET) { sin = (struct sockaddr_in *)ss; return (sin->sin_port); } else { sin6 = (struct sockaddr_in6 *)ss; return (sin6->sin6_port); } } static void * psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) { struct sockaddr_in6 *sin6; struct sockaddr_in *sin; if (family == AF_INET) { sin = (struct sockaddr_in *)ss; return (&sin->sin_addr); } else { sin6 = (struct sockaddr_in6 *)ss; return (&sin6->sin6_addr); } } static socklen_t psutil_sockaddr_addrlen(int family) { if (family == AF_INET) return (sizeof(struct in_addr)); else return (sizeof(struct in6_addr)); } static int psutil_sockaddr_matches(int family, int port, void *pcb_addr, struct sockaddr_storage *ss) { if (psutil_sockaddr_port(family, ss) != port) return (0); return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr, psutil_sockaddr_addrlen(family)) == 0); } static struct tcpcb * psutil_search_tcplist(char *buf, struct kinfo_file *kif) { struct tcpcb *tp; struct inpcb *inp; struct xinpgen *xig, *oxig; struct xsocket *so; oxig = xig = (struct xinpgen *)buf; for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); xig->xig_len > sizeof(struct xinpgen); xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { tp = &((struct xtcpcb *)xig)->xt_tp; inp = &((struct xtcpcb *)xig)->xt_inp; so = &((struct xtcpcb *)xig)->xt_socket; if (so->so_type != kif->kf_sock_type || so->xso_family != kif->kf_sock_domain || so->xso_protocol != kif->kf_sock_protocol) continue; if (kif->kf_sock_domain == AF_INET) { if (!psutil_sockaddr_matches( AF_INET, inp->inp_lport, &inp->inp_laddr, &kif->kf_sa_local)) continue; if (!psutil_sockaddr_matches( AF_INET, inp->inp_fport, &inp->inp_faddr, &kif->kf_sa_peer)) continue; } else { if (!psutil_sockaddr_matches( AF_INET6, inp->inp_lport, &inp->in6p_laddr, &kif->kf_sa_local)) continue; if (!psutil_sockaddr_matches( AF_INET6, inp->inp_fport, &inp->in6p_faddr, &kif->kf_sa_peer)) continue; } return (tp); } return NULL; } int psutil_populate_xfiles() { size_t len; if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) { PyErr_NoMemory(); return 0; } while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) { if (errno != ENOMEM) { PyErr_SetFromErrno(0); return 0; } len *= 2; if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) { PyErr_NoMemory(); return 0; } } if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) { PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch"); return 0; } psutil_nxfiles = len / sizeof *psutil_xfiles; return 1; } int psutil_get_pid_from_sock(int sock_hash) { struct xfile *xf; int hash, n; for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) { if (xf->xf_data == NULL) continue; hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); if (sock_hash == hash) return xf->xf_pid; } return -1; } // Reference: // https://gitorious.org/freebsd/freebsd/source/ // f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c int psutil_gather_inet(int proto, PyObject *py_retlist) { struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; struct xsocket *so; const char *varname = NULL; size_t len, bufsize; void *buf; int hash; int retry; int type; PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; switch (proto) { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; type = SOCK_STREAM; break; case IPPROTO_UDP: varname = "net.inet.udp.pcblist"; type = SOCK_DGRAM; break; } buf = NULL; bufsize = 8192; retry = 5; do { for (;;) { buf = realloc(buf, bufsize); if (buf == NULL) continue; // XXX len = bufsize; if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) break; if (errno != ENOMEM) { PyErr_SetFromErrno(0); goto error; } bufsize *= 2; } xig = (struct xinpgen *)buf; exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) { PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); goto error; } } while (xig->xig_gen != exig->xig_gen && retry--); for (;;) { int lport, rport, pid, status, family; xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; switch (proto) { case IPPROTO_TCP: xtp = (struct xtcpcb *)xig; if (xtp->xt_len != sizeof *xtp) { PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch"); goto error; } inp = &xtp->xt_inp; so = &xtp->xt_socket; status = xtp->xt_tp.t_state; break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; if (xip->xi_len != sizeof *xip) { PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch"); goto error; } inp = &xip->xi_inp; so = &xip->xi_socket; status = PSUTIL_CONN_NONE; break; default: PyErr_Format(PyExc_RuntimeError, "invalid proto"); goto error; } char lip[200], rip[200]; hash = (int)((uintptr_t)so->xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); if (pid < 0) continue; lport = ntohs(inp->inp_lport); rport = ntohs(inp->inp_fport); if (inp->inp_vflag & INP_IPV4) { family = AF_INET; inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip)); inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip)); } else if (inp->inp_vflag & INP_IPV6) { family = AF_INET6; inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip)); inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip)); } // construct python tuple/list py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; py_tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr, py_raddr, status, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(buf); return 1; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); free(buf); return 0; } int psutil_gather_unix(int proto, PyObject *py_retlist) { struct xunpgen *xug, *exug; struct xunpcb *xup; const char *varname = NULL; const char *protoname = NULL; size_t len; size_t bufsize; void *buf; int hash; int retry; int pid; struct sockaddr_un *sun; char path[PATH_MAX]; PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; switch (proto) { case SOCK_STREAM: varname = "net.local.stream.pcblist"; protoname = "stream"; break; case SOCK_DGRAM: varname = "net.local.dgram.pcblist"; protoname = "dgram"; break; } buf = NULL; bufsize = 8192; retry = 5; do { for (;;) { buf = realloc(buf, bufsize); if (buf == NULL) { PyErr_NoMemory(); goto error; } len = bufsize; if (sysctlbyname(varname, buf, &len, NULL, 0) == 0) break; if (errno != ENOMEM) { PyErr_SetFromErrno(0); goto error; } bufsize *= 2; } xug = (struct xunpgen *)buf; exug = (struct xunpgen *)(void *) ((char *)buf + len - sizeof *exug); if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) { PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch"); goto error; } } while (xug->xug_gen != exug->xug_gen && retry--); for (;;) { xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len); if (xug >= exug) break; xup = (struct xunpcb *)xug; if (xup->xu_len != sizeof *xup) goto error; hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE); pid = psutil_get_pid_from_sock(hash); if (pid < 0) continue; sun = (struct sockaddr_un *)&xup->xu_addr; snprintf(path, sizeof(path), "%.*s", (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); py_tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None, PSUTIL_CONN_NONE, pid); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_INCREF(Py_None); } free(buf); return 1; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); free(buf); return 0; } PyObject* psutil_net_connections(PyObject* self, PyObject* args) { // Return system-wide open connections. PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (psutil_populate_xfiles() != 1) goto error; if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0) goto error; if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0) goto error; if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0) goto error; if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0) goto error; free(psutil_xfiles); return py_retlist; error: Py_DECREF(py_retlist); free(psutil_xfiles); return NULL; } PyObject * psutil_proc_connections(PyObject *self, PyObject *args) { // Return connections opened by process. long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; char *tcplist = NULL; struct tcpcb *tcp; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; PyObject *py_family = NULL; PyObject *py_type = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) goto error; if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; } tcplist = psutil_fetch_tcplist(); if (tcplist == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } for (i = 0; i < cnt; i++) { int lport, rport, state; char lip[200], rip[200]; char path[PATH_MAX]; int inseq; py_tuple = NULL; py_laddr = NULL; py_raddr = NULL; kif = &freep[i]; if (kif->kf_type == KF_TYPE_SOCKET) { // apply filters py_family = PyLong_FromLong((long)kif->kf_sock_domain); inseq = PySequence_Contains(py_af_filter, py_family); Py_DECREF(py_family); if (inseq == 0) continue; py_type = PyLong_FromLong((long)kif->kf_sock_type); inseq = PySequence_Contains(py_type_filter, py_type); Py_DECREF(py_type); if (inseq == 0) continue; // IPv4 / IPv6 socket if ((kif->kf_sock_domain == AF_INET) || (kif->kf_sock_domain == AF_INET6)) { // fill status state = PSUTIL_CONN_NONE; if (kif->kf_sock_type == SOCK_STREAM) { tcp = psutil_search_tcplist(tcplist, kif); if (tcp != NULL) state = (int)tcp->t_state; } // build addr and port inet_ntop( kif->kf_sock_domain, psutil_sockaddr_addr(kif->kf_sock_domain, &kif->kf_sa_local), lip, sizeof(lip)); inet_ntop( kif->kf_sock_domain, psutil_sockaddr_addr(kif->kf_sock_domain, &kif->kf_sa_peer), rip, sizeof(rip)); lport = htons(psutil_sockaddr_port(kif->kf_sock_domain, &kif->kf_sa_local)); rport = htons(psutil_sockaddr_port(kif->kf_sock_domain, &kif->kf_sa_peer)); // construct python tuple/list py_laddr = Py_BuildValue("(si)", lip, lport); if (!py_laddr) goto error; if (rport != 0) py_raddr = Py_BuildValue("(si)", rip, rport); else py_raddr = Py_BuildValue("()"); if (!py_raddr) goto error; py_tuple = Py_BuildValue( "(iiiNNi)", kif->kf_fd, kif->kf_sock_domain, kif->kf_sock_type, py_laddr, py_raddr, state ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } // UNIX socket else if (kif->kf_sock_domain == AF_UNIX) { struct sockaddr_un *sun; sun = (struct sockaddr_un *)&kif->kf_sa_local; snprintf( path, sizeof(path), "%.*s", (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); py_tuple = Py_BuildValue( "(iiisOi)", kif->kf_fd, kif->kf_sock_domain, kif->kf_sock_type, path, Py_None, PSUTIL_CONN_NONE ); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_INCREF(Py_None); } } } free(freep); free(tcplist); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); Py_DECREF(py_retlist); if (freep != NULL) free(freep); if (tcplist != NULL) free(tcplist); return NULL; } psutil-3.4.2/psutil/arch/bsd/freebsd_socks.h0000644000175000017500000000051412633611503022774 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 PyObject* psutil_proc_connections(PyObject* self, PyObject* args); PyObject* psutil_net_connections(PyObject* self, PyObject* args); psutil-3.4.2/psutil/arch/bsd/netbsd.h0000664000175000017500000000222612645412301021441 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include typedef struct kinfo_proc2 kinfo_proc; int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc); struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt); int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); char *psutil_get_cmd_args(pid_t pid, size_t *argsize); PyObject * psutil_get_cmdline(pid_t pid); int psutil_pid_exists(pid_t pid); int psutil_raise_ad_or_nsp(long pid); // PyObject *psutil_proc_threads(PyObject *self, PyObject *args); PyObject *psutil_virtual_mem(PyObject *self, PyObject *args); PyObject *psutil_swap_mem(PyObject *self, PyObject *args); PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args); PyObject *psutil_proc_connections(PyObject *self, PyObject *args); PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args); PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); PyObject* psutil_proc_exe(PyObject* self, PyObject* args); PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args); psutil-3.4.2/psutil/arch/bsd/freebsd.c0000664000175000017500000006421512647677260021620 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Helper functions related to fetching process information. * Used by _psutil_bsd module methods. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // needed for vmtotal struct #include // for swap mem #include // process open files, shared libs (kinfo_getvmmap), cwd #include #include "freebsd.h" #include "../../_psutil_common.h" #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) #define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * (uint32_t) \ (bt.frac >> 32) ) >> 32 ) / 1000000) #ifndef _PATH_DEVNULL #define _PATH_DEVNULL "/dev/null" #endif // ============================================================================ // Utility functions // ============================================================================ int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { // Fills a kinfo_proc struct based on process pid. 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; } int psutil_raise_ad_or_nsp(long pid) { // Set exception to AccessDenied if pid exists else NoSuchProcess. int ret; ret = psutil_pid_exists(pid); if (ret == 0) NoSuchProcess(); else if (ret == 1) AccessDenied(); return ret; } // remove spaces from string static void psutil_remove_spaces(char *str) { char *p1 = str; char *p2 = str; do while (*p2 == ' ') p2++; while ((*p1++ = *p2++)); } // ============================================================================ // APIS // ============================================================================ int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { // Returns a list of all BSD processes on the system. This routine // allocates the list and puts it in *procList and a count of the // number of entries in *procCount. You are responsible for freeing // this list (use "free" from System framework). // On success, the function returns 0. // On error, the function returns a BSD errno value. int err; struct kinfo_proc *result; int done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); *procCount = 0; /* * We start by calling sysctl with result == NULL and length == 0. * That will succeed, and set length to the appropriate length. * We then allocate a buffer of that size and call sysctl again * with that buffer. If that succeeds, we're done. If that fails * with ENOMEM, we have to throw away our buffer and loop. Note * that the loop causes use to call sysctl with NULL again; this * is necessary because the ENOMEM failure case sets length to * the amount of data returned, not the amount of data that * could have been returned. */ result = NULL; done = 0; do { assert(result == NULL); // Call sysctl with a NULL buffer. length = 0; err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); if (err == -1) err = errno; // Allocate an appropriately sized buffer based on the results // from the previous call. if (err == 0) { result = malloc(length); if (result == NULL) err = ENOMEM; } // Call sysctl again with the new buffer. If we get an ENOMEM // error, toss away our buffer and start again. if (err == 0) { err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0); if (err == -1) err = errno; if (err == 0) { done = 1; } else if (err == ENOMEM) { assert(result != NULL); free(result); result = NULL; err = 0; } } } while (err == 0 && ! done); // Clean up and establish post conditions. if (err != 0 && result != NULL) { free(result); result = NULL; } *procList = result; *procCount = length / sizeof(struct kinfo_proc); assert((err == 0) == (*procList != NULL)); return err; } /* * XXX no longer used; it probably makese sense to remove it. * Borrowed from psi Python System Information project * * Get command arguments and environment variables. * * Based on code from ps. * * Returns: * 0 for success; * -1 for failure (Exception raised); * 1 for insufficient privileges. */ static char *psutil_get_cmd_args(long pid, size_t *argsize) { int mib[4], argmax; size_t size = sizeof(argmax); char *procargs = NULL; // Get the maximum process arguments size. mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof(argmax); if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) return NULL; // Allocate space for the arguments. procargs = (char *)malloc(argmax); if (procargs == NULL) { PyErr_NoMemory(); return NULL; } /* * Make a sysctl() call to get the raw argument space of the process. */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_ARGS; mib[3] = pid; size = argmax; if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) { free(procargs); return NULL; // Insufficient privileges } // return string and set the length of arguments *argsize = size; return procargs; } // returns the command line as a python list object PyObject * psutil_get_cmdline(long pid) { char *argstr = NULL; int pos = 0; size_t argsize = 0; PyObject *py_retlist = Py_BuildValue("[]"); PyObject *py_arg = NULL; if (pid < 0) return py_retlist; argstr = psutil_get_cmd_args(pid, &argsize); if (argstr == NULL) goto error; // args are returned as a flattened string with \0 separators between // arguments add each string to the list then step forward to the next // separator if (argsize > 0) { while (pos < argsize) { py_arg = Py_BuildValue("s", &argstr[pos]); if (!py_arg) goto error; if (PyList_Append(py_retlist, py_arg)) goto error; Py_DECREF(py_arg); pos = pos + strlen(&argstr[pos]) + 1; } } free(argstr); return py_retlist; error: Py_XDECREF(py_arg); Py_DECREF(py_retlist); if (argstr != NULL) free(argstr); return NULL; } /* * Return 1 if PID exists in the current process list, else 0, -1 * on error. * TODO: this should live in _psutil_posix.c but for some reason if I * move it there I get a "include undefined symbol" error. */ int psutil_pid_exists(long pid) { int ret; if (pid < 0) return 0; ret = kill(pid , 0); if (ret == 0) return 1; else { if (ret == ESRCH) return 0; else if (ret == EPERM) return 1; else { PyErr_SetFromErrno(PyExc_OSError); return -1; } } } /* * Return process pathname executable. * Thanks to Robert N. M. Watson: * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT */ PyObject * psutil_proc_exe(PyObject *self, PyObject *args) { long pid; char pathname[PATH_MAX]; int error; int mib[4]; int ret; size_t size; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; 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; } if (size == 0 || strlen(pathname) == 0) { ret = psutil_pid_exists(pid); if (ret == -1) return NULL; else if (ret == 0) return NoSuchProcess(); else strcpy(pathname, ""); } return Py_BuildValue("s", pathname); } PyObject * psutil_proc_num_threads(PyObject *self, PyObject *args) { // Return number of threads used by process as a Python integer. long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; return Py_BuildValue("l", (long)kp.ki_numthreads); } PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { // 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 long pid; int mib[4]; struct kinfo_proc *kip = NULL; struct kinfo_proc *kipp = NULL; int error; unsigned int i; size_t size; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return 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_NoMemory(); 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]; py_tuple = Py_BuildValue("Idd", kipp->ki_tid, PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_utime), PSUTIL_TV2DOUBLE(kipp->ki_rusage.ru_stime)); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(kip); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (kip != NULL) free(kip); return NULL; } PyObject * psutil_cpu_count_phys(PyObject *self, PyObject *args) { // Return an XML string from which we'll determine the number of // physical CPU cores in the system. void *topology = NULL; size_t size = 0; PyObject *py_str; if (sysctlbyname("kern.sched.topology_spec", NULL, &size, NULL, 0)) goto error; topology = malloc(size); if (!topology) { PyErr_NoMemory(); return NULL; } if (sysctlbyname("kern.sched.topology_spec", topology, &size, NULL, 0)) goto error; py_str = Py_BuildValue("s", topology); free(topology); return py_str; error: if (topology != NULL) free(topology); Py_RETURN_NONE; } /* * Return virtual memory usage statistics. */ PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { unsigned long total; unsigned int active, inactive, wired, cached, free; size_t size = sizeof(total); struct vmtotal vm; int mib[] = {CTL_VM, VM_METER}; long pagesize = getpagesize(); #if __FreeBSD_version > 702101 long buffers; #else int buffers; #endif size_t buffers_size = sizeof(buffers); if (sysctlbyname("hw.physmem", &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, &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, (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(PyExc_OSError); return NULL; } PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { // Return swap memory stats (see 'swapinfo' cmdline tool) kvm_t *kd; struct kvm_swap kvmsw[1]; unsigned int swapin, swapout, nodein, nodeout; size_t size = sizeof(unsigned int); kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open failed"); if (kd == NULL) { PyErr_SetString(PyExc_RuntimeError, "kvm_open failed"); return NULL; } if (kvm_getswapinfo(kd, kvmsw, 1, 0) < 0) { kvm_close(kd); PyErr_SetString(PyExc_RuntimeError, "kvm_getswapinfo failed"); return NULL; } kvm_close(kd); 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(PyExc_OSError); return NULL; } #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { long pid; struct kinfo_file *freep = NULL; struct kinfo_file *kif; struct kinfo_proc kipp; PyObject *py_path = NULL; int i, cnt; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_kinfo_proc(pid, &kipp) == -1) goto error; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; } for (i = 0; i < cnt; i++) { kif = &freep[i]; if (kif->kf_fd == KF_FD_TYPE_CWD) { py_path = Py_BuildValue("s", kif->kf_path); if (!py_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 (py_path == NULL) py_path = Py_BuildValue("s", ""); free(freep); return py_path; error: Py_XDECREF(py_path); if (freep != NULL) free(freep); return NULL; } #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 PyObject * psutil_proc_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 (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; } free(freep); return Py_BuildValue("i", cnt); } #endif PyObject * psutil_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; if (py_retlist == NULL) return NULL; // retrieve maxcpus value size = sizeof(maxcpus); if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { Py_DECREF(py_retlist); PyErr_SetFromErrno(PyExc_OSError); 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(PyExc_OSError); goto error; } // per-cpu info size = sizeof(cpu_time); if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); 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; } PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { int i; struct statinfo stats; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; if (devstat_checkversion(NULL) < 0) { PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed"); goto error; } stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); if (stats.dinfo == NULL) { PyErr_NoMemory(); goto error; } 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) PSUTIL_BT2MSEC(current.duration[DEVSTAT_READ]), // r time (long long) PSUTIL_BT2MSEC(current.duration[DEVSTAT_WRITE]) // w time ); // finished transactions 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; } PyObject * psutil_proc_memory_maps(PyObject *self, PyObject *args) { // Return a list of tuples for every process memory maps. //'procstat' cmdline utility has been used as an example. long pid; int ptrwidth; int i, cnt; char addr[1000]; char perms[4]; const char *path; struct kinfo_proc kp; struct kinfo_vmentry *freep = NULL; struct kinfo_vmentry *kve; ptrwidth = 2 * sizeof(void *); PyObject *py_tuple = NULL; PyObject *py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_kinfo_proc(pid, &kp) == -1) goto error; freep = kinfo_getvmmap(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; } for (i = 0; i < cnt; i++) { py_tuple = 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); psutil_remove_spaces(addr); 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; } py_tuple = 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 (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(freep); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (freep != NULL) free(freep); return NULL; } PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) { // Get process CPU affinity. // Reference: // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c long pid; int ret; int i; cpuset_t mask; PyObject* py_retlist; PyObject* py_cpu_num; if (!PyArg_ParseTuple(args, "i", &pid)) return NULL; ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, sizeof(mask), &mask); if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } py_retlist = PyList_New(0); if (py_retlist == NULL) return NULL; for (i = 0; i < CPU_SETSIZE; i++) { if (CPU_ISSET(i, &mask)) { py_cpu_num = Py_BuildValue("i", i); if (py_cpu_num == NULL) goto error; if (PyList_Append(py_retlist, py_cpu_num)) goto error; } } return py_retlist; error: Py_XDECREF(py_cpu_num); Py_DECREF(py_retlist); return NULL; } PyObject * psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { // Set process CPU affinity. // Reference: // http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c long pid; int i; int seq_len; int ret; cpuset_t cpu_set; PyObject *py_cpu_set; PyObject *py_cpu_seq = NULL; if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) return NULL; py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); if (!py_cpu_seq) return NULL; seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); // calculate the mask CPU_ZERO(&cpu_set); for (i = 0; i < seq_len; i++) { PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); #if PY_MAJOR_VERSION >= 3 long value = PyLong_AsLong(item); #else long value = PyInt_AsLong(item); #endif if (value == -1 && PyErr_Occurred()) goto error; CPU_SET(value, &cpu_set); } // set affinity ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid, sizeof(cpu_set), &cpu_set); if (ret != 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } Py_DECREF(py_cpu_seq); Py_RETURN_NONE; error: if (py_cpu_seq != NULL) Py_DECREF(py_cpu_seq); return NULL; } psutil-3.4.2/psutil/arch/bsd/openbsd.c0000664000175000017500000005271412645411704021624 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, Giampaolo Rodola', Landry Breuil. * All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Platform-specific module methods for OpenBSD. */ #include #include #include #include #include #include #include #include #include #include #include #include #include // for VFS_* #include // for swap_mem #include // for vmtotal struct #include #include // connection stuff #include // for NI_MAXHOST #include #include // for CPUSTATES & CP_* #define _KERNEL // for DTYPE_* #include #undef _KERNEL #include // struct diskstats #include // for inet_ntoa() #include // for warn() & err() #include "openbsd.h" #include "../../_psutil_common.h" #define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0) #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) // a signaler for connections without an actual status int PSUTIL_CONN_NONE = 128; // ============================================================================ // Utility functions // ============================================================================ int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) { // Fills a kinfo_proc struct based on process pid. int ret; int mib[6]; size_t size = sizeof(struct kinfo_proc); mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; mib[4] = size; mib[5] = 1; ret = sysctl((int*)mib, 6, proc, &size, NULL, 0); if (ret == -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; } struct kinfo_file * kinfo_getfile(long pid, int* cnt) { // Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an // int as arg and returns an array with cnt struct kinfo_file. int mib[6]; size_t len; struct kinfo_file* kf; mib[0] = CTL_KERN; mib[1] = KERN_FILE; mib[2] = KERN_FILE_BYPID; mib[3] = (int) pid; mib[4] = sizeof(struct kinfo_file); mib[5] = 0; /* get the size of what would be returned */ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if ((kf = malloc(len)) == NULL) { PyErr_NoMemory(); return NULL; } mib[5] = (int)(len / sizeof(struct kinfo_file)); if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } *cnt = (int)(len / sizeof(struct kinfo_file)); return kf; } int psutil_pid_exists(long pid) { // Return 1 if PID exists in the current process list, else 0, -1 // on error. // TODO: this should live in _psutil_posix.c but for some reason if I // move it there I get a "include undefined symbol" error. int ret; if (pid < 0) return 0; ret = kill(pid , 0); if (ret == 0) return 1; else { if (ret == ESRCH) return 0; else if (ret == EPERM) return 1; else { PyErr_SetFromErrno(PyExc_OSError); return -1; } } } int psutil_raise_ad_or_nsp(long pid) { // Set exception to AccessDenied if pid exists else NoSuchProcess. if (psutil_pid_exists(pid) == 0) NoSuchProcess(); else AccessDenied(); return 0; } // ============================================================================ // APIS // ============================================================================ int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { // Returns a list of all BSD processes on the system. This routine // allocates the list and puts it in *procList and a count of the // number of entries in *procCount. You are responsible for freeing // this list (use "free" from System framework). // On success, the function returns 0. // On error, the function returns a BSD errno value. struct kinfo_proc *result; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. char errbuf[_POSIX2_LINE_MAX]; int cnt; kvm_t *kd; assert(procList != NULL); assert(*procList == NULL); assert(procCount != NULL); kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); if (kd == NULL) { return errno; } result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt); if (result == NULL) { kvm_close(kd); err(1, NULL); return errno; } *procCount = (size_t)cnt; size_t mlen = cnt * sizeof(struct kinfo_proc); if ((*procList = malloc(mlen)) == NULL) { kvm_close(kd); err(1, NULL); return errno; } memcpy(*procList, result, mlen); assert(*procList != NULL); kvm_close(kd); return 0; } char ** _psutil_get_argv(long pid) { static char **argv; int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV}; size_t argv_size = 128; /* Loop and reallocate until we have enough space to fit argv. */ for (;; argv_size *= 2) { if ((argv = realloc(argv, argv_size)) == NULL) err(1, NULL); if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0) return argv; if (errno == ESRCH) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if (errno != ENOMEM) err(1, NULL); } } // returns the command line as a python list object PyObject * psutil_get_cmdline(long pid) { static char **argv; char **p; PyObject *py_arg = NULL; PyObject *py_retlist = Py_BuildValue("[]"); if (!py_retlist) return NULL; if (pid < 0) return py_retlist; if ((argv = _psutil_get_argv(pid)) == NULL) goto error; for (p = argv; *p != NULL; p++) { py_arg = Py_BuildValue("s", *p); if (!py_arg) goto error; if (PyList_Append(py_retlist, py_arg)) goto error; Py_DECREF(py_arg); } return py_retlist; error: Py_XDECREF(py_arg); Py_DECREF(py_retlist); return NULL; } PyObject * psutil_proc_threads(PyObject *self, PyObject *args) { // OpenBSD reference: // https://github.com/janmojzis/pstree/blob/master/proc_kvm.c // Note: this requires root access, else it will fail trying // to access /dev/kmem. long pid; kvm_t *kd = NULL; int nentries, i; char errbuf[4096]; struct kinfo_proc *kp; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); if (! kd) { if (strstr(errbuf, "Permission denied") != NULL) AccessDenied(); else PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() failed"); goto error; } kp = kvm_getprocs( kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid, sizeof(*kp), &nentries); if (! kp) { if (strstr(errbuf, "Permission denied") != NULL) AccessDenied(); else PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() failed"); goto error; } for (i = 0; i < nentries; i++) { if (kp[i].p_tid < 0) continue; if (kp[i].p_pid == pid) { py_tuple = Py_BuildValue( "Idd", kp[i].p_tid, PSUTIL_KPT2DOUBLE(kp[i].p_uutime), PSUTIL_KPT2DOUBLE(kp[i].p_ustime)); if (py_tuple == NULL) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } kvm_close(kd); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (kd != NULL) kvm_close(kd); return NULL; } PyObject * psutil_virtual_mem(PyObject *self, PyObject *args) { int64_t total_physmem; int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT}; int physmem_mib[] = {CTL_HW, HW_PHYSMEM64}; int vmmeter_mib[] = {CTL_VM, VM_METER}; size_t size; struct uvmexp uvmexp; struct bcachestats bcstats; struct vmtotal vmdata; long pagesize = getpagesize(); size = sizeof(total_physmem); if (sysctl(physmem_mib, 2, &total_physmem, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } size = sizeof(uvmexp); if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } size = sizeof(bcstats); if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } size = sizeof(vmdata); if (sysctl(vmmeter_mib, 2, &vmdata, &size, NULL, 0) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("KKKKKKKK", // Note: many programs calculate total memory as // "uvmexp.npages * pagesize" but this is incorrect and does not // match "sysctl | grep hw.physmem". (unsigned long long) total_physmem, (unsigned long long) uvmexp.free * pagesize, (unsigned long long) uvmexp.active * pagesize, (unsigned long long) uvmexp.inactive * pagesize, (unsigned long long) uvmexp.wired * pagesize, // this is how "top" determines it (unsigned long long) bcstats.numbufpages * pagesize, // cached (unsigned long long) 0, // buffers (unsigned long long) vmdata.t_vmshr + vmdata.t_rmshr // shared ); } PyObject * psutil_swap_mem(PyObject *self, PyObject *args) { uint64_t swap_total, swap_free; struct swapent *swdev; int nswap, i; if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) { PyErr_NoMemory(); return NULL; } if (swapctl(SWAP_STATS, swdev, nswap) == -1) { PyErr_SetFromErrno(PyExc_OSError); goto error; } // Total things up. swap_total = swap_free = 0; for (i = 0; i < nswap; i++) { if (swdev[i].se_flags & SWF_ENABLE) { swap_free += (swdev[i].se_nblks - swdev[i].se_inuse); swap_total += swdev[i].se_nblks; } } free(swdev); return Py_BuildValue("(LLLII)", swap_total * DEV_BSIZE, (swap_total - swap_free) * DEV_BSIZE, swap_free * DEV_BSIZE, // swap in / swap out is not supported as the // swapent struct does not provide any info // about it. 0, 0); error: free(swdev); return NULL; } PyObject * psutil_proc_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 (psutil_kinfo_proc(pid, &kipp) == -1) return NULL; freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); return NULL; } free(freep); return Py_BuildValue("i", cnt); } PyObject * psutil_proc_cwd(PyObject *self, PyObject *args) { // Reference: // http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179 long pid; struct kinfo_proc kp; char path[MAXPATHLEN]; size_t pathlen = sizeof path; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_kinfo_proc(pid, &kp) == -1) return NULL; int name[] = { CTL_KERN, KERN_PROC_CWD, pid }; if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("s", path); } // see sys/kern/kern_sysctl.c lines 1100 and // usr.bin/fstat/fstat.c print_inet_details() static char * psutil_convert_ipv4(int family, uint32_t addr[4]) { struct in_addr a; memcpy(&a, addr, sizeof(a)); return inet_ntoa(a); } static char * psutil_inet6_addrstr(struct in6_addr *p) { struct sockaddr_in6 sin6; static char hbuf[NI_MAXHOST]; const int niflags = NI_NUMERICHOST; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *p; if (IN6_IS_ADDR_LINKLOCAL(p) && *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) { sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0; } if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, hbuf, sizeof(hbuf), NULL, 0, niflags)) return "invalid"; return hbuf; } PyObject * psutil_proc_connections(PyObject *self, PyObject *args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; char *tcplist = NULL; PyObject *py_retlist = PyList_New(0); PyObject *py_tuple = NULL; PyObject *py_laddr = NULL; PyObject *py_raddr = NULL; PyObject *py_af_filter = NULL; PyObject *py_type_filter = NULL; PyObject *py_family = NULL; PyObject *_type = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter)) goto error; if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } freep = kinfo_getfile(pid, &cnt); if (freep == NULL) { psutil_raise_ad_or_nsp(pid); goto error; } for (i = 0; i < cnt; i++) { int state; int lport; int rport; char addrbuf[NI_MAXHOST + 2]; int inseq; struct in6_addr laddr6; py_tuple = NULL; py_laddr = NULL; py_raddr = NULL; kif = &freep[i]; if (kif->f_type == DTYPE_SOCKET) { // apply filters py_family = PyLong_FromLong((long)kif->so_family); inseq = PySequence_Contains(py_af_filter, py_family); Py_DECREF(py_family); if (inseq == 0) continue; _type = PyLong_FromLong((long)kif->so_type); inseq = PySequence_Contains(py_type_filter, _type); Py_DECREF(_type); if (inseq == 0) continue; // IPv4 / IPv6 socket if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) { // fill status if (kif->so_type == SOCK_STREAM) state = kif->t_state; else state = PSUTIL_CONN_NONE; // ports lport = ntohs(kif->inp_lport); rport = ntohs(kif->inp_fport); // local address, IPv4 if (kif->so_family == AF_INET) { py_laddr = Py_BuildValue( "(si)", psutil_convert_ipv4(kif->so_family, kif->inp_laddru), lport); if (!py_laddr) goto error; } else { // local address, IPv6 memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6)); snprintf(addrbuf, sizeof(addrbuf), "%s", psutil_inet6_addrstr(&laddr6)); py_laddr = Py_BuildValue("(si)", addrbuf, lport); if (!py_laddr) goto error; } if (rport != 0) { // remote address, IPv4 if (kif->so_family == AF_INET) { py_raddr = Py_BuildValue( "(si)", psutil_convert_ipv4( kif->so_family, kif->inp_faddru), rport); } else { // remote address, IPv6 memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6)); snprintf(addrbuf, sizeof(addrbuf), "%s", psutil_inet6_addrstr(&laddr6)); py_raddr = Py_BuildValue("(si)", addrbuf, rport); if (!py_raddr) goto error; } } else { py_raddr = Py_BuildValue("()"); } if (!py_raddr) goto error; py_tuple = Py_BuildValue( "(iiiNNi)", kif->fd_fd, kif->so_family, kif->so_type, py_laddr, py_raddr, state); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } // UNIX socket else if (kif->so_family == AF_UNIX) { py_tuple = Py_BuildValue( "(iiisOi)", kif->fd_fd, kif->so_family, kif->so_type, kif->unp_path, Py_None, PSUTIL_CONN_NONE); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); Py_INCREF(Py_None); } } } free(freep); free(tcplist); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_laddr); Py_XDECREF(py_raddr); Py_DECREF(py_retlist); if (freep != NULL) free(freep); if (tcplist != NULL) free(tcplist); return NULL; } PyObject * psutil_per_cpu_times(PyObject *self, PyObject *args) { int mib[3]; int ncpu; size_t len; size_t size; int i; PyObject *py_retlist = PyList_New(0); PyObject *py_cputime = NULL; if (py_retlist == NULL) return NULL; // 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(PyExc_OSError); goto error; } uint64_t cpu_time[CPUSTATES]; for (i = 0; i < ncpu; i++) { // per-cpu info mib[0] = CTL_KERN; mib[1] = KERN_CPTIME2; mib[2] = i; size = sizeof(cpu_time); if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) { warn("failed to get kern.cptime2"); PyErr_SetFromErrno(PyExc_OSError); return NULL; } py_cputime = 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); 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; } PyObject * psutil_disk_io_counters(PyObject *self, PyObject *args) { int i, dk_ndrive, mib[3]; size_t len; struct diskstats *stats; PyObject *py_retdict = PyDict_New(); PyObject *py_disk_info = NULL; if (py_retdict == NULL) return NULL; mib[0] = CTL_HW; mib[1] = HW_DISKSTATS; len = 0; if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { warn("can't get hw.diskstats size"); PyErr_SetFromErrno(PyExc_OSError); goto error; } dk_ndrive = (int)(len / sizeof(struct diskstats)); stats = malloc(len); if (stats == NULL) { warn("can't malloc"); PyErr_NoMemory(); goto error; } if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) { warn("could not read hw.diskstats"); PyErr_SetFromErrno(PyExc_OSError); goto error; } for (i = 0; i < dk_ndrive; i++) { py_disk_info = Py_BuildValue( "(KKKKLL)", stats[i].ds_rxfer, stats[i].ds_wxfer, stats[i].ds_rbytes, stats[i].ds_wbytes, // assume half read - half writes. // TODO: why? (long long) PSUTIL_TV2DOUBLE(stats[i].ds_time) / 2, (long long) PSUTIL_TV2DOUBLE(stats[i].ds_time) / 2); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } free(stats); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (stats != NULL) free(stats); return NULL; } psutil-3.4.2/psutil/_psposix.py0000664000175000017500000001200212612743061020537 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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 errno import glob import os import sys import time from ._common import memoize from ._common import sdiskusage from ._common import usage_percent from ._compat import PY3 from ._compat import unicode class TimeoutExpired(Exception): pass def pid_exists(pid): """Check whether pid exists in the current process table.""" if pid == 0: # According to "man 2 kill" PID 0 has a special meaning: # it refers to <> so we don't want to go any further. # If we get here it means this UNIX platform *does* have # a process with id 0. return True try: os.kill(pid, 0) except OSError as err: if err.errno == errno.ESRCH: # ESRCH == No such process return False elif err.errno == errno.EPERM: # EPERM clearly means there's a process to deny access to return True else: # According to "man 2 kill" possible error values are # (EINVAL, EPERM, ESRCH) therefore we should never get # here. If we do let's be explicit in considering this # an error. raise err 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 timer() >= stop_at: raise TimeoutExpired() time.sleep(delay) return min(delay * 2, 0.04) timer = getattr(time, 'monotonic', time.time) if timeout is not None: def waitcall(): return os.waitpid(pid, os.WNOHANG) stop_at = timer() + timeout else: def waitcall(): return os.waitpid(pid, 0) delay = 0.0001 while True: try: retpid, status = waitcall() except OSError as err: 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 True: 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 disk_usage(path): """Return disk usage associated with path.""" try: st = os.statvfs(path) except UnicodeEncodeError: if not PY3 and isinstance(path, unicode): # this is a bug with os.statvfs() and unicode on # Python 2, see: # - https://github.com/giampaolo/psutil/issues/416 # - http://bugs.python.org/issue18695 try: path = path.encode(sys.getfilesystemencoding()) except UnicodeEncodeError: pass st = os.statvfs(path) else: raise 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 sdiskusage(total, used, free, percent) @memoize def _get_terminal_map(): ret = {} ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*') for name in ls: assert name not in ret try: ret[os.stat(name).st_rdev] = name except OSError as err: if err.errno != errno.ENOENT: raise return ret psutil-3.4.2/psutil/_psutil_sunos.h0000664000175000017500000000263612572074510021415 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 // processes static PyObject* psutil_proc_basic_info(PyObject* self, PyObject* args); static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_proc_cred(PyObject* self, PyObject* args); static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args); static PyObject* psutil_proc_name_and_args(PyObject* self, PyObject* args); static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args); static PyObject* psutil_proc_query_thread(PyObject* self, PyObject* args); // system static PyObject* psutil_boot_time(PyObject* self, PyObject* args); static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args); static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args); static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args); static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args); static PyObject* psutil_swap_mem(PyObject* self, PyObject* args); static PyObject* psutil_users(PyObject* self, PyObject* args); static PyObject* psutil_net_connections(PyObject* self, PyObject* args); static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); psutil-3.4.2/psutil/_psutil_posix.h0000664000175000017500000000103512572074510021400 0ustar giampaologiampaolo00000000000000/* * Copyright (c) 2009, 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 static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args); static PyObject* psutil_posix_getpriority(PyObject* self, PyObject* args); static PyObject* psutil_posix_setpriority(PyObject* self, PyObject* args); #if defined(__FreeBSD__) || defined(__APPLE__) static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args); #endif psutil-3.4.2/psutil/_pslinux.py0000664000175000017500000013672312646145360020562 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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 base64 import errno import functools import os import re import socket import struct import sys import traceback import warnings from collections import defaultdict from collections import namedtuple from . import _common from . import _psposix from . import _psutil_linux as cext from . import _psutil_posix as cext_posix from ._common import isfile_strict from ._common import memoize from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_UNKNOWN from ._common import path_exists_strict from ._common import supports_ipv6 from ._common import usage_percent from ._compat import b from ._compat import basestring from ._compat import long from ._compat import PY3 if sys.version_info >= (3, 4): import enum else: enum = None __extra__all__ = [ # 'PROCFS_PATH', # io prio constants "IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE", "IOPRIO_CLASS_IDLE", # connection status constants "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", ] # --- constants HAS_PRLIMIT = hasattr(cext, "linux_prlimit") # RLIMIT_* constants, not guaranteed to be present on all kernels if HAS_PRLIMIT: for name in dir(cext): if name.startswith('RLIM'): __extra__all__.append(name) # Number of clock ticks per second CLOCK_TICKS = os.sysconf("SC_CLK_TCK") PAGESIZE = os.sysconf("SC_PAGE_SIZE") BOOT_TIME = None # set later # Used when reading "big" files, namely /proc/{pid}/smaps and /proc/net/*. # On Python 2, using a buffer with open() for such files may result in a # speedup, see: https://github.com/giampaolo/psutil/issues/708 BIGGER_FILE_BUFFERING = -1 if PY3 else 8192 LITTLE_ENDIAN = sys.byteorder == 'little' if PY3: FS_ENCODING = sys.getfilesystemencoding() if enum is None: AF_LINK = socket.AF_PACKET else: AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': int(socket.AF_PACKET)}) AF_LINK = AddressFamily.AF_LINK # ioprio_* constants http://linux.die.net/man/2/ioprio_get if enum is None: IOPRIO_CLASS_NONE = 0 IOPRIO_CLASS_RT = 1 IOPRIO_CLASS_BE = 2 IOPRIO_CLASS_IDLE = 3 else: class IOPriority(enum.IntEnum): IOPRIO_CLASS_NONE = 0 IOPRIO_CLASS_RT = 1 IOPRIO_CLASS_BE = 2 IOPRIO_CLASS_IDLE = 3 globals().update(IOPriority.__members__) # taken from /fs/proc/array.c PROC_STATUSES = { "R": _common.STATUS_RUNNING, "S": _common.STATUS_SLEEPING, "D": _common.STATUS_DISK_SLEEP, "T": _common.STATUS_STOPPED, "t": _common.STATUS_TRACING_STOP, "Z": _common.STATUS_ZOMBIE, "X": _common.STATUS_DEAD, "x": _common.STATUS_DEAD, "K": _common.STATUS_WAKE_KILL, "W": _common.STATUS_WAKING } # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { "01": _common.CONN_ESTABLISHED, "02": _common.CONN_SYN_SENT, "03": _common.CONN_SYN_RECV, "04": _common.CONN_FIN_WAIT1, "05": _common.CONN_FIN_WAIT2, "06": _common.CONN_TIME_WAIT, "07": _common.CONN_CLOSE, "08": _common.CONN_CLOSE_WAIT, "09": _common.CONN_LAST_ACK, "0A": _common.CONN_LISTEN, "0B": _common.CONN_CLOSING } # set later from __init__.py NoSuchProcess = None ZombieProcess = None AccessDenied = None TimeoutExpired = None # --- utils def open_binary(fname, **kwargs): return open(fname, "rb", **kwargs) def open_text(fname, **kwargs): """On Python 3 opens a file in text mode by using fs encoding. On Python 2 this is just an alias for open(name, 'rt'). """ if PY3 and 'encoding' not in kwargs: kwargs['encoding'] = FS_ENCODING return open(fname, "rt", **kwargs) def get_procfs_path(): return sys.modules['psutil'].PROCFS_PATH def readlink(path): """Wrapper around os.readlink().""" assert isinstance(path, basestring), path path = os.readlink(path) # readlink() might return paths containing null bytes ('\x00') # resulting in "TypeError: must be encoded string without NULL # bytes, not str" errors when the string is passed to other # fs-related functions (os.*, open(), ...). # Apparently everything after '\x00' is garbage (we can have # ' (deleted)', 'new' and possibly others), see: # https://github.com/giampaolo/psutil/issues/717 path = path.split('\x00')[0] # Certain paths have ' (deleted)' appended. Usually this is # bogus as the file actually exists. Even if it doesn't we # don't care. if path.endswith(' (deleted)') and not path_exists_strict(path): path = path[:-10] return path # --- named tuples @memoize def set_scputimes_ntuple(procfs_path): """Return a namedtuple of variable fields depending on the CPU times available on this Linux kernel version which may be: (user, nice, system, idle, iowait, irq, softirq, [steal, [guest, [guest_nice]]]) """ global scputimes with open_binary('%s/stat' % procfs_path) as f: values = f.readline().split()[1:] fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq'] vlen = len(values) if vlen >= 8: # Linux >= 2.6.11 fields.append('steal') if vlen >= 9: # Linux >= 2.6.24 fields.append('guest') if vlen >= 10: # Linux >= 3.2.0 fields.append('guest_nice') scputimes = namedtuple('scputimes', fields) return scputimes try: scputimes = set_scputimes_ntuple("/proc") except Exception: # Don't want to crash at import time. traceback.print_exc() scputimes = namedtuple('scputimes', 'user system idle')(0.0, 0.0, 0.0) svmem = namedtuple( 'svmem', ['total', 'available', 'percent', 'used', 'free', 'active', 'inactive', 'buffers', 'cached']) pextmem = namedtuple('pextmem', 'rss vms shared text lib data dirty') pmmap_grouped = namedtuple( 'pmmap_grouped', ['path', 'rss', 'size', 'pss', 'shared_clean', 'shared_dirty', 'private_clean', 'private_dirty', 'referenced', 'anonymous', 'swap']) pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) # --- system memory def virtual_memory(): total, free, buffers, shared, _, _ = cext.linux_sysinfo() cached = active = inactive = None with open_binary('%s/meminfo' % get_procfs_path()) as f: for line in f: if line.startswith(b"Cached:"): cached = int(line.split()[1]) * 1024 elif line.startswith(b"Active:"): active = int(line.split()[1]) * 1024 elif line.startswith(b"Inactive:"): inactive = int(line.split()[1]) * 1024 if (cached is not None and active is not None and inactive is not None): break else: # we might get here when dealing with exotic Linux flavors, see: # https://github.com/giampaolo/psutil/issues/313 msg = "'cached', 'active' and 'inactive' memory stats couldn't " \ "be determined and were set to 0" warnings.warn(msg, RuntimeWarning) cached = active = inactive = 0 avail = free + buffers + cached used = total - free percent = usage_percent((total - avail), total, _round=1) return svmem(total, avail, percent, used, free, active, inactive, buffers, cached) def swap_memory(): _, _, _, _, total, free = cext.linux_sysinfo() used = total - free percent = usage_percent(used, total, _round=1) # get pgin/pgouts try: f = open_binary("%s/vmstat" % get_procfs_path()) except IOError as err: # see https://github.com/giampaolo/psutil/issues/722 msg = "'sin' and 'sout' swap memory stats couldn't " \ "be determined and were set to 0 (%s)" % str(err) warnings.warn(msg, RuntimeWarning) sin = sout = 0 else: with f: sin = sout = None for line in f: # values are expressed in 4 kilo bytes, we want # bytes instead if line.startswith(b'pswpin'): sin = int(line.split(b' ')[1]) * 4 * 1024 elif line.startswith(b'pswpout'): sout = int(line.split(b' ')[1]) * 4 * 1024 if sin is not None and sout is not None: break else: # we might get here when dealing with exotic Linux # flavors, see: # https://github.com/giampaolo/psutil/issues/313 msg = "'sin' and 'sout' swap memory stats couldn't " \ "be determined and were set to 0" warnings.warn(msg, RuntimeWarning) sin = sout = 0 return _common.sswap(total, used, free, percent, sin, sout) # --- CPUs def cpu_times(): """Return a named tuple representing the following system-wide CPU times: (user, nice, system, idle, iowait, irq, softirq [steal, [guest, [guest_nice]]]) Last 3 fields may not be available on all Linux kernel versions. """ procfs_path = get_procfs_path() set_scputimes_ntuple(procfs_path) with open_binary('%s/stat' % procfs_path) as f: values = f.readline().split() fields = values[1:len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] return scputimes(*fields) def per_cpu_times(): """Return a list of namedtuple representing the CPU times for every CPU available on the system. """ procfs_path = get_procfs_path() set_scputimes_ntuple(procfs_path) cpus = [] with open_binary('%s/stat' % procfs_path) as f: # get rid of the first line which refers to system wide CPU stats f.readline() for line in f: if line.startswith(b'cpu'): values = line.split() fields = values[1:len(scputimes._fields) + 1] fields = [float(x) / CLOCK_TICKS for x in fields] entry = scputimes(*fields) cpus.append(entry) return cpus def cpu_count_logical(): """Return the number of logical CPUs in the system.""" try: return os.sysconf("SC_NPROCESSORS_ONLN") except ValueError: # as a second fallback we try to parse /proc/cpuinfo num = 0 with open_binary('%s/cpuinfo' % get_procfs_path()) as f: for line in f: if line.lower().startswith(b'processor'): num += 1 # unknown format (e.g. amrel/sparc architectures), see: # https://github.com/giampaolo/psutil/issues/200 # try to parse /proc/stat as a last resort if num == 0: search = re.compile('cpu\d') with open_text('%s/stat' % get_procfs_path()) as f: for line in f: line = line.split(' ')[0] if search.match(line): num += 1 if num == 0: # mimic os.cpu_count() return None return num def cpu_count_physical(): """Return the number of physical cores in the system.""" mapping = {} current_info = {} with open_binary('%s/cpuinfo' % get_procfs_path()) as f: for line in f: line = line.strip().lower() if not line: # new section if (b'physical id' in current_info and b'cpu cores' in current_info): mapping[current_info[b'physical id']] = \ current_info[b'cpu cores'] current_info = {} else: # ongoing section if (line.startswith(b'physical id') or line.startswith(b'cpu cores')): key, value = line.split(b'\t:', 1) current_info[key] = int(value) # mimic os.cpu_count() return sum(mapping.values()) or None # --- other system functions def users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = cext.users() for item in rawlist: user, tty, hostname, tstamp, user_process = item # note: 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' or hostname == ':0': hostname = 'localhost' nt = _common.suser(user, tty or None, hostname, tstamp) retlist.append(nt) return retlist def boot_time(): """Return the system boot time expressed in seconds since the epoch.""" global BOOT_TIME with open_binary('%s/stat' % get_procfs_path()) as f: for line in f: if line.startswith(b'btime'): ret = float(line.strip().split()[1]) BOOT_TIME = ret return ret raise RuntimeError( "line 'btime' not found in %s/stat" % get_procfs_path()) # --- processes def pids(): """Returns a list of PIDs currently running on the system.""" return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()] def pid_exists(pid): """Check For the existence of a unix pid.""" return _psposix.pid_exists(pid) # --- network class _Ipv6UnsupportedError(Exception): pass class Connections: """A wrapper on top of /proc/net/* files, retrieving per-process and system-wide open connections (TCP, UDP, UNIX) similarly to "netstat -an". Note: in case of UNIX sockets we're only able to determine the local endpoint/path, not the one it's connected to. According to [1] it would be possible but not easily. [1] http://serverfault.com/a/417946 """ def __init__(self): 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) self.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), } self._procfs_path = None def get_proc_inodes(self, pid): inodes = defaultdict(list) for fd in os.listdir("%s/%s/fd" % (self._procfs_path, pid)): try: inode = readlink("%s/%s/fd/%s" % (self._procfs_path, pid, fd)) except OSError as err: # ENOENT == file which is gone in the meantime; # os.stat('/proc/%s' % self.pid) will be done later # to force NSP (if it's the case) if err.errno in (errno.ENOENT, errno.ESRCH): continue elif err.errno == errno.EINVAL: # not a link continue else: raise else: if inode.startswith('socket:['): # the process is using a socket inode = inode[8:][:-1] inodes[inode].append((pid, int(fd))) return inodes def get_all_inodes(self): inodes = {} for pid in pids(): try: inodes.update(self.get_proc_inodes(pid)) except OSError as err: # os.listdir() is gonna raise a lot of access denied # exceptions in case of unprivileged user; that's fine # as we'll just end up returning a connection with PID # and fd set to None anyway. # Both netstat -an and lsof does the same so it's # unlikely we can do any better. # ENOENT just means a PID disappeared on us. if err.errno not in ( errno.ENOENT, errno.ESRCH, errno.EPERM, errno.EACCES): raise return inodes def decode_address(self, 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) # this usually refers to a local socket in listen mode with # no end-points connected if not port: return () if PY3: ip = ip.encode('ascii') if family == socket.AF_INET: # see: https://github.com/giampaolo/psutil/issues/201 if LITTLE_ENDIAN: 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) try: # see: https://github.com/giampaolo/psutil/issues/201 if LITTLE_ENDIAN: 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))) except ValueError: # see: https://github.com/giampaolo/psutil/issues/623 if not supports_ipv6(): raise _Ipv6UnsupportedError else: raise return (ip, port) def process_inet(self, file, family, type_, inodes, filter_pid=None): """Parse /proc/net/tcp* and /proc/net/udp* files.""" if file.endswith('6') and not os.path.exists(file): # IPv6 not supported return with open_text(file, buffering=BIGGER_FILE_BUFFERING) as f: f.readline() # skip the first line for line in f: try: _, laddr, raddr, status, _, _, _, _, _, inode = \ line.split()[:10] except ValueError: raise RuntimeError( "error while parsing %s; malformed line %r" % ( file, line)) if inode in inodes: # # We assume inet sockets are unique, so we error # # out if there are multiple references to the # # same inode. We won't do this for UNIX sockets. # if len(inodes[inode]) > 1 and family != socket.AF_UNIX: # raise ValueError("ambiguos inode with multiple " # "PIDs references") pid, fd = inodes[inode][0] else: pid, fd = None, -1 if filter_pid is not None and filter_pid != pid: continue else: if type_ == socket.SOCK_STREAM: status = TCP_STATUSES[status] else: status = _common.CONN_NONE try: laddr = self.decode_address(laddr, family) raddr = self.decode_address(raddr, family) except _Ipv6UnsupportedError: continue yield (fd, family, type_, laddr, raddr, status, pid) def process_unix(self, file, family, inodes, filter_pid=None): """Parse /proc/net/unix files.""" # see: https://github.com/giampaolo/psutil/issues/675 kw = dict(errors='replace') if PY3 else dict() with open_text(file, buffering=BIGGER_FILE_BUFFERING, **kw) as f: f.readline() # skip the first line for line in f: tokens = line.split() try: _, _, _, _, type_, _, inode = tokens[0:7] except ValueError: raise RuntimeError( "error while parsing %s; malformed line %r" % ( file, line)) if inode in inodes: # With UNIX sockets we can have a single inode # referencing many file descriptors. pairs = inodes[inode] else: pairs = [(None, -1)] for pid, fd in pairs: if filter_pid is not None and filter_pid != pid: continue else: if len(tokens) == 8: path = tokens[-1] else: path = "" type_ = int(type_) raddr = None status = _common.CONN_NONE yield (fd, family, type_, path, raddr, status, pid) def retrieve(self, kind, pid=None): if kind not in self.tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in self.tmap]))) self._procfs_path = get_procfs_path() if pid is not None: inodes = self.get_proc_inodes(pid) if not inodes: # no connections for this process return [] else: inodes = self.get_all_inodes() ret = set() for f, family, type_ in self.tmap[kind]: if family in (socket.AF_INET, socket.AF_INET6): ls = self.process_inet( "%s/net/%s" % (self._procfs_path, f), family, type_, inodes, filter_pid=pid) else: ls = self.process_unix( "%s/net/%s" % (self._procfs_path, f), family, inodes, filter_pid=pid) for fd, family, type_, laddr, raddr, status, bound_pid in ls: if pid: conn = _common.pconn(fd, family, type_, laddr, raddr, status) else: conn = _common.sconn(fd, family, type_, laddr, raddr, status, bound_pid) ret.add(conn) return list(ret) _connections = Connections() def net_connections(kind='inet'): """Return system-wide open connections.""" return _connections.retrieve(kind) def net_io_counters(): """Return network I/O statistics for every network interface installed on the system as a dict of raw tuples. """ with open_text("%s/net/dev" % get_procfs_path()) as f: lines = f.readlines() retdict = {} for line in lines[2:]: colon = line.rfind(':') assert colon > 0, repr(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[3]) 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 net_if_stats(): """Get NIC stats (isup, duplex, speed, mtu).""" duplex_map = {cext.DUPLEX_FULL: NIC_DUPLEX_FULL, cext.DUPLEX_HALF: NIC_DUPLEX_HALF, cext.DUPLEX_UNKNOWN: NIC_DUPLEX_UNKNOWN} names = net_io_counters().keys() ret = {} for name in names: isup, duplex, speed, mtu = cext.net_if_stats(name) duplex = duplex_map[duplex] ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret net_if_addrs = cext_posix.net_if_addrs # --- disks 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 = [] with open_text("%s/partitions" % get_procfs_path()) as f: lines = f.readlines()[2:] for line in reversed(lines): _, _, _, name = line.split() if name[-1].isdigit(): # we're dealing with a partition (e.g. 'sda1'); 'sda' will # also be around but we want to omit it partitions.append(name) else: if not partitions or not partitions[-1].startswith(name): # we're dealing with a disk entity for which no # partitions have been defined (e.g. 'sda' but # 'sda1' was not around), see: # https://github.com/giampaolo/psutil/issues/338 partitions.append(name) # retdict = {} with open_text("%s/diskstats" % get_procfs_path()) as f: lines = f.readlines() for line in lines: # http://www.mjmwired.net/kernel/Documentation/iostats.txt fields = line.split() if len(fields) > 7: _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \ fields[:11] else: # from kernel 2.6.0 to 2.6.25 _, _, name, reads, rbytes, writes, wbytes = fields rtime, wtime = 0, 0 if name in partitions: rbytes = int(rbytes) * SECTOR_SIZE wbytes = int(wbytes) * SECTOR_SIZE reads = int(reads) writes = int(writes) rtime = int(rtime) wtime = int(wtime) retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime) return retdict def disk_partitions(all=False): """Return mounted disk partitions as a list of namedtuples""" fstypes = set() with open_text("%s/filesystems" % get_procfs_path()) as f: for line in f: line = line.strip() if not line.startswith("nodev"): fstypes.add(line.strip()) else: # ignore all lines starting with "nodev" except "nodev zfs" fstype = line.split("\t")[1] if fstype == "zfs": fstypes.add("zfs") retlist = [] partitions = cext.disk_partitions() for partition in partitions: device, mountpoint, fstype, opts = partition if device == 'none': device = '' if not all: if device == '' or fstype not in fstypes: continue ntuple = _common.sdiskpart(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist disk_usage = _psposix.disk_usage # --- decorators def wrap_exceptions(fun): """Decorator which translates bare OSError and IOError exceptions into NoSuchProcess and AccessDenied. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except EnvironmentError as err: # support for private module import if NoSuchProcess is None or AccessDenied is None: raise # 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. if err.errno in (errno.ENOENT, errno.ESRCH): raise NoSuchProcess(self.pid, self._name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise return wrapper def wrap_exceptions_w_zombie(fun): """Same as above but also handles zombies.""" @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return wrap_exceptions(fun)(self) except NoSuchProcess: if not pid_exists(self.pid): raise else: raise ZombieProcess(self.pid, self._name, self._ppid) return wrapper class Process(object): """Linux process implementation.""" __slots__ = ["pid", "_name", "_ppid", "_procfs_path"] def __init__(self, pid): self.pid = pid self._name = None self._ppid = None self._procfs_path = get_procfs_path() @wrap_exceptions def name(self): with open_text("%s/%s/stat" % (self._procfs_path, self.pid)) as f: data = f.read() # XXX - gets changed later and probably needs refactoring return data[data.find('(') + 1:data.rfind(')')] def exe(self): try: return readlink("%s/%s/exe" % (self._procfs_path, self.pid)) except OSError as err: if err.errno in (errno.ENOENT, errno.ESRCH): # 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("%s/%s" % (self._procfs_path, self.pid)): return "" else: if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._name) else: raise ZombieProcess(self.pid, self._name, self._ppid) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._name) raise @wrap_exceptions def cmdline(self): with open_text("%s/%s/cmdline" % (self._procfs_path, self.pid)) as f: data = f.read() if data.endswith('\x00'): data = data[:-1] return [x for x in data.split('\x00')] @wrap_exceptions def terminal(self): tmap = _psposix._get_terminal_map() with open_binary("%s/%s/stat" % (self._procfs_path, self.pid)) as f: tty_nr = int(f.read().split(b' ')[6]) try: return tmap[tty_nr] except KeyError: return None if os.path.exists('/proc/%s/io' % os.getpid()): @wrap_exceptions def io_counters(self): fname = "%s/%s/io" % (self._procfs_path, self.pid) with open_binary(fname) as f: rcount = wcount = rbytes = wbytes = None for line in f: if rcount is None and line.startswith(b"syscr"): rcount = int(line.split()[1]) elif wcount is None and line.startswith(b"syscw"): wcount = int(line.split()[1]) elif rbytes is None and line.startswith(b"read_bytes"): rbytes = int(line.split()[1]) elif wbytes is None and line.startswith(b"write_bytes"): wbytes = int(line.split()[1]) for x in (rcount, wcount, rbytes, wbytes): if x is None: raise NotImplementedError( "couldn't read all necessary info from %r" % fname) return _common.pio(rcount, wcount, rbytes, wbytes) else: def io_counters(self): raise NotImplementedError("couldn't find /proc/%s/io (kernel " "too old?)" % self.pid) @wrap_exceptions def cpu_times(self): with open_binary("%s/%s/stat" % (self._procfs_path, self.pid)) as f: st = f.read().strip() # ignore the first two values ("pid (exe)") st = st[st.find(b')') + 2:] values = st.split(b' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS return _common.pcputimes(utime, stime) @wrap_exceptions def wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except _psposix.TimeoutExpired: # support for private module import if TimeoutExpired is None: raise raise TimeoutExpired(timeout, self.pid, self._name) @wrap_exceptions def create_time(self): with open_binary("%s/%s/stat" % (self._procfs_path, self.pid)) as f: st = f.read().strip() # ignore the first two values ("pid (exe)") st = st[st.rfind(b')') + 2:] values = st.split(b' ') # 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. # Also use cached value if available. bt = BOOT_TIME or boot_time() return (float(values[19]) / CLOCK_TICKS) + bt @wrap_exceptions def memory_info(self): with open_binary("%s/%s/statm" % (self._procfs_path, self.pid)) as f: vms, rss = f.readline().split()[:2] return _common.pmem(int(rss) * PAGESIZE, int(vms) * PAGESIZE) @wrap_exceptions def memory_info_ex(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 | | # ============================================================ with open_binary("%s/%s/statm" % (self._procfs_path, self.pid)) as f: vms, rss, shared, text, lib, data, dirty = \ [int(x) * PAGESIZE for x in f.readline().split()[:7]] return pextmem(rss, vms, shared, text, lib, data, dirty) if os.path.exists('/proc/%s/smaps' % os.getpid()): @wrap_exceptions def memory_maps(self): """Return process's mapped memory regions as a list of named tuples. Fields are explained in 'man proc'; here is an updated (Apr 2012) version: http://goo.gl/fmebo """ with open_text("%s/%s/smaps" % (self._procfs_path, self.pid), buffering=BIGGER_FILE_BUFFERING) as f: first_line = f.readline() current_block = [first_line] def get_blocks(): data = {} for line in f: fields = line.split(None, 5) if not fields[0].endswith(':'): # new block section yield (current_block.pop(), data) current_block.append(line) else: try: data[fields[0]] = int(fields[1]) * 1024 except ValueError: if fields[0].startswith('VmFlags:'): # see issue #369 continue else: raise ValueError("don't know how to inte" "rpret line %r" % line) yield (current_block.pop(), data) ls = [] 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() ls.append(( addr, perms, path, data['Rss:'], data.get('Size:', 0), data.get('Pss:', 0), data.get('Shared_Clean:', 0), data.get('Shared_Dirty:', 0), data.get('Private_Clean:', 0), data.get('Private_Dirty:', 0), data.get('Referenced:', 0), data.get('Anonymous:', 0), data.get('Swap:', 0) )) return ls else: def memory_maps(self): msg = "couldn't find /proc/%s/smaps; kernel < 2.6.14 or " \ "CONFIG_MMU kernel configuration option is not enabled" \ % self.pid raise NotImplementedError(msg) @wrap_exceptions_w_zombie def cwd(self): return readlink("%s/%s/cwd" % (self._procfs_path, self.pid)) @wrap_exceptions def num_ctx_switches(self): vol = unvol = None with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: for line in f: if line.startswith(b"voluntary_ctxt_switches"): vol = int(line.split()[1]) elif line.startswith(b"nonvoluntary_ctxt_switches"): unvol = int(line.split()[1]) if vol is not None and unvol is not None: return _common.pctxsw(vol, unvol) raise NotImplementedError( "'voluntary_ctxt_switches' and 'nonvoluntary_ctxt_switches'" "fields were not found in /proc/%s/status; the kernel is " "probably older than 2.6.23" % self.pid) @wrap_exceptions def num_threads(self): with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: for line in f: if line.startswith(b"Threads:"): return int(line.split()[1]) raise NotImplementedError("line not found") @wrap_exceptions def threads(self): thread_ids = os.listdir("%s/%s/task" % (self._procfs_path, self.pid)) thread_ids.sort() retlist = [] hit_enoent = False for thread_id in thread_ids: fname = "%s/%s/task/%s/stat" % ( self._procfs_path, self.pid, thread_id) try: with open_binary(fname) as f: st = f.read().strip() except IOError as err: if err.errno == errno.ENOENT: # no such file or directory; it means thread # disappeared on us hit_enoent = True continue raise # ignore the first two values ("pid (exe)") st = st[st.find(b')') + 2:] values = st.split(b' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS ntuple = _common.pthread(int(thread_id), utime, stime) retlist.append(ntuple) if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (self._procfs_path, self.pid)) return retlist @wrap_exceptions def nice_get(self): # with open_text('%s/%s/stat' % (self._procfs_path, self.pid)) as f: # data = f.read() # return int(data.split()[18]) # Use C implementation return cext_posix.getpriority(self.pid) @wrap_exceptions def nice_set(self, value): return cext_posix.setpriority(self.pid, value) @wrap_exceptions def cpu_affinity_get(self): return cext.proc_cpu_affinity_get(self.pid) @wrap_exceptions def cpu_affinity_set(self, cpus): try: cext.proc_cpu_affinity_set(self.pid, cpus) except OSError as err: if err.errno == errno.EINVAL: allcpus = tuple(range(len(per_cpu_times()))) for cpu in cpus: if cpu not in allcpus: raise ValueError("invalid CPU #%i (choose between %s)" % (cpu, allcpus)) raise # only starting from kernel 2.6.13 if hasattr(cext, "proc_ioprio_get"): @wrap_exceptions def ionice_get(self): ioclass, value = cext.proc_ioprio_get(self.pid) if enum is not None: ioclass = IOPriority(ioclass) return _common.pionice(ioclass, value) @wrap_exceptions def ionice_set(self, ioclass, value): if value is not None: if not PY3 and not isinstance(value, (int, long)): msg = "value argument is not an integer (gor %r)" % value raise TypeError(msg) if not 0 <= value <= 7: raise ValueError( "value argument range expected is between 0 and 7") if ioclass in (IOPRIO_CLASS_NONE, None): if value: msg = "can't specify value with IOPRIO_CLASS_NONE " \ "(got %r)" % value raise ValueError(msg) ioclass = IOPRIO_CLASS_NONE value = 0 elif ioclass == IOPRIO_CLASS_IDLE: if value: msg = "can't specify value with IOPRIO_CLASS_IDLE " \ "(got %r)" % value raise ValueError(msg) value = 0 elif ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): if value is None: # TODO: add comment explaining why this is 4 (?) value = 4 else: # otherwise we would get OSError(EVINAL) raise ValueError("invalid ioclass argument %r" % ioclass) return cext.proc_ioprio_set(self.pid, ioclass, value) if HAS_PRLIMIT: @wrap_exceptions def rlimit(self, resource, limits=None): # If pid is 0 prlimit() applies to the calling process and # we don't want that. We should never get here though as # PID 0 is not supported on Linux. if self.pid == 0: raise ValueError("can't use prlimit() against PID 0 process") try: if limits is None: # get return cext.linux_prlimit(self.pid, resource) else: # set if len(limits) != 2: raise ValueError( "second argument must be a (soft, hard) tuple, " "got %s" % repr(limits)) soft, hard = limits cext.linux_prlimit(self.pid, resource, soft, hard) except OSError as err: if err.errno == errno.ENOSYS and pid_exists(self.pid): # I saw this happening on Travis: # https://travis-ci.org/giampaolo/psutil/jobs/51368273 raise ZombieProcess(self.pid, self._name, self._ppid) else: raise @wrap_exceptions def status(self): with open_binary("%s/%s/status" % (self._procfs_path, self.pid)) as f: for line in f: if line.startswith(b"State:"): letter = line.split()[1] if PY3: letter = letter.decode() # XXX is '?' legit? (we're not supposed to return # it anyway) return PROC_STATUSES.get(letter, '?') @wrap_exceptions def open_files(self): retlist = [] files = os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)) hit_enoent = False for fd in files: file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd) try: file = readlink(file) except OSError as err: # ENOENT == file which is gone in the meantime if err.errno in (errno.ENOENT, errno.ESRCH): hit_enoent = True continue elif err.errno == errno.EINVAL: # not a link continue else: 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 = _common.popenfile(file, int(fd)) retlist.append(ntuple) if hit_enoent: # raise NSP if the process disappeared on us os.stat('%s/%s' % (self._procfs_path, self.pid)) return retlist @wrap_exceptions def connections(self, kind='inet'): ret = _connections.retrieve(kind, self.pid) # raise NSP if the process disappeared on us os.stat('%s/%s' % (self._procfs_path, self.pid)) return ret @wrap_exceptions def num_fds(self): return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid))) @wrap_exceptions def ppid(self): fpath = "%s/%s/status" % (self._procfs_path, self.pid) with open_binary(fpath) as f: for line in f: if line.startswith(b"PPid:"): # PPid: nnnn return int(line.split()[1]) raise NotImplementedError("line 'PPid' not found in %s" % fpath) @wrap_exceptions def uids(self): fpath = "%s/%s/status" % (self._procfs_path, self.pid) with open_binary(fpath) as f: for line in f: if line.startswith(b'Uid:'): _, real, effective, saved, fs = line.split() return _common.puids(int(real), int(effective), int(saved)) raise NotImplementedError("line 'Uid' not found in %s" % fpath) @wrap_exceptions def gids(self): fpath = "%s/%s/status" % (self._procfs_path, self.pid) with open_binary(fpath) as f: for line in f: if line.startswith(b'Gid:'): _, real, effective, saved, fs = line.split() return _common.pgids(int(real), int(effective), int(saved)) raise NotImplementedError("line 'Gid' not found in %s" % fpath) psutil-3.4.2/psutil/_pswindows.py0000664000175000017500000004546312633663044021115 0ustar giampaologiampaolo00000000000000# Copyright (c) 2009, 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 functools import os import sys from collections import namedtuple from . import _common from . import _psutil_windows as cext from ._common import conn_tmap from ._common import isfile_strict from ._common import sockfam_to_enum from ._common import socktype_to_enum from ._common import usage_percent from ._compat import long from ._compat import lru_cache from ._compat import PY3 from ._compat import xrange from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS from ._psutil_windows import HIGH_PRIORITY_CLASS from ._psutil_windows import IDLE_PRIORITY_CLASS from ._psutil_windows import NORMAL_PRIORITY_CLASS from ._psutil_windows import REALTIME_PRIORITY_CLASS if sys.version_info >= (3, 4): import enum else: enum = None # process priority constants, import from __init__.py: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx __extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS", "CONN_DELETE_TCB", "AF_LINK", ] # --- module level constants (gets pushed up to psutil module) CONN_DELETE_TCB = "DELETE_TCB" WAIT_TIMEOUT = 0x00000102 # 258 in decimal ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, cext.ERROR_ACCESS_DENIED]) if enum is None: AF_LINK = -1 else: AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1}) AF_LINK = AddressFamily.AF_LINK TCP_STATUSES = { cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED, cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT, cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV, cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1, cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2, cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT, cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE, cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT, cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK, cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN, cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING, cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB, cext.PSUTIL_CONN_NONE: _common.CONN_NONE, } if enum is not None: class Priority(enum.IntEnum): ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS globals().update(Priority.__members__) scputimes = namedtuple('scputimes', ['user', 'system', 'idle']) svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) pextmem = namedtuple( 'pextmem', ['num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', 'pagefile', 'peak_pagefile', 'private']) pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss']) pmmap_ext = namedtuple( 'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields)) ntpinfo = namedtuple( 'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time', 'create_time', 'num_threads', 'io_rcount', 'io_wcount', 'io_rbytes', 'io_wbytes']) # set later from __init__.py NoSuchProcess = None AccessDenied = None TimeoutExpired = None @lru_cache(maxsize=512) def _win32_QueryDosDevice(s): return cext.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):]) def py2_strencode(s, encoding=sys.getfilesystemencoding()): if PY3 or isinstance(s, str): return s else: try: return s.encode(encoding) except UnicodeEncodeError: # Filesystem codec failed, return the plain unicode # string (this should never happen). return s # --- public functions def virtual_memory(): """System virtual memory as a namedtuple.""" mem = cext.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 svmem(total, avail, percent, used, free) def swap_memory(): """Swap system memory as a (total, used, free, sin, sout) tuple.""" mem = cext.virtual_mem() total = mem[2] free = mem[3] used = total - free percent = usage_percent(used, total, _round=1) return _common.sswap(total, used, free, percent, 0, 0) def disk_usage(path): """Return disk usage associated with path.""" try: total, free = cext.disk_usage(path) except WindowsError: if not os.path.exists(path): msg = "No such file or directory: '%s'" % path raise OSError(errno.ENOENT, msg) raise used = total - free percent = usage_percent(used, total, _round=1) return _common.sdiskusage(total, used, free, percent) def disk_partitions(all): """Return disk partitions.""" rawlist = cext.disk_partitions(all) return [_common.sdiskpart(*x) for x in rawlist] def cpu_times(): """Return system CPU times as a named tuple.""" user, system, idle = cext.cpu_times() return scputimes(user, system, idle) def per_cpu_times(): """Return system per-CPU times as a list of named tuples.""" ret = [] for cpu_t in cext.per_cpu_times(): user, system, idle = cpu_t item = scputimes(user, system, idle) ret.append(item) return ret def cpu_count_logical(): """Return the number of logical CPUs in the system.""" return cext.cpu_count_logical() def cpu_count_physical(): """Return the number of physical CPUs in the system.""" return cext.cpu_count_phys() def boot_time(): """The system boot time expressed in seconds since the epoch.""" return cext.boot_time() def net_connections(kind, _pid=-1): """Return socket connections. If pid == -1 return system-wide connections (as opposed to connections opened by one process only). """ 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] rawlist = cext.net_connections(_pid, families, types) ret = set() for item in rawlist: fd, fam, type, laddr, raddr, status, pid = item status = TCP_STATUSES[status] fam = sockfam_to_enum(fam) type = socktype_to_enum(type) if _pid == -1: nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid) else: nt = _common.pconn(fd, fam, type, laddr, raddr, status) ret.add(nt) return list(ret) def net_if_stats(): ret = cext.net_if_stats() for name, items in ret.items(): name = py2_strencode(name) isup, duplex, speed, mtu = items if hasattr(_common, 'NicDuplex'): duplex = _common.NicDuplex(duplex) ret[name] = _common.snicstats(isup, duplex, speed, mtu) return ret def net_io_counters(): ret = cext.net_io_counters() return dict([(py2_strencode(k), v) for k, v in ret.items()]) def net_if_addrs(): ret = [] for items in cext.net_if_addrs(): items = list(items) items[0] = py2_strencode(items[0]) ret.append(items) return ret def users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = cext.users() for item in rawlist: user, hostname, tstamp = item user = py2_strencode(user) nt = _common.suser(user, None, hostname, tstamp) retlist.append(nt) return retlist pids = cext.pids pid_exists = cext.pid_exists disk_io_counters = cext.disk_io_counters ppid_map = cext.ppid_map # not meant to be public def wrap_exceptions(fun): """Decorator which translates bare OSError and WindowsError exceptions into NoSuchProcess and AccessDenied. """ @functools.wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError as err: # support for private module import if NoSuchProcess is None or AccessDenied is None: raise if err.errno in ACCESS_DENIED_SET: raise AccessDenied(self.pid, self._name) if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_name", "_ppid"] def __init__(self, pid): self.pid = pid self._name = None self._ppid = None @wrap_exceptions def name(self): """Return process name, which on Windows is always the final part of the executable. """ # This is how PIDs 0 and 4 are always represented in taskmgr # and process-hacker. if self.pid == 0: return "System Idle Process" elif self.pid == 4: return "System" else: try: # Note: this will fail with AD for most PIDs owned # by another user but it's faster. return py2_strencode(os.path.basename(self.exe())) except AccessDenied: return py2_strencode(cext.proc_name(self.pid)) @wrap_exceptions def 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 # see https://github.com/giampaolo/psutil/issues/414 # see https://github.com/giampaolo/psutil/issues/528 if self.pid in (0, 4): raise AccessDenied(self.pid, self._name) return py2_strencode(_convert_raw_path(cext.proc_exe(self.pid))) @wrap_exceptions def cmdline(self): ret = cext.proc_cmdline(self.pid) if PY3: return ret else: return [py2_strencode(s) for s in ret] def ppid(self): try: return ppid_map()[self.pid] except KeyError: raise NoSuchProcess(self.pid, self._name) def _get_raw_meminfo(self): try: return cext.proc_memory_info(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: # TODO: the C ext can probably be refactored in order # to get this from cext.proc_info() return cext.proc_memory_info_2(self.pid) raise @wrap_exceptions def memory_info(self): # 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 _common.pmem(t[2], t[7]) @wrap_exceptions def memory_info_ex(self): return pextmem(*self._get_raw_meminfo()) def memory_maps(self): try: raw = cext.proc_memory_maps(self.pid) except OSError as err: # XXX - can't use wrap_exceptions decorator as we're # returning a generator; probably needs refactoring. if err.errno in ACCESS_DENIED_SET: raise AccessDenied(self.pid, self._name) if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._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(self): return cext.proc_kill(self.pid) @wrap_exceptions def send_signal(self, sig): os.kill(self.pid, sig) @wrap_exceptions def wait(self, timeout=None): if timeout is None: timeout = cext.INFINITE else: # WaitForSingleObject() expects time in milliseconds timeout = int(timeout * 1000) ret = cext.proc_wait(self.pid, timeout) if ret == WAIT_TIMEOUT: # support for private module import if TimeoutExpired is None: raise RuntimeError("timeout expired") raise TimeoutExpired(timeout, self.pid, self._name) return ret @wrap_exceptions def username(self): if self.pid in (0, 4): return 'NT AUTHORITY\\SYSTEM' return cext.proc_username(self.pid) @wrap_exceptions def create_time(self): # special case for kernel process PIDs; return system boot time if self.pid in (0, 4): return boot_time() try: return cext.proc_create_time(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: return ntpinfo(*cext.proc_info(self.pid)).create_time raise @wrap_exceptions def num_threads(self): return ntpinfo(*cext.proc_info(self.pid)).num_threads @wrap_exceptions def threads(self): rawlist = cext.proc_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = _common.pthread(thread_id, utime, stime) retlist.append(ntuple) return retlist @wrap_exceptions def cpu_times(self): try: ret = cext.proc_cpu_times(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: nt = ntpinfo(*cext.proc_info(self.pid)) ret = (nt.user_time, nt.kernel_time) else: raise return _common.pcputimes(*ret) @wrap_exceptions def suspend(self): return cext.proc_suspend(self.pid) @wrap_exceptions def resume(self): return cext.proc_resume(self.pid) @wrap_exceptions def cwd(self): if self.pid in (0, 4): raise AccessDenied(self.pid, self._name) # return a normalized pathname since the native C function appends # "\\" at the and of the path path = cext.proc_cwd(self.pid) return py2_strencode(os.path.normpath(path)) @wrap_exceptions def open_files(self): if self.pid in (0, 4): return [] ret = set() # 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 = cext.proc_open_files(self.pid) for _file in raw_file_names: _file = _convert_raw_path(_file) if isfile_strict(_file): if not PY3: _file = py2_strencode(_file) ntuple = _common.popenfile(_file, -1) ret.add(ntuple) return list(ret) @wrap_exceptions def connections(self, kind='inet'): return net_connections(kind, _pid=self.pid) @wrap_exceptions def nice_get(self): value = cext.proc_priority_get(self.pid) if enum is not None: value = Priority(value) return value @wrap_exceptions def nice_set(self, value): return cext.proc_priority_set(self.pid, value) # available on Windows >= Vista if hasattr(cext, "proc_io_priority_get"): @wrap_exceptions def ionice_get(self): return cext.proc_io_priority_get(self.pid) @wrap_exceptions def ionice_set(self, value, _): if _: raise TypeError("set_proc_ionice() on Windows takes only " "1 argument (2 given)") if value not in (2, 1, 0): raise ValueError("value must be 2 (normal), 1 (low) or 0 " "(very low); got %r" % value) return cext.proc_io_priority_set(self.pid, value) @wrap_exceptions def io_counters(self): try: ret = cext.proc_io_counters(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: nt = ntpinfo(*cext.proc_info(self.pid)) ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes) else: raise return _common.pio(*ret) @wrap_exceptions def status(self): suspended = cext.proc_is_suspended(self.pid) if suspended: return _common.STATUS_STOPPED else: return _common.STATUS_RUNNING @wrap_exceptions def cpu_affinity_get(self): def from_bitmask(x): return [i for i in xrange(64) if (1 << i) & x] bitmask = cext.proc_cpu_affinity_get(self.pid) return from_bitmask(bitmask) @wrap_exceptions def cpu_affinity_set(self, value): def to_bitmask(l): if not l: raise ValueError("invalid argument %r" % l) out = 0 for b in l: 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(per_cpu_times()))) for cpu in value: if cpu not in allcpus: if not isinstance(cpu, (int, long)): raise TypeError( "invalid CPU %r; an integer is required" % cpu) else: raise ValueError("invalid CPU %r" % cpu) bitmask = to_bitmask(value) cext.proc_cpu_affinity_set(self.pid, bitmask) @wrap_exceptions def num_handles(self): try: return cext.proc_num_handles(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: return ntpinfo(*cext.proc_info(self.pid)).num_handles raise @wrap_exceptions def num_ctx_switches(self): ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches # only voluntary ctx switches are supported return _common.pctxsw(ctx_switches, 0)