psutil-1.2.1/0000775000175000017500000000000012244726663015013 5ustar giampaologiampaolo00000000000000psutil-1.2.1/setup.cfg0000664000175000017500000000007312244726663016634 0ustar giampaologiampaolo00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 psutil-1.2.1/setup.py0000664000175000017500000001633412244725637016534 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. import fnmatch import os import shutil import sys try: from setuptools import setup, Extension except ImportError: from distutils.core import setup, Extension def clean(): """'python setup.py clean' custom command.""" def rglob(path, pattern): return [os.path.join(dirpath, f) for dirpath, dirnames, files in os.walk(path) for f in fnmatch.filter(files, pattern)] for dirname in ('build', 'dist'): if os.path.isdir(dirname): sys.stdout.write('rmdir: %s\n' % dirname) shutil.rmtree(dirname) for dirpath, dirnames, files in os.walk('.'): if dirpath.endswith(('__pycache__', '.egg-info')): sys.stdout.write('rmdir %s\n' % dirpath) shutil.rmtree(dirpath) for pattern in ['*.py[co]', '*.s[ol]', '*~', '*.orig', '*.rej', '*.swp']: for x in rglob('.', pattern): sys.stdout.write('rm %s\n' % x) os.remove(x) def get_version(): INIT = os.path.abspath(os.path.join(os.path.dirname(__file__), 'psutil', '__init__.py')) f = open(INIT, 'r') try: for line in f: if line.startswith('__version__'): ret = eval(line.strip().split(' = ')[1]) assert ret.count('.') == 2, ret for num in ret.split('.'): assert num.isdigit(), ret return ret else: raise ValueError("couldn't find version string") finally: f.close() def get_description(): README = os.path.abspath(os.path.join(os.path.dirname(__file__), 'README')) f = open(README, 'r') try: return f.read() finally: f.close() # POSIX if os.name == 'posix': posix_extension = Extension( '_psutil_posix', sources=['psutil/_psutil_posix.c'], ) # Windows if sys.platform.startswith("win32"): def get_winver(): maj, min = sys.getwindowsversion()[0:2] return '0x0%s' % ((maj * 100) + min) extensions = [Extension( '_psutil_mswindows', sources=[ 'psutil/_psutil_mswindows.c', 'psutil/_psutil_common.c', 'psutil/arch/mswindows/process_info.c', 'psutil/arch/mswindows/process_handles.c', 'psutil/arch/mswindows/security.c', ], define_macros=[ # be nice to mingw, see: # http://www.mingw.org/wiki/Use_more_recent_defined_functions ('_WIN32_WINNT', get_winver()), ('_AVAIL_WINVER_', get_winver()), # see: https://code.google.com/p/psutil/issues/detail?id=348 ('PSAPI_VERSION', 1), ], libraries=[ "psapi", "kernel32", "advapi32", "shell32", "netapi32", "iphlpapi", "wtsapi32", ], # extra_compile_args=["/Z7"], # extra_link_args=["/DEBUG"] )] # OS X elif sys.platform.startswith("darwin"): extensions = [Extension( '_psutil_osx', sources=[ 'psutil/_psutil_osx.c', 'psutil/_psutil_common.c', 'psutil/arch/osx/process_info.c' ], extra_link_args=['-framework', 'CoreFoundation', '-framework', 'IOKit'], ), posix_extension, ] # FreeBSD elif sys.platform.startswith("freebsd"): extensions = [Extension( '_psutil_bsd', sources=[ 'psutil/_psutil_bsd.c', 'psutil/_psutil_common.c', 'psutil/arch/bsd/process_info.c' ], libraries=["devstat"]), posix_extension, ] # Linux elif sys.platform.startswith("linux"): extensions = [Extension( '_psutil_linux', sources=['psutil/_psutil_linux.c']), posix_extension, ] # Solaris elif sys.platform.lower().startswith('sunos'): extensions = [Extension( '_psutil_sunos', sources=['psutil/_psutil_sunos.c'], libraries=['kstat', 'nsl'],), posix_extension, ] else: sys.exit('platform %s is not supported' % sys.platform) def main(): # "python setup.py clean" custom command if len(sys.argv) > 1 and sys.argv[1] == 'clean': return clean() setup_args = dict( name='psutil', version=get_version(), description='A process and system utilities module for Python', long_description=get_description(), keywords=[ 'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty', 'ionice', 'uptime', 'taskmgr', 'process', 'df', 'iotop', 'iostat', 'ifconfig', 'taskset', 'who', 'pidof', 'pmap', 'smem', 'monitoring', 'ulimit', 'prlimit', ], author='Giampaolo Rodola', author_email='psutil@googlegroups.com', maintainer='Giampaolo Rodola', maintainer_email='g.rodola gmail com', url='http://code.google.com/p/psutil/', platforms='Platform Independent', license='License :: OSI Approved :: BSD License', packages=['psutil'], test_suite='test.test_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 :: Linux', 'Operating System :: POSIX :: SunOS/Solaris', 'Operating System :: POSIX', 'Programming Language :: C', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', '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 :: Systems Administration', 'Topic :: Utilities', ], ) if extensions is not None: setup_args["ext_modules"] = extensions setup(**setup_args) if __name__ == '__main__': main() psutil-1.2.1/PKG-INFO0000664000175000017500000002607212244726663016117 0ustar giampaologiampaolo00000000000000Metadata-Version: 1.1 Name: psutil Version: 1.2.1 Summary: A process and system utilities module for Python Home-page: http://code.google.com/p/psutil/ Author: Giampaolo Rodola Author-email: g.rodola gmail com License: License :: OSI Approved :: BSD License Description: =========== Quick links =========== * `Home page `_ * `Download `_ * `Documentation `_ * `Forum `_ * `What's new `_ ======= Summary ======= psutil is a module providing an interface for retrieving information on all running processes and system utilization (CPU, memory, disks, network, users) in a portable way by using Python, implementing many functionalities offered by command line tools such as: **ps, top, df, kill, free, lsof, free, netstat, ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**. It currently supports **Linux**, **Windows**, **OSX**, **FreeBSD**, **Sun Solaris** both **32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using a single code base. ============== Example usages ============== CPU === >>> import psutil >>> psutil.cpu_times() cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.509, irq=0.0, softirq=19.422, 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] [7.0, 8.5] [1.2, 9.0] >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... cpupercent(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) cpupercent(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) cpupercent(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) Memory ====== >>> psutil.virtual_memory() vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336) >>> psutil.swap_memory() swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== >>> psutil.disk_partitions() [partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) iostat(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= >>> psutil.net_io_counters(pernic=True) {'eth0': iostat(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': iostat(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> Other system info ================= >>> psutil.get_users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.get_boot_time() 1365519115.0 >>> >>> psutil.NUM_CPUS 4 >>> psutil.TOTAL_PHYMEM 8374120448L >>> Process management ================== >>> import psutil >>> psutil.get_pid_list() [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071] >>> >>> p = psutil.Process(7055) >>> p.name 'python' >>> p.exe '/usr/bin/python' >>> p.getcwd() '/home/giampaolo' >>> p.cmdline ['/usr/bin/python', 'main.py'] >>> >>> str(p.status) 'running' >>> p.username 'giampaolo' >>> p.create_time 1267551141.5019531 >>> p.terminal '/dev/pts/0' >>> >>> p.uids user(real=1000, effective=1000, saved=1000) >>> p.gids group(real=1000, effective=1000, saved=1000) >>> >>> p.get_cpu_times() cputimes(user=1.02, system=0.31) >>> p.get_cpu_percent(interval=1.0) 12.1 >>> p.get_cpu_affinity() [0, 1, 2, 3] >>> p.set_cpu_affinity([0]) >>> >>> p.get_memory_percent() 0.63423 >>> >>> p.get_memory_info() meminfo(rss=7471104, vms=68513792) >>> p.get_ext_memory_info() meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.get_memory_maps() [mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), mmap(path='[heap]', rss=54653, anonymous=8192, swap=0), mmap(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.get_io_counters() io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.get_open_files() [openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.get_connections() [connection(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), connection(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), connection(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), connection(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.get_num_threads() 4 >>> p.get_num_fds() 8 >>> p.get_threads() [thread(id=5234, user_time=22.5, system_time=9.2891), thread(id=5235, user_time=0.0, system_time=0.0), thread(id=5236, user_time=0.0, system_time=0.0), thread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.get_num_ctx_switches() amount(voluntary=78, involuntary=19) >>> >>> p.get_nice() 0 >>> p.set_nice(10) >>> >>> p.set_ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Windows and Linux only) >>> p.get_ionice() ionice(ioclass=3, value=0) >>> >>> p.set_rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # resource limits (Linux only) >>> p.get_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 >>> Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,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 :: 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.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 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 :: Systems Administration Classifier: Topic :: Utilities psutil-1.2.1/HISTORY0000664000175000017500000006252212244725665016107 0ustar giampaologiampaolo00000000000000Bug tracker at http://code.google.com/p/psutil/issues 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 with 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] fixed "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: tar.gz and windows binary files are now hosted 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: STATUS_* and CONN_* constants (returned by Process' status() and get_connections() methods respectively) have been turned from constant objects to 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 ------------------ NEW FEATURES * #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: extensively use unittest2 module in unit tests and provide workarounds if this is not installed on python < 2.7. BUG FIXES * #374: [Windows] negative memory usage reported when processes use 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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 ------------------ NEW FEATURES * #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 instances of PID 0 on OS X and FreeBSD platforms. 0.1.0 - 2009-01-27 ------------------ * Initial release. psutil-1.2.1/LICENSE0000664000175000017500000000306012243206601015777 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-1.2.1/examples/0000775000175000017500000000000012244726663016631 5ustar giampaologiampaolo00000000000000psutil-1.2.1/examples/free.py0000775000175000017500000000170712243464703020125 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. """ import psutil from psutil._compat import print_ def main(): virt = psutil.virtual_memory() swap = psutil.swap_memory() templ = "%-7s %10s %10s %10s %10s %10s %10s" print_(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache')) print_(templ % ( 'Mem:', int(virt.total / 1024), int(virt.used / 1024), int(virt.free / 1024), int(getattr(virt, 'shared', 0) / 1024), int(getattr(virt, 'buffers', 0) / 1024), int(getattr(virt, 'cached', 0) / 1024))) print_(templ % ( 'Swap:', int(swap.total / 1024), int(swap.used / 1024), int(swap.free / 1024), '', '', '')) if __name__ == '__main__': main() psutil-1.2.1/examples/meminfo.py0000775000175000017500000000220012243464566020632 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. """ import psutil from psutil._compat import print_ def bytes2human(n): # http://code.activestate.com/recipes/578019 # >>> bytes2human(10000) # '9.8K' # >>> bytes2human(100001221) # '95.4M' symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.1f%s' % (value, s) return "%sB" % n def 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-1.2.1/examples/process_detail.py0000775000175000017500000001035212243464230022173 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' """ import datetime import os import socket import sys import psutil def convert_bytes(n): symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.1f%s' % (value, s) return "%sB" % n def print_(a, b): if sys.stdout.isatty() and os.name == 'posix': fmt = '\x1b[1;32m%-17s\x1b[0m %s' % (a, b) else: fmt = '%-15s %s' % (a, b) # python 2/3 compatibility layer sys.stdout.write(fmt + '\n') sys.stdout.flush() def run(pid): ACCESS_DENIED = '' try: p = psutil.Process(pid) pinfo = p.as_dict(ad_value=ACCESS_DENIED) except psutil.NoSuchProcess: sys.exit(str(sys.exc_info()[1])) try: if p.parent: parent = '(%s)' % p.parent.name else: parent = '' except psutil.Error: parent = '' started = datetime.datetime.fromtimestamp( pinfo['create_time']).strftime('%Y-%M-%d %H:%M') io = pinfo.get('io_counters', 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)) children = p.get_children() print_('pid', pinfo['pid']) print_('name', pinfo['name']) print_('exe', pinfo['exe']) print_('parent', '%s %s' % (pinfo['ppid'], parent)) print_('cmdline', ' '.join(pinfo['cmdline'])) print_('started', started) print_('user', pinfo['username']) if os.name == 'posix' and pinfo['uids'] and pinfo['gids']: print_('uids', 'real=%s, effective=%s, saved=%s' % pinfo['uids']) if os.name == 'posix' and pinfo['gids']: print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids']) if os.name == 'posix': print_('terminal', pinfo['terminal'] or '') if hasattr(p, 'getcwd'): print_('cwd', pinfo['cwd']) print_('memory', mem) print_('cpu', '%s%% (user=%s, system=%s)' % ( pinfo['cpu_percent'], 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'] != 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-1.2.1/examples/killall.py0000775000175000017500000000123512243464574020632 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-1.2.1/examples/who.py0000775000175000017500000000123412243464762020001 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. """ from datetime import datetime import psutil from psutil._compat import print_ def main(): users = psutil.get_users() for user in users: print_("%-15s %-15s %s (%s)" % ( user.name, user.terminal or '-', datetime.fromtimestamp(user.started).strftime("%Y-%m-%d %H:%M"), user.host)) if __name__ == '__main__': main() psutil-1.2.1/examples/nettop.py0000775000175000017500000000744012243464467020524 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' """ import sys import os if os.name != 'posix': sys.exit('platform not supported') import atexit import curses import time import psutil # --- curses stuff def tear_down(): win.keypad(0) curses.nocbreak() curses.echo() curses.endwin() win = curses.initscr() atexit.register(tear_down) curses.endwin() lineno = 0 def print_line(line, highlight=False): """A thin wrapper around curses's addstr().""" global lineno try: if highlight: line += " " * (win.getmaxyx()[1] - len(line)) win.addstr(lineno, 0, line, curses.A_REVERSE) else: win.addstr(lineno, 0, line, 0) except curses.error: lineno = 0 win.refresh() raise else: lineno += 1 # --- curses stuff def bytes2human(n): """ >>> bytes2human(10000) '9.8 K' >>> bytes2human(100001221) '95.4 M' """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f %s' % (value, s) return '%.2f B' % (n) def poll(interval): """Retrieve raw stats within an interval window.""" tot_before = psutil.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-1.2.1/examples/top.py0000775000175000017500000001371112243464035020002 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' """ import os import sys if os.name != 'posix': sys.exit('platform not supported') import atexit import curses import time from datetime import datetime, timedelta import psutil # --- curses stuff def tear_down(): win.keypad(0) curses.nocbreak() curses.echo() curses.endwin() win = curses.initscr() atexit.register(tear_down) curses.endwin() lineno = 0 def print_line(line, highlight=False): """A thin wrapper around curses's addstr().""" global lineno try: if highlight: line += " " * (win.getmaxyx()[1] - len(line)) win.addstr(lineno, 0, line, curses.A_REVERSE) else: win.addstr(lineno, 0, line, 0) except curses.error: lineno = 0 win.refresh() raise else: lineno += 1 # --- /curses stuff def bytes2human(n): """ >>> bytes2human(10000) '9K' >>> bytes2human(100001221) '95M' """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = int(float(n) / prefix[s]) return '%s%s' % (value, s) return "%sB" % n def poll(interval): # sleep some time time.sleep(interval) procs = [] procs_status = {} for p in psutil.process_iter(): try: p.dict = p.as_dict(['username', 'get_nice', 'get_memory_info', 'get_memory_percent', 'get_cpu_percent', 'get_cpu_times', 'name', 'status']) try: procs_status[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 for cpu_num, perc in enumerate(psutil.cpu_percent(interval=0, percpu=True)): dashes, empty_dashes = get_dashes(perc) print_line(" CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes, perc)) mem = psutil.virtual_memory() dashes, empty_dashes = get_dashes(mem.percent) used = mem.total - mem.available line = " Mem [%s%s] %5s%% %6s/%s" % ( dashes, empty_dashes, mem.percent, str(int(used / 1024 / 1024)) + "M", str(int(mem.total / 1024 / 1024)) + "M" ) print_line(line) # swap usage swap = psutil.swap_memory() dashes, empty_dashes = get_dashes(swap.percent) line = " Swap [%s%s] %5s%% %6s/%s" % ( dashes, empty_dashes, swap.percent, str(int(swap.used / 1024 / 1024)) + "M", str(int(swap.total / 1024 / 1024)) + "M" ) print_line(line) # processes number and status st = [] for x, y in procs_status.items(): if y: st.append("%s=%s" % (x, y)) st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1) print_line(" Processes: %s (%s)" % (num_procs, ' '.join(st))) # load average, uptime uptime = datetime.now() - datetime.fromtimestamp(psutil.BOOT_TIME) av1, av2, av3 = os.getloadavg() line = " Load average: %.2f %.2f %.2f Uptime: %s" \ % (av1, av2, av3, str(uptime).split('.')[0]) print_line(line) def refresh_window(procs, procs_status): """Print results on screen by using curses.""" curses.endwin() templ = "%-6s %-8s %4s %5s %5s %6s %4s %9s %2s" win.erase() header = templ % ("PID", "USER", "NI", "VIRT", "RES", "CPU%", "MEM%", "TIME+", "NAME") print_header(procs_status, len(procs)) print_line("") print_line(header, highlight=True) for p in procs: # TIME+ column shows process CPU cumulative time and it # is expressed as: "mm:ss.ms" if p.dict['cpu_times'] 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 1: args = poll(interval) refresh_window(*args) interval = 1 except (KeyboardInterrupt, SystemExit): pass if __name__ == '__main__': main() psutil-1.2.1/examples/netstat.py0000775000175000017500000000266612243464552020675 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'. """ import socket from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM import psutil from psutil._compat import print_ AD = "-" AF_INET6 = getattr(socket, 'AF_INET6', object()) proto_map = { (AF_INET, SOCK_STREAM): 'tcp', (AF_INET6, SOCK_STREAM): 'tcp6', (AF_INET, SOCK_DGRAM): 'udp', (AF_INET6, SOCK_DGRAM): 'udp6', } def main(): templ = "%-5s %-22s %-22s %-13s %-6s %s" print_(templ % ( "Proto", "Local addr", "Remote addr", "Status", "PID", "Program name")) for p in psutil.process_iter(): name = '?' try: name = p.name cons = p.get_connections(kind='inet') except psutil.AccessDenied: print_(templ % (AD, AD, AD, AD, p.pid, name)) except psutil.NoSuchProcess: continue else: for c in cons: raddr = "" laddr = "%s:%s" % (c.laddr) if c.raddr: raddr = "%s:%s" % (c.raddr) print_(templ % ( proto_map[(c.family, c.type)], laddr, raddr, c.status, p.pid, name[:15])) if __name__ == '__main__': main() psutil-1.2.1/examples/iotop.py0000775000175000017500000001046012243464626020336 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. Author: Giampaolo Rodola' """ import os import sys import psutil if not hasattr(psutil.Process, 'get_io_counters') or os.name != 'posix': sys.exit('platform not supported') import time import curses import atexit # --- curses stuff def tear_down(): win.keypad(0) curses.nocbreak() curses.echo() curses.endwin() win = curses.initscr() atexit.register(tear_down) curses.endwin() lineno = 0 def print_line(line, highlight=False): """A thin wrapper around curses's addstr().""" global lineno try: if highlight: line += " " * (win.getmaxyx()[1] - len(line)) win.addstr(lineno, 0, line, curses.A_REVERSE) else: win.addstr(lineno, 0, line, 0) except curses.error: lineno = 0 win.refresh() raise else: lineno += 1 # --- /curses stuff def bytes2human(n): """ >>> bytes2human(10000) '9.8 K/s' >>> bytes2human(100001221) '95.4 M/s' """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.2f %s/s' % (value, s) return '%.2f B/s' % (n) def poll(interval): """Calculate IO usage by comparing IO statics before and after the interval. Return a tuple including all currently running processes sorted by IO activity and total disks I/O activity. """ # first get a list of all processes and disk io counters procs = [p for p in psutil.process_iter()] for p in procs[:]: try: p._before = p.get_io_counters() except psutil.Error: procs.remove(p) continue disks_before = psutil.disk_io_counters() # sleep some time time.sleep(interval) # then retrieve the same info again for p in procs[:]: try: p._after = p.get_io_counters() p._cmdline = ' '.join(p.cmdline) if not p._cmdline: p._cmdline = p.name p._username = p.username except psutil.NoSuchProcess: procs.remove(p) disks_after = psutil.disk_io_counters() # finally calculate results by comparing data before and # after the interval for p in procs: p._read_per_sec = p._after.read_bytes - p._before.read_bytes p._write_per_sec = p._after.write_bytes - p._before.write_bytes p._total = p._read_per_sec + p._write_per_sec disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes # sort processes by total disk IO so that the more intensive # ones get listed first processes = sorted(procs, key=lambda p: p._total, reverse=True) return (processes, disks_read_per_sec, disks_write_per_sec) def refresh_window(procs, disks_read, disks_write): """Print results on screen by using curses.""" curses.endwin() templ = "%-5s %-7s %11s %11s %s" win.erase() disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \ % (bytes2human(disks_read), bytes2human(disks_write)) print_line(disks_tot) header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND") print_line(header, highlight=True) for p in procs: line = templ % ( p.pid, p._username[:7], bytes2human(p._read_per_sec), bytes2human(p._write_per_sec), p._cmdline) try: print_line(line) except curses.error: break win.refresh() def main(): try: interval = 0 while 1: args = poll(interval) refresh_window(*args) interval = 1 except (KeyboardInterrupt, SystemExit): pass if __name__ == '__main__': main() psutil-1.2.1/examples/disk_usage.py0000775000175000017500000000312712243464725021324 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. """ import sys import os import psutil from psutil._compat import print_ def bytes2human(n): # http://code.activestate.com/recipes/578019 # >>> bytes2human(10000) # '9.8K' # >>> bytes2human(100001221) # '95.4M' symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.1f%s' % (value, s) return "%sB" % n def main(): templ = "%-17s %8s %8s %8s %5s%% %9s %s" print_(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount")) for part in psutil.disk_partitions(all=False): 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-1.2.1/examples/pmap.py0000775000175000017500000000173712243464340020141 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. """ import sys import psutil from psutil._compat import print_ def main(): if len(sys.argv) != 2: sys.exit('usage: pmap pid') p = psutil.Process(int(sys.argv[1])) print_("pid=%s, name=%s" % (p.pid, p.name)) templ = "%-16s %10s %-7s %s" print_(templ % ("Address", "RSS", "Mode", "Mapping")) total_rss = 0 for m in p.get_memory_maps(grouped=False): total_rss += m.rss print_(templ % ( m.addr.split('-')[0].zfill(16), str(m.rss / 1024) + 'K', m.perms, m.path)) print_("-" * 33) print_(templ % ("Total", str(total_rss / 1024) + 'K', '', '')) if __name__ == '__main__': main() psutil-1.2.1/test/0000775000175000017500000000000012244726663015772 5ustar giampaologiampaolo00000000000000psutil-1.2.1/test/_windows.py0000664000175000017500000003401712243744616020177 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. """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 unittest import _psutil_mswindows import psutil from psutil._compat import PY3, callable, long from psutil._psmswindows import ACCESS_DENIED_SET from test_psutil import * try: import wmi except ImportError: err = sys.exc_info()[1] register_warning("Couldn't run wmi tests: %s" % str(err)) wmi = None try: import win32api import win32con except ImportError: err = sys.exc_info()[1] register_warning("Couldn't run pywin32 tests: %s" % str(err)) win32api = None def wrap_exceptions(callable): def wrapper(self, *args, **kwargs): try: return callable(self, *args, **kwargs) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: raise psutil.AccessDenied(None, None) if err.errno == errno.ESRCH: raise psutil.NoSuchProcess(None, None) raise return wrapper class WindowsSpecificTestCase(unittest.TestCase): def setUp(self): sproc = get_test_subprocess() wait_for_pid(sproc.pid) self.pid = sproc.pid def tearDown(self): reap_children() def test_issue_24(self): p = psutil.Process(0) self.assertRaises(psutil.AccessDenied, p.kill) def test_special_pid(self): p = psutil.Process(4) self.assertEqual(p.name, 'System') # use __str__ to access all common Process properties to check # that nothing strange happens str(p) p.username self.assertTrue(p.create_time >= 0.0) try: rss, vms = p.get_memory_info() except psutil.AccessDenied: # expected on Windows Vista and Windows 7 if not platform.uname()[1] in ('vista', 'win-7', 'win7'): raise else: self.assertTrue(rss > 0) def test_signal(self): p = psutil.Process(self.pid) self.assertRaises(ValueError, p.send_signal, signal.SIGINT) def test_nic_names(self): p = subprocess.Popen(['ipconfig', '/all'], stdout=subprocess.PIPE) out = p.communicate()[0] if PY3: out = str(out, sys.stdout.encoding) nics = psutil.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 if wmi is not None: # --- Process class tests def test_process_name(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) self.assertEqual(p.name, w.Caption) def test_process_exe(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) self.assertEqual(p.exe, w.ExecutablePath) def test_process_cmdline(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) self.assertEqual(' '.join(p.cmdline), w.CommandLine.replace('"', '')) def test_process_username(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) domain, _, username = w.GetOwner() username = "%s\\%s" % (domain, username) self.assertEqual(p.username, username) def test_process_rss_memory(self): time.sleep(0.1) w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) rss = p.get_memory_info().rss self.assertEqual(rss, int(w.WorkingSetSize)) def test_process_vms_memory(self): time.sleep(0.1) w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) vms = p.get_memory_info().vms # http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx # ...claims that PageFileUsage is represented in Kilo # bytes but funnily enough on certain platforms bytes are # returned instead. wmi_usage = int(w.PageFileUsage) if (vms != wmi_usage) and (vms != wmi_usage * 1024): self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms)) def test_process_create_time(self): w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(self.pid) wmic_create = str(w.CreationDate.split('.')[0]) psutil_create = time.strftime("%Y%m%d%H%M%S", time.localtime(p.create_time)) self.assertEqual(wmic_create, psutil_create) # --- psutil namespace functions and constants tests @unittest.skipUnless(hasattr(os, 'NUMBER_OF_PROCESSORS'), 'NUMBER_OF_PROCESSORS env var is not available') def test_NUM_CPUS(self): num_cpus = int(os.environ['NUMBER_OF_PROCESSORS']) self.assertEqual(num_cpus, psutil.NUM_CPUS) def test_TOTAL_PHYMEM(self): w = wmi.WMI().Win32_ComputerSystem()[0] self.assertEqual(int(w.TotalPhysicalMemory), psutil.TOTAL_PHYMEM) def test__UPTIME(self): # _UPTIME constant is not public but it is used internally # as value to return for pid 0 creation time. # WMI behaves the same. w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0] p = psutil.Process(0) wmic_create = str(w.CreationDate.split('.')[0]) psutil_create = time.strftime("%Y%m%d%H%M%S", time.localtime(p.create_time)) # XXX - ? no actual test here def test_get_pids(self): # Note: this test might fail if the OS is starting/killing # other processes in the meantime w = wmi.WMI().Win32_Process() wmi_pids = [x.ProcessId for x in w] wmi_pids.sort() psutil_pids = psutil.get_pid_list() psutil_pids.sort() if wmi_pids != psutil_pids: difference = \ filter(lambda x: x not in wmi_pids, psutil_pids) + \ filter(lambda x: x not in psutil_pids, wmi_pids) self.fail("difference: " + str(difference)) def test_disks(self): ps_parts = psutil.disk_partitions(all=True) wmi_parts = wmi.WMI().Win32_LogicalDisk() for ps_part in ps_parts: for wmi_part in wmi_parts: if ps_part.device.replace('\\', '') == wmi_part.DeviceID: if not ps_part.mountpoint: # this is usually a CD-ROM with no disk inserted break try: usage = psutil.disk_usage(ps_part.mountpoint) except OSError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: # usually this is the floppy break else: raise self.assertEqual(usage.total, int(wmi_part.Size)) wmi_free = int(wmi_part.FreeSpace) self.assertEqual(usage.free, wmi_free) # 10 MB tollerance if abs(usage.free - wmi_free) > 10 * 1024 * 1024: self.fail("psutil=%s, wmi=%s" % usage.free, wmi_free) break else: self.fail("can't find partition %s" % repr(ps_part)) if win32api is not None: def test_get_num_handles(self): p = psutil.Process(os.getpid()) before = p.get_num_handles() handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, win32con.FALSE, os.getpid()) after = p.get_num_handles() self.assertEqual(after, before + 1) win32api.CloseHandle(handle) self.assertEqual(p.get_num_handles(), before) def test_get_num_handles_2(self): # Note: this fails from time to time; I'm keen on thinking # it doesn't mean something is broken def call(p, attr): attr = getattr(p, name, None) if attr is not None and callable(attr): ret = attr() else: ret = attr p = psutil.Process(self.pid) failures = [] for name in dir(psutil.Process): if name.startswith('_') \ or name.startswith('set_') \ or name in ('terminate', 'kill', 'suspend', 'resume', 'nice', 'send_signal', 'wait', 'get_children', 'as_dict'): continue else: try: call(p, name) num1 = p.get_num_handles() call(p, name) num2 = p.get_num_handles() except (psutil.NoSuchProcess, psutil.AccessDenied): pass else: if num2 > num1: fail = "failure while processing Process.%s method " \ "(before=%s, after=%s)" % (name, num1, num2) failures.append(fail) if failures: self.fail('\n' + '\n'.join(failures)) class TestDualProcessImplementation(unittest.TestCase): fun_names = [ # function name tolerance ('get_process_cpu_times', 0.2), ('get_process_create_time', 0.5), ('get_process_num_handles', 1), # 1 because impl #1 opens a handle ('get_process_io_counters', 0), ('get_process_memory_info', 1024), # KB ] def test_compare_values(self): # Certain APIs on Windows have 2 internal implementations, one # based on documented Windows APIs, another one based # NtQuerySystemInformation() which gets called as fallback in # case the first fails because of limited permission error. # Here we test that the two methods return the exact same value, # see: # http://code.google.com/p/psutil/issues/detail?id=304 def assert_ge_0(obj): if isinstance(obj, tuple): for value in obj: self.assertGreaterEqual(value, 0) 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) failures = [] for name, tolerance in self.fun_names: meth1 = wrap_exceptions(getattr(_psutil_mswindows, name)) meth2 = wrap_exceptions(getattr(_psutil_mswindows, name + '_2')) for p in psutil.process_iter(): if name == 'get_process_memory_info' and p.pid == os.getpid(): continue # try: ret1 = meth1(p.pid) except psutil.NoSuchProcess: continue except psutil.AccessDenied: ret1 = None # try: ret2 = meth2(p.pid) except psutil.NoSuchProcess: # this is supposed to fail only in case of zombie process # never for permission error continue # compare values try: if ret1 is None: assert_ge_0(ret2) else: compare_with_tolerance(ret1, ret2, tolerance) assert_ge_0(ret1) assert_ge_0(ret2) except AssertionError: trace = traceback.format_exc() msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % ( trace, p.pid, name, ret1, ret2) failures.append(msg) break if failures: self.fail('\n\n'.join(failures)) def test_zombies(self): # test that NPS is raised by the 2nd implementation in case a # process no longer exists ZOMBIE_PID = max(psutil.get_pid_list()) + 5000 for name, _ in self.fun_names: meth = wrap_exceptions(getattr(_psutil_mswindows, name)) self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID) def test_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 test_main(): sys.exit(1) psutil-1.2.1/test/test_psutil.py0000664000175000017500000026617412243746022020731 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 (you can quickly run it with "python setup.py test"). Note: this is targeted for both python 2.x and 3.x so there's no need to use 2to3 tool first. If you're on Python < 2.7 it is recommended to install unittest2 module from: https://pypi.python.org/pypi/unittest2 """ from __future__ import division import atexit import datetime import errno import os 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, SOCK_STREAM, SOCK_DGRAM try: import ast # python >= 2.6 except ImportError: ast = None try: import unittest2 as unittest # pyhon < 2.7 + unittest2 installed except ImportError: import unittest import psutil from psutil._compat import PY3, callable, long, wraps # =================================================================== # --- Constants # =================================================================== # conf for retry_before_failing() decorator NO_RETRIES = 10 # bytes tolerance for OS memory related tests TOLERANCE = 500 * 1024 # 500KB 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( os.path.dirname(__file__)), 'examples')) POSIX = os.name == 'posix' LINUX = sys.platform.startswith("linux") WINDOWS = sys.platform.startswith("win32") OSX = sys.platform.startswith("darwin") BSD = sys.platform.startswith("freebsd") SUNOS = sys.platform.startswith("sunos") VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil) if x.startswith('STATUS_')] # =================================================================== # --- Utility functions # =================================================================== _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(2);" 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(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') # could have used NamedTemporaryFile(delete=False) but it's # >= 2.6 only fd, path = tempfile.mkstemp(prefix=TESTFILE_PREFIX) _testfiles.append(path) f = open(path, 'wb') try: f.write(src) f.flush() subp = get_test_subprocess([PYTHON, f.name], stdout=None, stderr=None) wait_for_pid(subp.pid) return subp finally: f.close() def warn(msg): """Raise a warning msg.""" warnings.warn(msg, UserWarning) def register_warning(msg): """Register a warning which will be printed on interpreter exit.""" atexit.register(lambda: warn(msg)) def sh(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE): """run cmd in a subprocess and return its output. raises RuntimeError on error. """ p = subprocess.Popen(cmdline, shell=True, stdout=stdout, stderr=stderr) stdout, stderr = p.communicate() if p.returncode != 0: raise RuntimeError(stderr) if stderr: warn(stderr) if PY3: stdout = str(stdout, sys.stdout.encoding) return stdout.strip() def which(program): """Same as UNIX which command. Return None on command not found.""" def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None 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) def wait_for_pid(pid, timeout=1): """Wait for pid to show up in the process list then return. Used in the test suite to give time the sub process to initialize. """ raise_at = time.time() + timeout while 1: if pid in psutil.get_pid_list(): # give it one more iteration to allow full initialization time.sleep(0.01) return time.sleep(0.0001) if time.time() >= raise_at: raise RuntimeError("Timed out") def reap_children(search_all=False): """Kill any subprocess started by this test suite and ensure that no zombies stick around to hog resources and create problems when looking for refleaks. """ pids = _subprocesses_started if search_all: this_process = psutil.Process(os.getpid()) for p in this_process.get_children(recursive=True): pids.add(p.pid) while pids: pid = pids.pop() try: child = psutil.Process(pid) child.kill() except psutil.NoSuchProcess: pass except psutil.AccessDenied: warn("couldn't kill child process with pid %s" % pid) else: child.wait(timeout=3) def check_ip_address(addr, family): """Attempts to check IP address's validity.""" if not addr: return if family in (AF_INET, AF_INET6): assert isinstance(addr, tuple) ip, port = addr assert isinstance(port, int), port if family == AF_INET: ip = list(map(int, ip.split('.'))) assert len(ip) == 4, ip for num in ip: assert 0 <= num <= 255, ip assert 0 <= port <= 65535, port elif family == AF_UNIX: assert isinstance(addr, (str, None)) else: raise ValueError("unknown family %r", family) def check_connection(conn): """Check validity of a connection namedtuple.""" valid_conn_states = [getattr(psutil, x) for x in dir(psutil) if x.startswith('CONN_')] 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(conn.laddr, conn.family) check_ip_address(conn.raddr, 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) s.bind((conn.laddr[0], 0)) s.close() 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: dupsock = None try: try: dupsock = socket.fromfd(conn.fd, conn.family, conn.type) except (socket.error, OSError): err = sys.exc_info()[1] if err.args[0] != errno.EBADF: raise else: # python >= 2.5 if hasattr(dupsock, "family"): assert dupsock.family == conn.family assert dupsock.type == conn.type finally: if dupsock is not None: dupsock.close() def safe_remove(file): "Convenience function for removing temporary test files" try: os.remove(file) except OSError: err = sys.exc_info()[1] if err.errno != errno.ENOENT: raise def safe_rmdir(dir): "Convenience function for removing temporary test directories" try: os.rmdir(dir) except OSError: err = sys.exc_info()[1] if err.errno != errno.ENOENT: raise def call_until(fun, expr, timeout=1): """Keep calling function for timeout secs and exit if eval() expression is True. """ stop_at = time.time() + timeout while time.time() < stop_at: ret = fun() if eval(expr): return ret time.sleep(0.001) raise RuntimeError('timed out (ret=%r)' % ret) def retry_before_failing(ntimes=None): """Decorator which runs a test function and retries N times before actually failing. """ def decorator(fun): @wraps(fun) def wrapper(*args, **kwargs): for x in range(ntimes or NO_RETRIES): try: return fun(*args, **kwargs) except AssertionError: err = sys.exc_info()[1] raise return wrapper return decorator def skip_on_access_denied(only_if=None): """Decorator to Ignore AccessDenied exceptions.""" def decorator(fun): @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__ self = args[0] if hasattr(self, 'skip'): # python >= 2.7 self.skip(msg) else: register_warning(msg) return wrapper return decorator def skip_on_not_implemented(only_if=None): """Decorator to Ignore NotImplementedError exceptions.""" def decorator(fun): @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__ self = args[0] if hasattr(self, 'skip'): # python >= 2.7 self.skip(msg) else: register_warning(msg) return wrapper return decorator def supports_ipv6(): """Return True if IPv6 is supported on this platform.""" if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"): return False sock = None try: try: sock = socket.socket(AF_INET6, SOCK_STREAM) sock.bind(("::1", 0)) except (socket.error, socket.gaierror): return False else: return True finally: if sock is not None: sock.close() class ThreadTask(threading.Thread): """A thread object used for running process thread tests.""" def __init__(self): threading.Thread.__init__(self) self._running = False self._interval = None self._flag = threading.Event() def __repr__(self): name = self.__class__.__name__ return '<%s running=%s at %#x>' % (name, self._running, id(self)) def start(self, interval=0.001): """Start thread and keep it running until an explicit stop() request. Polls for shutdown every 'timeout' seconds. """ if self._running: raise ValueError("already started") self._interval = interval threading.Thread.start(self) self._flag.wait() def run(self): self._running = True self._flag.set() while self._running: time.sleep(self._interval) def stop(self): """Stop thread execution and and waits until it is stopped.""" if not self._running: raise ValueError("already stopped") self._running = False self.join() # =================================================================== # --- Support for python < 2.7 in case unittest2 is not installed # =================================================================== if not hasattr(unittest, 'skip'): register_warning("unittest2 module is not installed; a serie of pretty " "darn ugly workarounds will be used") class SkipTest(Exception): pass class TestCase(unittest.TestCase): def _safe_repr(self, obj): MAX_LENGTH = 80 try: result = repr(obj) except Exception: result = object.__repr__(obj) if len(result) < MAX_LENGTH: return result return result[:MAX_LENGTH] + ' [truncated]...' def _fail_w_msg(self, a, b, middle, msg): self.fail(msg or '%s %s %s' % (self._safe_repr(a), middle, self._safe_repr(b))) def skip(self, msg): raise SkipTest(msg) def assertIn(self, a, b, msg=None): if a not in b: self._fail_w_msg(a, b, 'not found in', msg) def assertNotIn(self, a, b, msg=None): if a in b: self._fail_w_msg(a, b, 'found in', msg) def assertGreater(self, a, b, msg=None): if not a > b: self._fail_w_msg(a, b, 'not greater than', msg) def assertGreaterEqual(self, a, b, msg=None): if not a >= b: self._fail_w_msg(a, b, 'not greater than or equal to', msg) def assertLess(self, a, b, msg=None): if not a < b: self._fail_w_msg(a, b, 'not less than', msg) def assertLessEqual(self, a, b, msg=None): if not a <= b: self._fail_w_msg(a, b, 'not less or equal to', msg) def assertIsInstance(self, a, b, msg=None): if not isinstance(a, b): self.fail(msg or '%s is not an instance of %r' % (self._safe_repr(a), b)) def assertAlmostEqual(self, a, b, msg=None, delta=None): if delta is not None: if abs(a - b) <= delta: return self.fail(msg or '%s != %s within %s delta' % (self._safe_repr(a), self._safe_repr(b), self._safe_repr(delta))) else: self.assertEqual(a, b, msg=msg) def skipIf(condition, reason): def decorator(fun): @wraps(fun) def wrapper(*args, **kwargs): self = args[0] if condition: sys.stdout.write("skipped-") sys.stdout.flush() if warn: objname = "%s.%s" % (self.__class__.__name__, fun.__name__) msg = "%s was skipped" % objname if reason: msg += "; reason: " + repr(reason) register_warning(msg) return else: return fun(*args, **kwargs) return wrapper return decorator def skipUnless(condition, reason): if not condition: return unittest.skipIf(True, reason) return unittest.skipIf(False, reason) unittest.TestCase = TestCase unittest.skipIf = skipIf unittest.skipUnless = skipUnless del TestCase, skipIf, skipUnless # =================================================================== # --- System-related API tests # =================================================================== class TestSystemAPIs(unittest.TestCase): """Tests for system-related APIs.""" def setUp(self): safe_remove(TESTFN) safe_rmdir(TESTFN_UNICODE) 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()]) def test_wait_procs(self): l = [] callback = lambda p: l.append(p.pid) sproc1 = get_test_subprocess() sproc2 = get_test_subprocess() sproc3 = get_test_subprocess() procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)] t = time.time() gone, alive = psutil.wait_procs(procs, 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, 'retcode')) sproc3.terminate() gone, alive = psutil.wait_procs(procs, 0.03, callback=callback) self.assertEqual(len(gone), 1) self.assertEqual(len(alive), 2) self.assertIn(sproc3.pid, [x.pid for x in gone]) if POSIX: self.assertEqual(gone.pop().retcode, signal.SIGTERM) else: self.assertEqual(gone.pop().retcode, 1) self.assertEqual(l, [sproc3.pid]) for p in alive: self.assertFalse(hasattr(p, 'retcode')) sproc1.terminate() sproc2.terminate() gone, alive = psutil.wait_procs(procs, 0.03, callback=callback) self.assertEqual(len(gone), 3) self.assertEqual(len(alive), 0) self.assertEqual(set(l), set([sproc1.pid, sproc2.pid, sproc3.pid])) for p in gone: self.assertTrue(hasattr(p, 'retcode')) def test_TOTAL_PHYMEM(self): x = psutil.TOTAL_PHYMEM self.assertIsInstance(x, (int, long)) self.assertGreater(x, 0) self.assertEqual(x, psutil.virtual_memory().total) def test_BOOT_TIME(self, arg=None): x = arg or psutil.BOOT_TIME self.assertIsInstance(x, float) self.assertGreater(x, 0) self.assertLess(x, time.time()) def test_get_boot_time(self): self.test_BOOT_TIME(psutil.get_boot_time()) if WINDOWS: # work around float precision issues; give it 1 secs tolerance diff = abs(psutil.get_boot_time() - psutil.BOOT_TIME) self.assertLess(diff, 1) else: self.assertEqual(psutil.get_boot_time(), psutil.BOOT_TIME) def test_NUM_CPUS(self): self.assertEqual(psutil.NUM_CPUS, len(psutil.cpu_times(percpu=True))) self.assertGreaterEqual(psutil.NUM_CPUS, 1) @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_deprecated_apis(self): s = socket.socket() s.bind(('localhost', 0)) s.listen(1) warnings.filterwarnings("error") p = psutil.Process(os.getpid()) try: self.assertRaises(DeprecationWarning, psutil.virtmem_usage) self.assertRaises(DeprecationWarning, psutil.used_phymem) self.assertRaises(DeprecationWarning, psutil.avail_phymem) self.assertRaises(DeprecationWarning, psutil.total_virtmem) self.assertRaises(DeprecationWarning, psutil.used_virtmem) self.assertRaises(DeprecationWarning, psutil.avail_virtmem) self.assertRaises(DeprecationWarning, psutil.phymem_usage) self.assertRaises(DeprecationWarning, psutil.get_process_list) self.assertRaises(DeprecationWarning, psutil.network_io_counters) if LINUX: self.assertRaises(DeprecationWarning, psutil.phymem_buffers) self.assertRaises(DeprecationWarning, psutil.cached_phymem) try: p.nice except DeprecationWarning: pass else: self.fail("p.nice didn't raise DeprecationWarning") ret = call_until(p.get_connections, "len(ret) != 0", timeout=1) self.assertRaises(DeprecationWarning, getattr, ret[0], 'local_address') self.assertRaises(DeprecationWarning, getattr, ret[0], 'remote_address') finally: s.close() warnings.resetwarnings() def test_deprecated_apis_retval(self): warnings.filterwarnings("ignore") p = psutil.Process(os.getpid()) try: self.assertEqual(psutil.total_virtmem(), psutil.swap_memory().total) self.assertEqual(p.nice, p.get_nice()) finally: warnings.resetwarnings() def test_virtual_memory(self): mem = psutil.virtual_memory() assert mem.total > 0, mem assert mem.available > 0, mem assert 0 <= mem.percent <= 100, mem assert mem.used > 0, mem assert mem.free >= 0, mem for name in mem._fields: if name != 'total': value = getattr(mem, name) if not value >= 0: self.fail("%r < 0 (%s)" % (name, value)) if value > mem.total: self.fail("%r > total (total=%s, %s=%s)" % (name, mem.total, name, value)) def test_swap_memory(self): mem = psutil.swap_memory() assert mem.total >= 0, mem assert mem.used >= 0, mem 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) assert psutil.pid_exists(sproc.pid) p = psutil.Process(sproc.pid) p.kill() p.wait() self.assertFalse(psutil.pid_exists(sproc.pid)) self.assertFalse(psutil.pid_exists(-1)) def test_pid_exists_2(self): reap_children() pids = psutil.get_pid_list() for pid in pids: try: assert psutil.pid_exists(pid) except AssertionError: # in case the process disappeared in meantime fail only # if it is no longer in get_pid_list() time.sleep(.1) if pid in psutil.get_pid_list(): self.fail(pid) pids = range(max(pids) + 5000, max(pids) + 6000) for pid in pids: self.assertFalse(psutil.pid_exists(pid)) def test_get_pid_list(self): plist = [x.pid for x in psutil.process_iter()] pidlist = psutil.get_pid_list() self.assertEqual(plist.sort(), pidlist.sort()) # make sure every pid is unique self.assertEqual(len(pidlist), len(set(pidlist))) def test_test(self): # test for psutil.test() function stdout = sys.stdout sys.stdout = DEVNULL try: psutil.test() finally: sys.stdout = stdout def test_sys_cpu_times(self): total = 0 times = psutil.cpu_times() sum(times) for cp_time in times: self.assertIsInstance(cp_time, float) self.assertGreaterEqual(cp_time, 0.0) total += cp_time self.assertEqual(total, sum(times)) str(times) if not WINDOWS: # CPU times are always supposed to increase over time or # remain the same but never go backwards, see: # https://code.google.com/p/psutil/issues/detail?id=392 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))) if not WINDOWS: # CPU times are always supposed to increase over time or # remain the same but never go backwards, see: # https://code.google.com/p/psutil/issues/detail?id=392 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_times2(self): tot1 = psutil.cpu_times(percpu=True) stop_at = time.time() + 0.1 while 1: if time.time() >= stop_at: break tot2 = psutil.cpu_times(percpu=True) for t1, t2 in zip(tot1, tot2): t1, t2 = sum(t1), sum(t2) difference = t2 - t1 if difference >= 0.05: return self.fail() def _test_cpu_percent(self, percent): self.assertIsInstance(percent, float) self.assertGreaterEqual(percent, 0.0) self.assertLessEqual(percent, 100.0) def test_sys_cpu_percent(self): psutil.cpu_percent(interval=0.001) for x in range(1000): self._test_cpu_percent(psutil.cpu_percent(interval=None)) def test_sys_per_cpu_percent(self): self.assertEqual(len(psutil.cpu_percent(interval=0.001, percpu=True)), psutil.NUM_CPUS) for x in range(1000): percents = psutil.cpu_percent(interval=None, percpu=True) for percent in percents: self._test_cpu_percent(percent) def test_sys_cpu_times_percent(self): psutil.cpu_times_percent(interval=0.001) for x in range(1000): cpu = psutil.cpu_times_percent(interval=None) for percent in cpu: self._test_cpu_percent(percent) self._test_cpu_percent(sum(cpu)) def test_sys_per_cpu_times_percent(self): self.assertEqual(len(psutil.cpu_times_percent(interval=0.001, percpu=True)), psutil.NUM_CPUS) for x in range(1000): cpus = psutil.cpu_times_percent(interval=None, percpu=True) for cpu in cpus: for percent in cpu: self._test_cpu_percent(percent) self._test_cpu_percent(sum(cpu)) @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: err = sys.exc_info()[1] 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://code.google.com/p/psutil/issues/detail?id=416 os.mkdir(TESTFN_UNICODE) psutil.disk_usage(TESTFN_UNICODE) @unittest.skipIf(POSIX and not hasattr(os, 'statvfs'), "os.statvfs() function not available on this platform") def test_disk_partitions(self): # all = False for disk in psutil.disk_partitions(all=False): 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 for disk in psutil.disk_partitions(all=True): if not WINDOWS: try: os.stat(disk.mountpoint) except OSError: # http://mail.python.org/pipermail/python-dev/2012-June/120787.html err = sys.exc_info()[1] if err.errno not in (errno.EPERM, errno.EACCES): raise else: 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) 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) assert ret != [] for key in ret: assert key check_ntuple(ret[key]) def test_disk_io_counters(self): def check_ntuple(nt): self.assertEqual(nt[0], nt.read_count) self.assertEqual(nt[1], nt.write_count) self.assertEqual(nt[2], nt.read_bytes) self.assertEqual(nt[3], nt.write_bytes) self.assertEqual(nt[4], nt.read_time) self.assertEqual(nt[5], nt.write_time) assert nt.read_count >= 0, nt assert nt.write_count >= 0, nt assert nt.read_bytes >= 0, nt assert nt.write_bytes >= 0, nt assert nt.read_time >= 0, nt assert nt.write_time >= 0, nt ret = psutil.disk_io_counters(perdisk=False) check_ntuple(ret) ret = psutil.disk_io_counters(perdisk=True) # 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: # http://code.google.com/p/psutil/issues/detail?id=338 while key[-1].isdigit(): key = key[:-1] self.assertNotIn(key, ret.keys()) def test_get_users(self): users = psutil.get_users() assert users for user in users: assert user.name, user user.terminal user.host assert user.started > 0.0, user datetime.datetime.fromtimestamp(user.started) # =================================================================== # --- 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_no_pid(self): self.assertEqual(psutil.Process().pid, os.getpid()) def test_kill(self): sproc = get_test_subprocess(wait=True) test_pid = sproc.pid p = psutil.Process(test_pid) name = p.name p.kill() p.wait() self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON) def test_terminate(self): sproc = get_test_subprocess(wait=True) test_pid = sproc.pid p = psutil.Process(test_pid) name = p.name p.terminate() p.wait() self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON) def test_send_signal(self): if POSIX: sig = signal.SIGKILL else: sig = signal.SIGTERM sproc = get_test_subprocess() test_pid = sproc.pid p = psutil.Process(test_pid) name = p.name p.send_signal(sig) p.wait() self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON) def test_wait(self): # check exit code signal sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.kill() code = p.wait() if os.name == 'posix': self.assertEqual(code, signal.SIGKILL) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.terminate() code = p.wait() if os.name == 'posix': self.assertEqual(code, signal.SIGTERM) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) # check sys.exit() code code = "import time, sys; time.sleep(0.01); sys.exit(5);" sproc = get_test_subprocess([PYTHON, "-c", code]) p = psutil.Process(sproc.pid) self.assertEqual(p.wait(), 5) self.assertFalse(p.is_running()) # Test wait() issued twice. # It is not supposed to raise NSP when the process is gone. # On UNIX this should return None, on Windows it should keep # returning the exit code. sproc = get_test_subprocess([PYTHON, "-c", code]) p = psutil.Process(sproc.pid) self.assertEqual(p.wait(), 5) self.assertIn(p.wait(), (5, None)) # test timeout sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.name self.assertRaises(psutil.TimeoutExpired, p.wait, 0.01) # timeout < 0 not allowed self.assertRaises(ValueError, p.wait, -1) @unittest.skipUnless(POSIX, '') # XXX why is this 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(2)'];" % PYTHON code += "sp = Popen(cmd, stdout=PIPE);" code += "sys.stdout.write(str(sp.pid));" sproc = get_test_subprocess([PYTHON, "-c", code], stdout=subprocess.PIPE) grandson_pid = int(sproc.stdout.read()) grandson_proc = psutil.Process(grandson_pid) try: self.assertRaises(psutil.TimeoutExpired, grandson_proc.wait, 0.01) grandson_proc.kill() ret = grandson_proc.wait() self.assertEqual(ret, None) finally: if grandson_proc.is_running(): grandson_proc.kill() grandson_proc.wait() def test_wait_timeout_0(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) self.assertRaises(psutil.TimeoutExpired, p.wait, 0) p.kill() stop_at = time.time() + 2 while 1: try: code = p.wait(0) except psutil.TimeoutExpired: if time.time() >= stop_at: raise else: break if os.name == 'posix': self.assertEqual(code, signal.SIGKILL) else: self.assertEqual(code, 0) self.assertFalse(p.is_running()) def test_cpu_percent(self): p = psutil.Process(os.getpid()) p.get_cpu_percent(interval=0.001) p.get_cpu_percent(interval=0.001) for x in range(100): percent = p.get_cpu_percent(interval=None) self.assertIsInstance(percent, float) self.assertGreaterEqual(percent, 0.0) if os.name != 'posix': self.assertLessEqual(percent, 100.0) else: self.assertGreaterEqual(percent, 0.0) def test_cpu_times(self): times = psutil.Process(os.getpid()).get_cpu_times() assert (times.user > 0.0) or (times.system > 0.0), times # make sure returned values can be pretty printed with strftime time.strftime("%H:%M:%S", time.localtime(times.user)) time.strftime("%H:%M:%S", time.localtime(times.system)) # Test Process.cpu_times() against os.times() # os.times() is broken on Python 2.6 # http://bugs.python.org/issue1040026 # XXX fails on OSX: not sure if it's for os.times(). We should # try this with Python 2.7 and re-enable the test. @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(os.getpid()).get_cpu_times() utime, ktime = os.times()[:2] # Use os.times()[:2] as base values to compare our results # using a tolerance of +/- 0.1 seconds. # It will fail if the difference between the values is > 0.1s. if (max([user_time, utime]) - min([user_time, utime])) > 0.1: self.fail("expected: %s, found: %s" % (utime, user_time)) if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1: self.fail("expected: %s, found: %s" % (ktime, kernel_time)) def test_create_time(self): sproc = get_test_subprocess(wait=True) now = time.time() p = psutil.Process(sproc.pid) create_time = p.create_time # Use time.time() as base value to compare our result using a # tolerance of +/- 1 second. # It will fail if the difference between the values is > 2s. difference = abs(create_time - now) if difference > 2: self.fail("expected: %s, found: %s, difference: %s" % (now, create_time, difference)) # make sure returned value can be pretty printed with strftime time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time)) @unittest.skipIf(WINDOWS, 'windows only') def test_terminal(self): terminal = psutil.Process(os.getpid()).terminal if sys.stdin.isatty(): self.assertEqual(terminal, sh('tty')) else: assert terminal, repr(terminal) @unittest.skipIf(not hasattr(psutil.Process, 'get_io_counters'), 'not available on this platform') @skip_on_not_implemented(only_if=LINUX) def test_get_io_counters(self): p = psutil.Process(os.getpid()) # test reads io1 = p.get_io_counters() f = open(PYTHON, 'rb') f.read() f.close() io2 = p.get_io_counters() if not BSD: assert io2.read_count > io1.read_count, (io1, io2) self.assertEqual(io2.write_count, io1.write_count) assert io2.read_bytes >= io1.read_bytes, (io1, io2) assert io2.write_bytes >= io1.write_bytes, (io1, io2) # test writes io1 = p.get_io_counters() f = tempfile.TemporaryFile(prefix=TESTFILE_PREFIX) if PY3: f.write(bytes("x" * 1000000, 'ascii')) else: f.write("x" * 1000000) f.close() io2 = p.get_io_counters() assert io2.write_count >= io1.write_count, (io1, io2) assert io2.write_bytes >= io1.write_bytes, (io1, io2) assert io2.read_count >= io1.read_count, (io1, io2) assert io2.read_bytes >= io1.read_bytes, (io1, io2) # Linux and Windows Vista+ @unittest.skipUnless(hasattr(psutil.Process, 'get_ionice'), 'Linux and Windows Vista only') def test_get_set_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(os.getpid()) try: p.set_ionice(2) ioclass, value = p.get_ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 4) # p.set_ionice(3) ioclass, value = p.get_ionice() self.assertEqual(ioclass, 3) self.assertEqual(value, 0) # p.set_ionice(2, 0) ioclass, value = p.get_ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 0) p.set_ionice(2, 7) ioclass, value = p.get_ionice() self.assertEqual(ioclass, 2) self.assertEqual(value, 7) self.assertRaises(ValueError, p.set_ionice, 2, 10) finally: p.set_ionice(IOPRIO_CLASS_NONE) else: p = psutil.Process(os.getpid()) original = p.get_ionice() try: value = 0 # very low if original == value: value = 1 # low p.set_ionice(value) self.assertEqual(p.get_ionice(), value) finally: p.set_ionice(original) # self.assertRaises(ValueError, p.set_ionice, 3) self.assertRaises(TypeError, p.set_ionice, 2, 1) @unittest.skipUnless(hasattr(psutil.Process, 'get_rlimit'), "only available on Linux >= 2.6.36") def test_get_rlimit(self): import resource p = psutil.Process(os.getpid()) names = [x for x in dir(psutil) if x.startswith('RLIMIT_')] for name in names: value = getattr(psutil, name) if name in dir(resource): self.assertEqual(value, getattr(resource, name)) self.assertEqual(p.get_rlimit(value), resource.getrlimit(value)) else: ret = p.get_rlimit(value) self.assertEqual(len(ret), 2) self.assertGreaterEqual(ret[0], -1) self.assertGreaterEqual(ret[1], -1) @unittest.skipUnless(hasattr(psutil.Process, 'set_rlimit'), "only available on Linux >= 2.6.36") def test_set_rlimit(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.set_rlimit(psutil.RLIMIT_NOFILE, (5, 5)) self.assertEqual(p.get_rlimit(psutil.RLIMIT_NOFILE), (5, 5)) def test_get_num_threads(self): # on certain platforms such as Linux we might test for exact # thread number, since we always have with 1 thread per process, # but this does not apply across all platforms (OSX, Windows) p = psutil.Process(os.getpid()) step1 = p.get_num_threads() thread = ThreadTask() thread.start() try: step2 = p.get_num_threads() self.assertEqual(step2, step1 + 1) thread.stop() finally: if thread._running: thread.stop() @unittest.skipUnless(WINDOWS, 'Windows only') def test_get_num_handles(self): # a better test is done later into test/_windows.py p = psutil.Process(os.getpid()) self.assertGreater(p.get_num_handles(), 0) def test_get_threads(self): p = psutil.Process(os.getpid()) step1 = p.get_threads() thread = ThreadTask() thread.start() try: step2 = p.get_threads() self.assertEqual(len(step2), len(step1) + 1) # on Linux, first thread id is supposed to be this process if LINUX: self.assertEqual(step2[0].id, os.getpid()) athread = step2[0] # test named tuple self.assertEqual(athread.id, athread[0]) self.assertEqual(athread.user_time, athread[1]) self.assertEqual(athread.system_time, athread[2]) # test num threads thread.stop() finally: if thread._running: thread.stop() def test_get_memory_info(self): p = psutil.Process(os.getpid()) # step 1 - get a base value to compare our results rss1, vms1 = p.get_memory_info() percent1 = p.get_memory_percent() self.assertGreater(rss1, 0) self.assertGreater(vms1, 0) # step 2 - allocate some memory memarr = [None] * 1500000 rss2, vms2 = p.get_memory_info() percent2 = p.get_memory_percent() # make sure that the memory usage bumped up self.assertGreater(rss2, rss1) self.assertGreaterEqual(vms2, vms1) # vms might be equal self.assertGreater(percent2, percent1) del memarr # def test_get_ext_memory_info(self): # # tested later in fetch all test suite def test_get_memory_maps(self): p = psutil.Process(os.getpid()) maps = p.get_memory_maps() paths = [x for x in maps] self.assertEqual(len(paths), len(set(paths))) ext_maps = p.get_memory_maps(grouped=False) for nt in maps: if not nt.path.startswith('['): assert os.path.isabs(nt.path), nt.path if POSIX: assert os.path.exists(nt.path), nt.path else: # XXX - On Windows we have this strange behavior with # 64 bit dlls: they are visible via explorer but cannot # be accessed via os.stat() (wtf?). if '64' not in os.path.basename(nt.path): assert os.path.exists(nt.path), nt.path for nt in ext_maps: for fname in nt._fields: value = getattr(nt, fname) if fname == 'path': continue elif fname in ('addr', 'perms'): assert value, value else: self.assertIsInstance(value, (int, long)) assert value >= 0, value def test_get_memory_percent(self): p = psutil.Process(os.getpid()) self.assertGreater(p.get_memory_percent(), 0.0) def test_pid(self): sproc = get_test_subprocess() self.assertEqual(psutil.Process(sproc.pid).pid, sproc.pid) def test_is_running(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) assert p.is_running() assert p.is_running() p.kill() p.wait() assert not p.is_running() assert not p.is_running() def test_exe(self): sproc = get_test_subprocess(wait=True) exe = psutil.Process(sproc.pid).exe try: self.assertEqual(exe, PYTHON) except AssertionError: if WINDOWS and len(exe) == len(PYTHON): # on Windows we don't care about case sensitivity self.assertEqual(exe.lower(), PYTHON.lower()) 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(2)"] sproc = get_test_subprocess(cmdline, wait=True) self.assertEqual(' '.join(psutil.Process(sproc.pid).cmdline), ' '.join(cmdline)) 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.skipUnless(POSIX, 'posix only') def test_uids(self): p = psutil.Process(os.getpid()) real, effective, saved = p.uids # os.getuid() refers to "real" uid self.assertEqual(real, os.getuid()) # os.geteuid() refers to "effective" uid self.assertEqual(effective, os.geteuid()) # no such thing as os.getsuid() ("saved" uid), but starting # from python 2.7 we have os.getresuid()[2] if hasattr(os, "getresuid"): self.assertEqual(saved, os.getresuid()[2]) @unittest.skipUnless(POSIX, 'posix only') def test_gids(self): p = psutil.Process(os.getpid()) real, effective, saved = p.gids # os.getuid() refers to "real" uid self.assertEqual(real, os.getgid()) # os.geteuid() refers to "effective" uid self.assertEqual(effective, os.getegid()) # no such thing as os.getsuid() ("saved" uid), but starting # from python 2.7 we have os.getresgid()[2] if hasattr(os, "getresuid"): self.assertEqual(saved, os.getresgid()[2]) def test_nice(self): p = psutil.Process(os.getpid()) self.assertRaises(TypeError, p.set_nice, "str") if os.name == 'nt': try: self.assertEqual(p.get_nice(), psutil.NORMAL_PRIORITY_CLASS) p.set_nice(psutil.HIGH_PRIORITY_CLASS) self.assertEqual(p.get_nice(), psutil.HIGH_PRIORITY_CLASS) p.set_nice(psutil.NORMAL_PRIORITY_CLASS) self.assertEqual(p.get_nice(), psutil.NORMAL_PRIORITY_CLASS) finally: p.set_nice(psutil.NORMAL_PRIORITY_CLASS) else: try: try: first_nice = p.get_nice() p.set_nice(1) self.assertEqual(p.get_nice(), 1) # going back to previous nice value raises AccessDenied on OSX if not OSX: p.set_nice(0) self.assertEqual(p.get_nice(), 0) except psutil.AccessDenied: pass finally: try: p.set_nice(first_nice) except psutil.AccessDenied: pass def test_status(self): p = psutil.Process(os.getpid()) 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) 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 @unittest.skipUnless(hasattr(psutil.Process, "getcwd"), 'not available on this platform') def test_getcwd(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) self.assertEqual(p.getcwd(), os.getcwd()) @unittest.skipIf(not hasattr(psutil.Process, "getcwd"), 'not available on this platform') def test_getcwd_2(self): cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(2)"] sproc = get_test_subprocess(cmd, wait=True) p = psutil.Process(sproc.pid) call_until(p.getcwd, "ret == os.path.dirname(os.getcwd())", timeout=1) @unittest.skipIf(not hasattr(psutil.Process, "get_cpu_affinity"), 'not available on this platform') def test_cpu_affinity(self): p = psutil.Process(os.getpid()) initial = p.get_cpu_affinity() all_cpus = list(range(len(psutil.cpu_percent(percpu=True)))) # for n in all_cpus: p.set_cpu_affinity([n]) self.assertEqual(p.get_cpu_affinity(), [n]) # p.set_cpu_affinity(all_cpus) self.assertEqual(p.get_cpu_affinity(), all_cpus) # p.set_cpu_affinity(initial) invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10] self.assertRaises(ValueError, p.set_cpu_affinity, invalid_cpu) def test_get_open_files(self): # current process p = psutil.Process(os.getpid()) files = p.get_open_files() self.assertFalse(TESTFN in files) f = open(TESTFN, 'w') call_until(p.get_open_files, "len(ret) != %i" % len(files)) filenames = [x.path for x in p.get_open_files()] self.assertIn(TESTFN, filenames) f.close() for file in filenames: assert os.path.isfile(file), file # another process cmdline = "import time; f = open(r'%s', 'r'); time.sleep(2);" % TESTFN sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True) p = psutil.Process(sproc.pid) for x in range(100): filenames = [x.path for x in p.get_open_files()] if TESTFN in filenames: break time.sleep(.01) else: self.assertIn(TESTFN, filenames) for file in filenames: assert os.path.isfile(file), file def test_get_open_files2(self): # test fd and path fields fileobj = open(TESTFN, 'w') p = psutil.Process(os.getpid()) for path, fd in p.get_open_files(): if path == fileobj.name or fd == fileobj.fileno(): break else: self.fail("no file found; files=%s" % repr(p.get_open_files())) self.assertEqual(path, fileobj.name) if WINDOWS: self.assertEqual(fd, -1) else: self.assertEqual(fd, fileobj.fileno()) # test positions ntuple = p.get_open_files()[0] self.assertEqual(ntuple[0], ntuple.path) self.assertEqual(ntuple[1], ntuple.fd) # test file is gone fileobj.close() self.assertTrue(fileobj.name not in p.get_open_files()) def test_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 def test_get_connections(self): arg = "import socket, time;" \ "s = socket.socket();" \ "s.bind(('127.0.0.1', 0));" \ "s.listen(1);" \ "conn, addr = s.accept();" \ "time.sleep(2);" sproc = get_test_subprocess([PYTHON, "-c", arg]) p = psutil.Process(sproc.pid) cons = call_until(p.get_connections, "len(ret) != 0", timeout=1) self.assertEqual(len(cons), 1) con = cons[0] check_connection(con) self.assertEqual(con.family, AF_INET) self.assertEqual(con.type, SOCK_STREAM) self.assertEqual(con.status, psutil.CONN_LISTEN, con.status) self.assertEqual(con.laddr[0], '127.0.0.1') self.assertEqual(con.raddr, ()) # test positions self.assertEqual(con[0], con.fd) self.assertEqual(con[1], con.family) self.assertEqual(con[2], con.type) self.assertEqual(con[3], con.laddr) self.assertEqual(con[4], con.raddr) self.assertEqual(con[5], con.status) # test kind arg self.assertRaises(ValueError, p.get_connections, 'foo') @unittest.skipUnless(supports_ipv6(), 'IPv6 is not supported') def test_get_connections_ipv6(self): s = socket.socket(AF_INET6, SOCK_STREAM) s.bind(('::1', 0)) s.listen(1) cons = psutil.Process(os.getpid()).get_connections() s.close() self.assertEqual(len(cons), 1) self.assertEqual(cons[0].laddr[0], '::1') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'AF_UNIX is not supported') def test_get_connections_unix(self): def check(type): safe_remove(TESTFN) sock = socket.socket(AF_UNIX, type) try: sock.bind(TESTFN) conn = psutil.Process(os.getpid()).get_connections(kind='unix')[0] check_connection(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) finally: sock.close() check(SOCK_STREAM) check(SOCK_DGRAM) @unittest.skipUnless(hasattr(socket, "fromfd"), 'socket.fromfd() is not availble') @unittest.skipIf(WINDOWS or SUNOS, 'connection fd available on this platform') def test_connection_fromfd(self): sock = socket.socket() sock.bind(('localhost', 0)) sock.listen(1) p = psutil.Process(os.getpid()) for conn in p.get_connections(): if conn.fd == sock.fileno(): break else: sock.close() self.fail("couldn't find socket fd") dupsock = socket.fromfd(conn.fd, conn.family, conn.type) try: self.assertEqual(dupsock.getsockname(), conn.laddr) self.assertNotEqual(sock.fileno(), dupsock.fileno()) finally: sock.close() dupsock.close() def test_get_connections_all(self): tcp_template = textwrap.dedent(""" import socket s = socket.socket($family, socket.SOCK_STREAM) s.bind(('$addr', 0)) s.listen(1) conn, addr = s.accept() """) udp_template = textwrap.dedent(""" import socket, time s = socket.socket($family, socket.SOCK_DGRAM) s.bind(('$addr', 0)) time.sleep(2) """) from string import Template tcp4_template = Template(tcp_template).substitute( family=int(AF_INET), addr="127.0.0.1") udp4_template = Template(udp_template).substitute( family=int(AF_INET), addr="127.0.0.1") tcp6_template = Template(tcp_template).substitute( family=int(AF_INET6), addr="::1") udp6_template = Template(udp_template).substitute( family=int(AF_INET6), addr="::1") # launch various subprocess instantiating a socket of various # families and types to enrich psutil results tcp4_proc = pyrun(tcp4_template) udp4_proc = pyrun(udp4_template) if supports_ipv6(): tcp6_proc = pyrun(tcp6_template) udp6_proc = pyrun(udp6_template) else: tcp6_proc = None udp6_proc = None # check matches against subprocesses just created all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6") def check_conn(proc, conn, family, type, laddr, raddr, status, kinds): self.assertEqual(conn.family, family) self.assertEqual(conn.type, type) self.assertIn(conn.laddr[0], laddr) self.assertEqual(conn.raddr, raddr) self.assertEqual(conn.status, status) for kind in all_kinds: cons = proc.get_connections(kind=kind) if kind in kinds: assert cons != [], cons else: self.assertEqual(cons, [], cons) for p in psutil.Process(os.getpid()).get_children(): for conn in p.get_connections(): # TCP v4 if p.pid == tcp4_proc.pid: check_conn(p, conn, AF_INET, SOCK_STREAM, "127.0.0.1", (), psutil.CONN_LISTEN, ("all", "inet", "inet4", "tcp", "tcp4")) # UDP v4 elif p.pid == udp4_proc.pid: check_conn(p, conn, AF_INET, SOCK_DGRAM, "127.0.0.1", (), 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, ("::", "::1"), (), 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, ("::", "::1"), (), psutil.CONN_NONE, ("all", "inet", "inet6", "udp", "udp6")) @unittest.skipUnless(POSIX, 'posix only') def test_get_num_fds(self): p = psutil.Process(os.getpid()) start = p.get_num_fds() file = open(TESTFN, 'w') self.assertEqual(p.get_num_fds(), start + 1) sock = socket.socket() self.assertEqual(p.get_num_fds(), start + 2) file.close() sock.close() self.assertEqual(p.get_num_fds(), start) @skip_on_not_implemented(only_if=LINUX) def test_get_num_ctx_switches(self): p = psutil.Process(os.getpid()) before = sum(p.get_num_ctx_switches()) for x in range(500000): after = sum(p.get_num_ctx_switches()) if after > before: return self.fail("num ctx switches still the same after 50.000 iterations") def test_parent_ppid(self): this_parent = os.getpid() sproc = get_test_subprocess() p = psutil.Process(sproc.pid) self.assertEqual(p.ppid, this_parent) self.assertEqual(p.parent.pid, this_parent) # no other process is supposed to have us as parent for p in psutil.process_iter(): if p.pid == sproc.pid: continue self.assertTrue(p.ppid != this_parent) def test_get_children(self): p = psutil.Process(os.getpid()) self.assertEqual(p.get_children(), []) self.assertEqual(p.get_children(recursive=True), []) sproc = get_test_subprocess() children1 = p.get_children() children2 = p.get_children(recursive=True) for children in (children1, children2): self.assertEqual(len(children), 1) self.assertEqual(children[0].pid, sproc.pid) self.assertEqual(children[0].ppid, os.getpid()) def test_get_children_recursive(self): # here we create a subprocess which creates another one as in: # A (parent) -> B (child) -> C (grandchild) s = "import subprocess, os, sys, time;" s += "PYTHON = os.path.realpath(sys.executable);" s += "cmd = [PYTHON, '-c', 'import time; time.sleep(2);'];" s += "subprocess.Popen(cmd);" s += "time.sleep(2);" get_test_subprocess(cmd=[PYTHON, "-c", s]) p = psutil.Process(os.getpid()) self.assertEqual(len(p.get_children(recursive=False)), 1) # give the grandchild some time to start stop_at = time.time() + 1.5 while time.time() < stop_at: children = p.get_children(recursive=True) if len(children) > 1: break self.assertEqual(len(children), 2) self.assertEqual(children[0].ppid, os.getpid()) self.assertEqual(children[1].ppid, children[0].pid) def test_get_children_duplicates(self): # find the process which has the highest number of children from psutil._compat import defaultdict table = defaultdict(int) for p in psutil.process_iter(): try: table[p.ppid] += 1 except psutil.Error: pass # this is the one, now let's make sure there are no duplicates pid = sorted(table.items(), key=lambda x: x[1])[-1][0] p = psutil.Process(pid) try: c = p.get_children(recursive=True) except psutil.AccessDenied: # windows pass else: self.assertEqual(len(c), len(set(c))) def test_suspend_resume(self): sproc = get_test_subprocess(wait=True) p = psutil.Process(sproc.pid) p.suspend() for x in range(100): if p.status == psutil.STATUS_STOPPED: break time.sleep(0.01) 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(os.getpid()) d = p.as_dict() try: import json except ImportError: pass else: json.loads(json.dumps(d)) # d = p.as_dict(attrs=['exe', 'name']) self.assertEqual(sorted(d.keys()), ['exe', 'name']) # p = psutil.Process(min(psutil.get_pid_list())) d = p.as_dict(attrs=['get_connections'], ad_value='foo') if not isinstance(d['connections'], list): self.assertEqual(d['connections'], 'foo') def test_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.kill() p.wait() for name in dir(p): if name.startswith('_')\ or name in ('pid', 'send_signal', 'is_running', 'set_ionice', 'wait', 'set_cpu_affinity', 'create_time', 'set_nice', 'nice'): continue try: # if name == 'get_rlimit' args = () meth = getattr(p, name) if callable(meth): if name == 'get_rlimit': args = (psutil.RLIMIT_NOFILE,) elif name == 'set_rlimit': args = (psutil.RLIMIT_NOFILE, (5, 5)) meth(*args) except psutil.NoSuchProcess: pass except NotImplementedError: pass else: self.fail("NoSuchProcess exception not raised for %r" % name) # other methods try: if os.name == 'posix': p.set_nice(1) else: p.set_nice(psutil.NORMAL_PRIORITY_CLASS) except psutil.NoSuchProcess: pass else: self.fail("exception not raised") if hasattr(p, 'set_ionice'): self.assertRaises(psutil.NoSuchProcess, p.set_ionice, 2) self.assertRaises(psutil.NoSuchProcess, p.send_signal, signal.SIGTERM) self.assertRaises(psutil.NoSuchProcess, p.set_nice, 0) self.assertFalse(p.is_running()) if hasattr(p, "set_cpu_affinity"): self.assertRaises(psutil.NoSuchProcess, p.set_cpu_affinity, [0]) @unittest.skipUnless(POSIX, 'posix only') def test_zombie_process(self): # 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 get_children(recursive=True). src = textwrap.dedent("""\ import os, sys, time, socket child_pid = os.fork() if child_pid > 0: time.sleep(3000) else: # this is the zombie process s = socket.socket(socket.AF_UNIX) s.connect('%s') if sys.version_info < (3, ): pid = str(os.getpid()) else: pid = bytes(str(os.getpid()), 'ascii') s.sendall(pid) s.close() """ % TESTFN) pyrun(src) sock = None try: sock = socket.socket(socket.AF_UNIX) sock.settimeout(2) sock.bind(TESTFN) sock.listen(1) conn, _ = sock.accept() zpid = int(conn.recv(1024)) zproc = psutil.Process(zpid) # Make sure we can re-instantiate the process after its # status changed to zombie and at least be able to # query its status. # XXX should we also assume ppid should be querable? call_until(lambda: zproc.status, "ret == psutil.STATUS_ZOMBIE") self.assertTrue(psutil.pid_exists(zpid)) zproc = psutil.Process(zpid) descendants = [x.pid for x in psutil.Process(os.getpid()).get_children(recursive=True)] self.assertIn(zpid, descendants) finally: if sock is not None: sock.close() reap_children(search_all=True) def test__str__(self): sproc = get_test_subprocess() p = psutil.Process(sproc.pid) self.assertIn(str(sproc.pid), str(p)) # python shows up as 'Python' in cmdline on OS X so test fails on OS X if not OSX: self.assertIn(os.path.basename(PYTHON), str(p)) sproc = get_test_subprocess() p = psutil.Process(sproc.pid) p.kill() p.wait() self.assertIn(str(sproc.pid), str(p)) self.assertIn("terminated", str(p)) @unittest.skipIf(LINUX, 'PID 0 not available on Linux') def test_pid_0(self): # Process(0) is supposed to work on all platforms except Linux p = psutil.Process(0) self.assertTrue(p.name) if os.name == 'posix': try: self.assertEqual(p.uids.real, 0) self.assertEqual(p.gids.real, 0) except psutil.AccessDenied: pass self.assertIn(p.ppid, (0, 1)) #self.assertEqual(p.exe, "") p.cmdline try: p.get_num_threads() except psutil.AccessDenied: pass try: p.get_memory_info() except psutil.AccessDenied: pass # username property try: if POSIX: self.assertEqual(p.username, 'root') elif WINDOWS: self.assertEqual(p.username, 'NT AUTHORITY\\SYSTEM') else: p.username except psutil.AccessDenied: pass self.assertIn(0, psutil.get_pid_list()) self.assertTrue(psutil.pid_exists(0)) def test__all__(self): for name in dir(psutil): if name in ('callable', 'defaultdict', 'error', 'namedtuple', 'test'): 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 'deprecated' not in fun.__doc__.lower(): self.fail('%r not in psutil.__all__' % name) 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(2);"] proc = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: proc.name proc.stdin self.assertTrue(hasattr(proc, 'name')) self.assertTrue(hasattr(proc, 'stdin')) self.assertRaises(AttributeError, getattr, proc, 'foo') finally: proc.kill() proc.wait() # =================================================================== # --- 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 = ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'as_dict', 'get_cpu_percent', 'nice', 'parent', 'get_children', 'pid'] attrs = [] for name in dir(psutil.Process): if name.startswith("_"): continue if name.startswith("set_"): continue if name in excluded_names: continue attrs.append(name) 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 == 'get_rlimit': args = (psutil.RLIMIT_NOFILE,) ret = attr(*args) else: ret = attr valid_procs += 1 except NotImplementedError: register_warning("%r was skipped because not " "implemented" % (self.__class__.__name__ + '.test_' + name)) except (psutil.NoSuchProcess, psutil.AccessDenied): err = sys.exc_info()[1] self.assertEqual(err.pid, p.pid) if err.name: # make sure exception's name attr is set # with the actual process name self.assertEqual(err.name, p.name) self.assertTrue(str(err)) self.assertTrue(err.msg) else: if ret not in (0, 0.0, [], None, ''): assert ret, ret meth = getattr(self, name) meth(ret) except Exception: err = sys.exc_info()[1] 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()) 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): pass def exe(self, ret): 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: assert os.path.isfile(ret), 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): self.assertTrue(ret >= 0) def name(self, ret): self.assertTrue(isinstance(ret, str)) self.assertTrue(ret) def create_time(self, ret): self.assertTrue(ret > 0) # 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): for uid in ret: self.assertTrue(uid >= 0) self.assertIn(uid, self._uids) def gids(self, ret): # note: testing all gids as above seems not to be reliable for # gid == 30 (nodoby); not sure why. for gid in ret: self.assertTrue(gid >= 0) #self.assertIn(uid, self.gids) def username(self, ret): self.assertTrue(ret) if os.name == 'posix': self.assertIn(ret, self._usernames) def status(self, ret): self.assertTrue(ret != "") self.assertTrue(ret != '?') self.assertIn(ret, VALID_PROC_STATUSES) def get_io_counters(self, ret): for field in ret: if field != -1: self.assertTrue(field >= 0) def get_ionice(self, ret): if LINUX: self.assertTrue(ret.ioclass >= 0) self.assertTrue(ret.value >= 0) else: self.assertTrue(ret >= 0) self.assertIn(ret, (0, 1, 2)) def get_num_threads(self, ret): self.assertTrue(ret >= 1) def get_threads(self, ret): for t in ret: self.assertTrue(t.id >= 0) self.assertTrue(t.user_time >= 0) self.assertTrue(t.system_time >= 0) def get_cpu_times(self, ret): self.assertTrue(ret.user >= 0) self.assertTrue(ret.system >= 0) def get_memory_info(self, ret): self.assertTrue(ret.rss >= 0) self.assertTrue(ret.vms >= 0) def get_ext_memory_info(self, ret): for name in ret._fields: self.assertTrue(getattr(ret, name) >= 0) if POSIX and ret.vms != 0: # VMS is always supposed to be the highest for name in ret._fields: if name != 'vms': value = getattr(ret, name) assert ret.vms > value, ret elif WINDOWS: assert ret.peak_wset >= ret.wset, ret assert ret.peak_paged_pool >= ret.paged_pool, ret assert ret.peak_nonpaged_pool >= ret.nonpaged_pool, ret assert ret.peak_pagefile >= ret.pagefile, ret def get_open_files(self, ret): for f in ret: if WINDOWS: assert f.fd == -1, f else: self.assertIsInstance(f.fd, int) assert os.path.isabs(f.path), f assert os.path.isfile(f.path), f def get_num_fds(self, ret): self.assertTrue(ret >= 0) def get_connections(self, ret): for conn in ret: check_connection(conn) def getcwd(self, ret): if ret is not None: # BSD may return None assert os.path.isabs(ret), ret try: st = os.stat(ret) except OSError: err = sys.exc_info()[1] # directory has been removed in mean time if err.errno != errno.ENOENT: raise else: self.assertTrue(stat.S_ISDIR(st.st_mode)) def get_memory_percent(self, ret): assert 0 <= ret <= 100, ret def is_running(self, ret): self.assertTrue(ret) def get_cpu_affinity(self, ret): assert ret != [], ret def terminal(self, ret): if ret is not None: assert os.path.isabs(ret), ret assert os.path.exists(ret), ret def get_memory_maps(self, ret): for nt in ret: for fname in nt._fields: value = getattr(nt, fname) if fname == 'path': if not value.startswith('['): assert os.path.isabs(nt.path), nt.path # commented as on Linux we might get '/foo/bar (deleted)' #assert os.path.exists(nt.path), nt.path elif fname in ('addr', 'perms'): self.assertTrue(value) else: self.assertIsInstance(value, (int, long)) assert value >= 0, value def get_num_handles(self, ret): if WINDOWS: self.assertGreaterEqual(ret, 0) else: self.assertGreaterEqual(ret, 0) def get_nice(self, ret): if POSIX: assert -20 <= ret <= 20, ret else: priorities = [getattr(psutil, x) for x in dir(psutil) if x.endswith('_PRIORITY_CLASS')] self.assertIn(ret, priorities) def get_num_ctx_switches(self, ret): self.assertTrue(ret.voluntary >= 0) self.assertTrue(ret.involuntary >= 0) def get_rlimit(self, ret): self.assertEqual(len(ret), 2) self.assertGreaterEqual(ret[0], -1) self.assertGreaterEqual(ret[1], -1) # =================================================================== # --- Limited user tests # =================================================================== if hasattr(os, 'getuid') and os.getuid() == 0: 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 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) os.setegid(1000) os.seteuid(1000) TestProcess.setUp(self) def tearDown(self): os.setegid(self.PROCESS_UID) os.seteuid(self.PROCESS_GID) TestProcess.tearDown(self) def test_nice(self): try: psutil.Process(os.getpid()).set_nice(-1) except psutil.AccessDenied: pass else: self.fail("exception not raised") def test_zombie_process(self): # causes problems if test test suite is run as root pass # =================================================================== # --- 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: err = sys.exc_info()[1] 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) f = open(exe, 'r') try: src = f.read() finally: f.close() 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)) 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') def test_who(self): self.assert_stdout('who.py') def test_netstat(self): self.assert_stdout('netstat.py') 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 cleanup(): reap_children(search_all=True) DEVNULL.close() safe_remove(TESTFN) safe_rmdir(TESTFN_UNICODE) for path in _testfiles: safe_remove(path) atexit.register(cleanup) safe_remove(TESTFN) safe_rmdir(TESTFN_UNICODE) def test_main(): tests = [] test_suite = unittest.TestSuite() tests.append(TestSystemAPIs) tests.append(TestProcess) tests.append(TestFetchAllProcesses) if POSIX: from _posix import PosixSpecificTestCase tests.append(PosixSpecificTestCase) # import the specific platform test suite if LINUX: from _linux import LinuxSpecificTestCase as stc elif WINDOWS: from _windows import WindowsSpecificTestCase as stc from _windows import TestDualProcessImplementation tests.append(TestDualProcessImplementation) elif OSX: from _osx import OSXSpecificTestCase as stc elif BSD: from _bsd import BSDSpecificTestCase as stc elif SUNOS: from _sunos import SunOSSpecificTestCase as stc tests.append(stc) if hasattr(os, 'getuid'): if 'LimitedUserTestCase' in globals(): tests.append(LimitedUserTestCase) else: register_warning("LimitedUserTestCase was skipped (super-user " "privileges are required)") tests.append(TestExampleScripts) 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 test_main(): sys.exit(1) psutil-1.2.1/test/_sunos.py0000664000175000017500000000311512244714321017636 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 datetime import psutil from test_psutil import * class SunOSSpecificTestCase(unittest.TestCase): def test_swap_memory(self): out = sh('swap -l -k') 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:] t = t.replace('K', '') f = f.replace('K', '') total += int(int(t) * 1024) free += int(int(f) * 1024) 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 test_BOOT_TIME(self): psutil_bt = datetime.datetime.fromtimestamp(psutil.BOOT_TIME).strftime( "%b %d %H:%M") sys_bt = sh('last reboot | head -1') sys_bt = ' '.join(sys_bt.split()[-3:]) self.assertEqual(sys_bt, psutil_bt) def test_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 test_main(): sys.exit(1) psutil-1.2.1/test/test_memory_leaks.py0000664000175000017500000002467112243463730022074 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 gc import os import socket import sys import threading import time import types import unittest import psutil import psutil._common from psutil._compat import PY3, callable, xrange from test_psutil import * LOOPS = 1000 TOLERANCE = 4096 # disable cache for Process class properties psutil._common.cached_property.enabled = False class Base(unittest.TestCase): proc = psutil.Process(os.getpid()) def execute(self, function, *args, **kwargs): def call_many_times(): for x in xrange(LOOPS - 1): self.call(function, *args, **kwargs) del x gc.collect() return self.get_mem() self.call(function, *args, **kwargs) self.assertEqual(gc.garbage, []) self.assertEqual(threading.active_count(), 1) # RSS comparison # step 1 rss1 = call_many_times() # step 2 rss2 = call_many_times() difference = rss2 - rss1 if difference > TOLERANCE: # This doesn't necessarily mean we have a leak yet. # At this point we assume that after having called the # function so many times the memory usage is stabilized # and if there are no leaks it should not increase any # more. # Let's keep calling fun for 3 more seconds and fail if # we notice any difference. stop_at = time.time() + 3 while 1: self.call(function, *args, **kwargs) if time.time() >= stop_at: break del stop_at gc.collect() rss3 = self.get_mem() difference = rss3 - rss2 if rss3 > rss2: self.fail("rss2=%s, rss3=%s, difference=%s" % (rss2, rss3, difference)) def get_mem(self): return psutil.Process(os.getpid()).get_memory_info()[0] def call(self, *args, **kwargs): raise NotImplementedError("must be implemented in subclass") class TestProcessObjectLeaks(Base): """Test leaks of Process class methods and properties""" def __init__(self, *args, **kwargs): Base.__init__(self, *args, **kwargs) # skip tests which are not supported by Process API supported_attrs = dir(psutil.Process) for attr in [x for x in dir(self) if x.startswith('test')]: if attr[5:] not in supported_attrs: meth = getattr(self, attr) name = meth.__func__.__name__.replace('test_', '') @unittest.skipIf(True, "%s not supported on this platform" % name) def test_(self): pass setattr(self, attr, types.MethodType(test_, self)) def setUp(self): gc.collect() def tearDown(self): reap_children() def call(self, function, *args, **kwargs): try: obj = getattr(self.proc, function) if callable(obj): obj(*args, **kwargs) except psutil.Error: pass def test_name(self): self.execute('name') def test_cmdline(self): self.execute('cmdline') def test_exe(self): self.execute('exe') def test_ppid(self): self.execute('ppid') def test_uids(self): self.execute('uids') def test_gids(self): self.execute('gids') def test_status(self): self.execute('status') def test_get_nice(self): self.execute('get_nice') def test_set_nice(self): niceness = psutil.Process(os.getpid()).get_nice() self.execute('set_nice', niceness) def test_get_io_counters(self): self.execute('get_io_counters') def test_get_ionice(self): self.execute('get_ionice') def test_set_ionice(self): if WINDOWS: value = psutil.Process(os.getpid()).get_ionice() self.execute('set_ionice', value) else: self.execute('set_ionice', psutil.IOPRIO_CLASS_NONE) def test_username(self): self.execute('username') def test_create_time(self): self.execute('create_time') def test_get_num_threads(self): self.execute('get_num_threads') def test_get_num_handles(self): self.execute('get_num_handles') def test_get_num_fds(self): self.execute('get_num_fds') def test_get_threads(self): self.execute('get_threads') def test_get_cpu_times(self): self.execute('get_cpu_times') def test_get_memory_info(self): self.execute('get_memory_info') def test_get_ext_memory_info(self): self.execute('get_ext_memory_info') def test_terminal(self): self.execute('terminal') @unittest.skipIf(POSIX, "not worth being tested on POSIX (pure python)") def test_resume(self): self.execute('resume') def test_getcwd(self): self.execute('getcwd') def test_get_cpu_affinity(self): self.execute('get_cpu_affinity') def test_set_cpu_affinity(self): affinity = psutil.Process(os.getpid()).get_cpu_affinity() self.execute('set_cpu_affinity', affinity) def test_get_open_files(self): safe_remove(TESTFN) # needed after UNIX socket test has run f = open(TESTFN, 'w') try: self.execute('get_open_files') finally: f.close() # OSX implementation is unbelievably slow @unittest.skipIf(OSX, "OSX implementation is too slow") def test_get_memory_maps(self): self.execute('get_memory_maps') @unittest.skipUnless(LINUX, "feature not supported on this platform") def test_get_rlimit(self): self.execute('get_rlimit', psutil.RLIMIT_NOFILE) @unittest.skipUnless(LINUX, "feature not supported on this platform") def test_get_rlimit(self): limit = psutil.Process(os.getpid()).get_rlimit(psutil.RLIMIT_NOFILE) self.execute('set_rlimit', psutil.RLIMIT_NOFILE, limit) # Linux implementation is pure python so since it's slow we skip it @unittest.skipIf(LINUX, "not worth being tested on Linux (pure python)") def test_get_connections(self): def create_socket(family, type): sock = socket.socket(family, type) sock.bind(('', 0)) if type == socket.SOCK_STREAM: sock.listen(1) return sock socks = [] socks.append(create_socket(socket.AF_INET, socket.SOCK_STREAM)) socks.append(create_socket(socket.AF_INET, socket.SOCK_DGRAM)) if supports_ipv6(): socks.append(create_socket(socket.AF_INET6, socket.SOCK_STREAM)) socks.append(create_socket(socket.AF_INET6, socket.SOCK_DGRAM)) if hasattr(socket, 'AF_UNIX'): safe_remove(TESTFN) s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.bind(TESTFN) s.listen(1) socks.append(s) 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('get_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 if not POSIX: def test_kill(self): self.execute('kill') def test_terminate(self): self.execute('terminate') def test_suspend(self): self.execute('suspend') def test_resume(self): self.execute('resume') def test_wait(self): self.execute('wait') class TestModuleFunctionsLeaks(Base): """Test leaks of psutil module functions.""" def setUp(self): gc.collect() def call(self, function, *args, **kwargs): obj = getattr(psutil, function) if callable(obj): obj(*args, **kwargs) @unittest.skipUnless( hasattr(psutil._psplatform, "get_num_cpus"), "platform module does not expose a get_num_cpus() function") @unittest.skipIf(LINUX, "not worth being tested on POSIX (pure python)") def test_NUM_CPUS(self): psutil.get_num_cpus = psutil._psplatform.get_num_cpus self.execute('get_num_cpus') @unittest.skipIf(POSIX, "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') def test_cpu_times(self): self.execute('cpu_times') def test_per_cpu_times(self): self.execute('cpu_times', percpu=True) @unittest.skipIf(POSIX, "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') def test_net_io_counters(self): self.execute('net_io_counters') 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_get_users(self): self.execute('get_users') def test_main(): test_suite = unittest.TestSuite() tests = [TestProcessObjectLeaksZombie, TestProcessObjectLeaks, TestModuleFunctionsLeaks] for test in tests: test_suite.addTest(unittest.makeSuite(test)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not test_main(): sys.exit(1) psutil-1.2.1/test/_osx.py0000664000175000017500000001146312243745044017312 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 unittest import psutil from psutil._compat import PY3 from test_psutil import * 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 class OSXSpecificTestCase(unittest.TestCase): def setUp(self): self.pid = get_test_subprocess().pid def tearDown(self): 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) # --- virtual mem def test_vmem_total(self): sysctl_hwphymem = sysctl('sysctl hw.memsize') self.assertEqual(sysctl_hwphymem, psutil.TOTAL_PHYMEM) @retry_before_failing() def test_vmem_free(self): num = vm_stat("free") self.assertAlmostEqual(psutil.virtual_memory().free, num, delta=TOLERANCE) @retry_before_failing() def test_vmem_active(self): num = vm_stat("active") self.assertAlmostEqual(psutil.virtual_memory().active, num, delta=TOLERANCE) @retry_before_failing() def test_vmem_inactive(self): num = vm_stat("inactive") self.assertAlmostEqual(psutil.virtual_memory().inactive, num, delta=TOLERANCE) @retry_before_failing() def test_vmem_wired(self): num = vm_stat("wired") self.assertAlmostEqual(psutil.virtual_memory().wired, num, delta=TOLERANCE) # --- swap mem def test_swapmem_sin(self): num = vm_stat("Pageins") self.assertEqual(psutil.swap_memory().sin, num) def test_swapmem_sout(self): num = vm_stat("Pageouts") self.assertEqual(psutil.swap_memory().sout, num) def test_swapmem_total(self): tot1 = psutil.swap_memory().total tot2 = 0 # OSX uses multiple cache files: # http://en.wikipedia.org/wiki/Paging#OS_X for name in os.listdir("/var/vm/"): file = os.path.join("/var/vm", name) if os.path.isfile(file): tot2 += os.path.getsize(file) self.assertEqual(tot1, tot2) def test_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 test_main(): sys.exit(1) psutil-1.2.1/test/_posix.py0000775000175000017500000002150312243745176017650 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 unittest import psutil from psutil._compat import PY3 from test_psutil import * 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 class PosixSpecificTestCase(unittest.TestCase): """Compare psutil results against 'ps' command line utility.""" # for ps -o arguments see: http://unixhelp.ed.ac.uk/CGI/man-cgi?ps def setUp(self): self.pid = get_test_subprocess([PYTHON, "-E", "-O"], stdin=subprocess.PIPE).pid def tearDown(self): reap_children() def test_process_parent_pid(self): ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid) ppid_psutil = psutil.Process(self.pid).ppid self.assertEqual(ppid_ps, ppid_psutil) def test_process_uid(self): uid_ps = ps("ps --no-headers -o uid -p %s" % self.pid) uid_psutil = psutil.Process(self.pid).uids.real self.assertEqual(uid_ps, uid_psutil) def test_process_gid(self): gid_ps = ps("ps --no-headers -o rgid -p %s" % self.pid) gid_psutil = psutil.Process(self.pid).gids.real self.assertEqual(gid_ps, gid_psutil) def test_process_username(self): username_ps = ps("ps --no-headers -o user -p %s" % self.pid) username_psutil = psutil.Process(self.pid).username self.assertEqual(username_ps, username_psutil) @skip_on_access_denied() def test_process_rss_memory(self): # give python interpreter some time to properly initialize # so that the results are the same time.sleep(0.1) rss_ps = ps("ps --no-headers -o rss -p %s" % self.pid) rss_psutil = psutil.Process(self.pid).get_memory_info()[0] / 1024 self.assertEqual(rss_ps, rss_psutil) @skip_on_access_denied() def test_process_vsz_memory(self): # give python interpreter some time to properly initialize # so that the results are the same time.sleep(0.1) vsz_ps = ps("ps --no-headers -o vsz -p %s" % self.pid) vsz_psutil = psutil.Process(self.pid).get_memory_info()[1] / 1024 self.assertEqual(vsz_ps, vsz_psutil) def test_process_name(self): # use command + arg since "comm" keyword not supported on all platforms name_ps = ps("ps --no-headers -o command -p %s" % self.pid).split(' ')[0] # remove path if there is any, from the command name_ps = os.path.basename(name_ps).lower() name_psutil = psutil.Process(self.pid).name.lower() self.assertEqual(name_ps, name_psutil) @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 if SUNOS: time_psutil = round(time_psutil) time_psutil_tstamp = datetime.datetime.fromtimestamp( time_psutil).strftime("%H:%M:%S") self.assertEqual(time_ps, 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) @retry_before_failing() def test_get_pids(self): # Note: this test might fail if the OS is starting/killing # other processes in the meantime if SUNOS: cmd = ["ps", "ax"] else: cmd = ["ps", "ax", "-o", "pid"] p = get_test_subprocess(cmd, stdout=subprocess.PIPE) output = p.communicate()[0].strip() 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.get_pid_list() pids_ps.sort() pids_psutil.sort() # on OSX ps doesn't show pid 0 if OSX and 0 not in pids_ps: pids_ps.insert(0, 0) if pids_ps != pids_psutil: difference = [x for x in pids_psutil if x not in pids_ps] + \ [x for x in pids_ps if x not in pids_psutil] self.fail("difference: " + str(difference)) # for some reason ifconfig -a does not report differente interfaces # psutil does @unittest.skipIf(SUNOS, "test not reliable on SUNOS") 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" % nic) def test_get_users(self): out = sh("who") lines = out.split('\n') users = [x.split()[0] for x in lines] self.assertEqual(len(users), len(psutil.get_users())) terminals = [x.split()[1] for x in lines] for u in psutil.get_users(): self.assertTrue(u.name in users, u.name) self.assertTrue(u.terminal in terminals, u.terminal) 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 == 'get_rlimit': args = (psutil.RLIMIT_NOFILE,) elif name == 'set_rlimit': args = (psutil.RLIMIT_NOFILE, (5, 5)) ret = attr(*args) else: ret = attr p = psutil.Process(os.getpid()) failures = [] for name in dir(psutil.Process): if name.startswith('_') \ or name.startswith('set_') \ or name in ('terminate', 'kill', 'suspend', 'resume', 'nice', 'send_signal', 'wait', 'get_children', 'as_dict'): continue else: try: num1 = p.get_num_fds() for x in range(2): call(p, name) num2 = p.get_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)) def test_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 test_main(): sys.exit(1) psutil-1.2.1/test/_bsd.py0000664000175000017500000001672012243745416017255 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: add test for comparing connections with 'sockstat' cmd """BSD specific tests. These are implicitly run by test_psutil.py.""" import unittest import subprocess import time import sys import os import psutil from psutil._compat import PY3 from test_psutil import * 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) result = result[result.find(": ") + 2:] try: return int(result) except ValueError: return result def muse(field): """Thin wrapper around 'muse' cmdline utility.""" out = sh('muse') for line in out.split('\n'): if line.startswith(field): break else: raise ValueError("line not found") return int(line.split()[1]) class BSDSpecificTestCase(unittest.TestCase): def setUp(self): self.pid = get_test_subprocess().pid def tearDown(self): reap_children() def test_BOOT_TIME(self): s = sysctl('sysctl kern.boottime') s = s[s.find(" sec = ") + 7:] s = s[:s.find(',')] btime = int(s) self.assertEqual(btime, psutil.BOOT_TIME) def test_process_create_time(self): cmdline = "ps -o lstart -p %s" % self.pid p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE) output = p.communicate()[0] if PY3: output = str(output, sys.stdout.encoding) start_ps = output.replace('STARTED', '').strip() start_psutil = psutil.Process(self.pid).create_time start_psutil = time.strftime("%a %b %e %H:%M:%S %Y", time.localtime(start_psutil)) self.assertEqual(start_ps, start_psutil) def test_disks(self): # test psutil.disk_usage() and psutil.disk_partitions() # against "df -a" def df(path): out = sh('df -k "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total = int(total) * 1024 used = int(used) * 1024 free = int(free) * 1024 return dev, total, used, free for part in psutil.disk_partitions(all=False): usage = psutil.disk_usage(part.mountpoint) dev, total, used, free = df(part.mountpoint) self.assertEqual(part.device, dev) self.assertEqual(usage.total, total) # 10 MB tollerance if abs(usage.free - free) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.free, free)) if abs(usage.used - used) > 10 * 1024 * 1024: self.fail("psutil=%s, df=%s" % (usage.used, used)) def test_memory_maps(self): out = sh('procstat -v %s' % self.pid) maps = psutil.Process(self.pid).get_memory_maps(grouped=False) lines = out.split('\n')[1:] while lines: line = lines.pop() fields = line.split() _, start, stop, perms, res = fields[:5] map = maps.pop() self.assertEqual("%s-%s" % (start, stop), map.addr) self.assertEqual(int(res), map.rss) if not map.path.startswith('['): self.assertEqual(fields[10], map.path) # --- virtual_memory(); tests against sysctl def test_vmem_total(self): syst = sysctl("sysctl vm.stats.vm.v_page_count") * PAGESIZE self.assertEqual(psutil.virtual_memory().total, syst) @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=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=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=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=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=TOLERANCE) @retry_before_failing() def test_vmem_buffers(self): syst = sysctl("vfs.bufspace") self.assertAlmostEqual(psutil.virtual_memory().buffers, syst, delta=TOLERANCE) # --- virtual_memory(); tests against muse @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") def test_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_active(self): num = muse('Active') self.assertAlmostEqual(psutil.virtual_memory().active, num, delta=TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_inactive(self): num = muse('Inactive') self.assertAlmostEqual(psutil.virtual_memory().inactive, num, delta=TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_wired(self): num = muse('Wired') self.assertAlmostEqual(psutil.virtual_memory().wired, num, delta=TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_cached(self): num = muse('Cache') self.assertAlmostEqual(psutil.virtual_memory().cached, num, delta=TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_free(self): num = muse('Free') self.assertAlmostEqual(psutil.virtual_memory().free, num, delta=TOLERANCE) @unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available") @retry_before_failing() def test_buffers(self): num = muse('Buffer') self.assertAlmostEqual(psutil.virtual_memory().buffers, num, delta=TOLERANCE) def test_main(): test_suite = unittest.TestSuite() test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase)) result = unittest.TextTestRunner(verbosity=2).run(test_suite) return result.wasSuccessful() if __name__ == '__main__': if not test_main(): sys.exit(1) psutil-1.2.1/test/__init__.py0000664000175000017500000000000012243206601020051 0ustar giampaologiampaolo00000000000000psutil-1.2.1/test/_linux.py0000664000175000017500000001565012243744766017654 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 os import re import sys import time import unittest from test_psutil import * import psutil 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.get_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:] used = int(lines[0].split()[2]) * 1024 self.assertAlmostEqual(used, psutil.virtual_memory().used, delta=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=TOLERANCE) @retry_before_failing() def test_vmem_buffers(self): lines = sh('free').split('\n')[1:] buffers = int(lines[0].split()[5]) * 1024 self.assertAlmostEqual(buffers, psutil.virtual_memory().buffers, delta=TOLERANCE) @retry_before_failing() def test_vmem_cached(self): lines = sh('free').split('\n')[1:] cached = int(lines[0].split()[6]) * 1024 self.assertAlmostEqual(cached, psutil.virtual_memory().cached, delta=TOLERANCE) def test_swapmem_total(self): lines = sh('free').split('\n')[1:] total = int(lines[2].split()[1]) * 1024 self.assertEqual(total, psutil.swap_memory().total) @retry_before_failing() def test_swapmem_used(self): lines = sh('free').split('\n')[1:] used = int(lines[2].split()[2]) * 1024 self.assertAlmostEqual(used, psutil.swap_memory().used, delta=TOLERANCE) @retry_before_failing() def test_swapmem_free(self): lines = sh('free').split('\n')[1:] free = int(lines[2].split()[3]) * 1024 self.assertAlmostEqual(free, psutil.swap_memory().free, delta=TOLERANCE) 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('.'))) # steal >= 2.6.11 # guest >= 2.6.24 # guest_nice >= 3.2.0 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) # --- tests for specific kernel versions @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.get_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_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 test_main(): sys.exit(1) psutil-1.2.1/psutil/0000775000175000017500000000000012244726663016333 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil/_psposix.py0000664000175000017500000001137712243460243020546 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. """Routines common to all posix systems.""" import errno import glob import os import sys import time from psutil._common import nt_diskinfo, usage_percent, memoize from psutil._compat import PY3, unicode from psutil._error import TimeoutExpired def pid_exists(pid): """Check whether pid exists in the current process table.""" if pid < 0: return False try: os.kill(pid, 0) except OSError: err = sys.exc_info()[1] 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 bever 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(pid) time.sleep(delay) return min(delay * 2, 0.04) timer = getattr(time, 'monotonic', time.time) if timeout is not None: waitcall = lambda: os.waitpid(pid, os.WNOHANG) stop_at = timer() + timeout else: waitcall = lambda: os.waitpid(pid, 0) delay = 0.0001 while 1: try: retpid, status = waitcall() except OSError: err = sys.exc_info()[1] if err.errno == errno.EINTR: delay = check_timeout(delay) continue elif err.errno == errno.ECHILD: # This has two meanings: # - pid is not a child of os.getpid() in which case # we keep polling until it's gone # - pid never existed in the first place # In both cases we'll eventually return None as we # can't determine its exit status code. while 1: if pid_exists(pid): delay = check_timeout(delay) else: return else: raise else: if retpid == 0: # WNOHANG was used, pid is still running delay = check_timeout(delay) continue # process exited due to a signal; return the integer of # that signal if os.WIFSIGNALED(status): return os.WTERMSIG(status) # process exited using exit(2) system call; return the # integer exit(2) system call has been called with elif os.WIFEXITED(status): return os.WEXITSTATUS(status) else: # should never happen raise RuntimeError("unknown process exit status") def get_disk_usage(path): """Return disk usage associated with path.""" 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://code.google.com/p/psutil/issues/detail?id=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 nt_diskinfo(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: err = sys.exc_info()[1] if err.errno != errno.ENOENT: raise return ret psutil-1.2.1/psutil/_pssunos.py0000664000175000017500000004327312244714321020553 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 Solaris platform implementation.""" import errno import os import socket import subprocess import _psutil_posix import _psutil_sunos from psutil import _psposix from psutil._common import * from psutil._compat import namedtuple, PY3 from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired __extra__all__ = ["CONN_IDLE", "CONN_BOUND"] PAGE_SIZE = os.sysconf('SC_PAGE_SIZE') NUM_CPUS = os.sysconf("SC_NPROCESSORS_ONLN") TOTAL_PHYMEM = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE try: BOOT_TIME = _psutil_sunos.get_boot_time() except Exception: BOOT_TIME = None warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) CONN_IDLE = "IDLE" CONN_BOUND = "BOUND" PROC_STATUSES = { _psutil_sunos.SSLEEP: STATUS_SLEEPING, _psutil_sunos.SRUN: STATUS_RUNNING, _psutil_sunos.SZOMB: STATUS_ZOMBIE, _psutil_sunos.SSTOP: STATUS_STOPPED, _psutil_sunos.SIDL: STATUS_IDLE, _psutil_sunos.SONPROC: STATUS_RUNNING, # same as run _psutil_sunos.SWAIT: STATUS_WAITING, } TCP_STATUSES = { _psutil_sunos.TCPS_ESTABLISHED: CONN_ESTABLISHED, _psutil_sunos.TCPS_SYN_SENT: CONN_SYN_SENT, _psutil_sunos.TCPS_SYN_RCVD: CONN_SYN_RECV, _psutil_sunos.TCPS_FIN_WAIT_1: CONN_FIN_WAIT1, _psutil_sunos.TCPS_FIN_WAIT_2: CONN_FIN_WAIT2, _psutil_sunos.TCPS_TIME_WAIT: CONN_TIME_WAIT, _psutil_sunos.TCPS_CLOSED: CONN_CLOSE, _psutil_sunos.TCPS_CLOSE_WAIT: CONN_CLOSE_WAIT, _psutil_sunos.TCPS_LAST_ACK: CONN_LAST_ACK, _psutil_sunos.TCPS_LISTEN: CONN_LISTEN, _psutil_sunos.TCPS_CLOSING: CONN_CLOSING, _psutil_sunos.PSUTIL_CONN_NONE: CONN_NONE, _psutil_sunos.TCPS_IDLE: CONN_IDLE, # sunos specific _psutil_sunos.TCPS_BOUND: CONN_BOUND, # sunos specific } disk_io_counters = _psutil_sunos.get_disk_io_counters net_io_counters = _psutil_sunos.get_net_io_counters get_disk_usage = _psposix.get_disk_usage get_system_boot_time = _psutil_sunos.get_boot_time nt_virtmem_info = namedtuple('vmem', ' '.join([ 'total', 'available', 'percent', 'used', 'free'])) # all platforms 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 nt_virtmem_info(total, avail, percent, used, free) def swap_memory(): sin, sout = _psutil_sunos.get_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(['swap', '-l', '-k'], stdout=subprocess.PIPE) stdout, stderr = p.communicate() if PY3: stdout = stdout.decode(sys.stdout.encoding) if p.returncode != 0: raise RuntimeError("'swap -l -k' 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:] t = t.replace('K', '') f = f.replace('K', '') total += int(int(t) * 1024) free += int(int(f) * 1024) used = total - free percent = usage_percent(used, total, _round=1) return nt_swapmeminfo(total, used, free, percent, sin * PAGE_SIZE, sout * PAGE_SIZE) def get_pid_list(): """Returns a list of PIDs currently running on the system.""" return [int(x) for x in os.listdir('/proc') if x.isdigit()] def pid_exists(pid): """Check for the existence of a unix pid.""" return _psposix.pid_exists(pid) _cputimes_ntuple = namedtuple('cputimes', 'user system idle iowait') def get_system_cpu_times(): """Return system-wide CPU times as a named tuple""" ret = _psutil_sunos.get_system_per_cpu_times() return _cputimes_ntuple(*[sum(x) for x in zip(*ret)]) def get_system_per_cpu_times(): """Return system per-CPU times as a list of named tuples""" ret = _psutil_sunos.get_system_per_cpu_times() return [_cputimes_ntuple(*x) for x in ret] def get_system_users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = _psutil_sunos.get_system_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 = nt_user(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 = _psutil_sunos.get_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 get_disk_usage(mountpoint).total: continue ntuple = nt_partition(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def wrap_exceptions(callable): """Call callable into a try/except clause and translate ENOENT, EACCES and EPERM in NoSuchProcess or AccessDenied exceptions. """ def wrapper(self, *args, **kwargs): try: return callable(self, *args, **kwargs) except EnvironmentError: # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_process_name"] def __init__(self, pid): self.pid = pid self._process_name = None @wrap_exceptions def get_process_name(self): # note: max len == 15 return _psutil_sunos.get_process_name_and_args(self.pid)[0] @wrap_exceptions def get_process_exe(self): # Will be guess 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.get_process_cmdline() return "" @wrap_exceptions def get_process_cmdline(self): return _psutil_sunos.get_process_name_and_args(self.pid)[1].split(' ') @wrap_exceptions def get_process_create_time(self): return _psutil_sunos.get_process_basic_info(self.pid)[3] @wrap_exceptions def get_process_num_threads(self): return _psutil_sunos.get_process_basic_info(self.pid)[5] @wrap_exceptions def get_process_nice(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 _psutil_posix.getpriority(self.pid) except EnvironmentError: err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): if pid_exists(self.pid): raise AccessDenied(self.pid, self._process_name) raise @wrap_exceptions def set_process_nice(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._process_name) return _psutil_posix.setpriority(self.pid, value) @wrap_exceptions def get_process_ppid(self): return _psutil_sunos.get_process_basic_info(self.pid)[0] @wrap_exceptions def get_process_uids(self): real, effective, saved, _, _, _ = \ _psutil_sunos.get_process_cred(self.pid) return nt_uids(real, effective, saved) @wrap_exceptions def get_process_gids(self): _, _, _, real, effective, saved = \ _psutil_sunos.get_process_cred(self.pid) return nt_uids(real, effective, saved) @wrap_exceptions def get_cpu_times(self): user, system = _psutil_sunos.get_process_cpu_times(self.pid) return nt_cputimes(user, system) @wrap_exceptions def get_process_terminal(self): hit_enoent = False tty = wrap_exceptions(_psutil_sunos.get_process_basic_info(self.pid)[0]) if tty != _psutil_sunos.PRNODEV: for x in (0, 1, 2, 255): try: return os.readlink('/proc/%d/path/%d' % (self.pid, x)) except OSError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue raise if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) @wrap_exceptions def get_process_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 try: return os.readlink("/proc/%s/path/cwd" % self.pid) except OSError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: os.stat("/proc/%s" % self.pid) return None raise @wrap_exceptions def get_memory_info(self): ret = _psutil_sunos.get_process_basic_info(self.pid) rss, vms = ret[1] * 1024, ret[2] * 1024 return nt_meminfo(rss, vms) # it seems Solaris uses rss and vms only get_ext_memory_info = get_memory_info @wrap_exceptions def get_process_status(self): code = _psutil_sunos.get_process_basic_info(self.pid)[6] # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(code, '?') @wrap_exceptions def get_process_threads(self): ret = [] tids = os.listdir('/proc/%d/lwp' % self.pid) hit_enoent = False for tid in tids: tid = int(tid) try: utime, stime = _psutil_sunos.query_process_thread(self.pid, tid) except EnvironmentError: # ENOENT == thread gone in meantime err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue raise else: nt = nt_thread(tid, utime, stime) ret.append(nt) if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) return ret @wrap_exceptions def get_open_files(self): retlist = [] hit_enoent = False pathdir = '/proc/%d/path' % self.pid for fd in os.listdir('/proc/%d/fd' % self.pid): path = os.path.join(pathdir, fd) if os.path.islink(path): try: file = os.readlink(path) except OSError: # ENOENT == file which is gone in the meantime err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue raise else: if isfile_strict(file): retlist.append(nt_openfile(file, int(fd))) if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % 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._process_name) if 'no such process' in stderr.lower(): raise NoSuchProcess(self.pid, self._process_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, "", CONN_NONE) @wrap_exceptions def get_connections(self, kind='inet'): if kind not in conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = _psutil_sunos.get_process_connections( self.pid, families, types) # 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 rawlist: os.stat('/proc/%s' % self.pid) # will raise NSP if process is gone ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item if fam not in families: continue if type not in types: continue status = TCP_STATUSES[status] nt = nt_connection(fd, fam, type, laddr, raddr, status) ret.append(nt) # UNIX sockets if socket.AF_UNIX in families: ret.extend([nt_connection(*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 get_memory_maps(self): def toaddr(start, end): return '%s-%s' % (hex(start)[2:].strip('L'), hex(end)[2:].strip('L')) retlist = [] rawlist = _psutil_sunos.get_process_memory_maps(self.pid) 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('/proc/%s/path/%s' % (self.pid, name)) except OSError: err = sys.exc_info()[1] 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 = '/proc/%s/path/%s' % (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('/proc/%s' % self.pid) return retlist @wrap_exceptions def get_num_fds(self): return len(os.listdir("/proc/%s/fd" % self.pid)) @wrap_exceptions def get_num_ctx_switches(self): return nt_ctxsw(*_psutil_sunos.get_process_num_ctx_switches(self.pid)) @wrap_exceptions def process_wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except TimeoutExpired: raise TimeoutExpired(self.pid, self._process_name) psutil-1.2.1/psutil/_psutil_mswindows.c0000664000175000017500000026264012244725637022302 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_mswindows */ // Fixes clash between winsock2.h and windows.h #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include #include #include #include // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") #include "_psutil_mswindows.h" #include "_psutil_common.h" #include "arch/mswindows/security.h" #include "arch/mswindows/process_info.h" #include "arch/mswindows/process_handles.h" #include "arch/mswindows/ntextapi.h" /* * Return a Python float representing the system uptime expressed in seconds * since the epoch. */ static PyObject* get_system_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* 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* get_pid_list(PyObject* self, PyObject* args) { DWORD *proclist = NULL; DWORD numberOfReturnedPIDs; DWORD i; PyObject* pid = NULL; PyObject* retlist = PyList_New(0); if (retlist == NULL) { return NULL; } proclist = psutil_get_pids(&numberOfReturnedPIDs); if (NULL == proclist) { goto error; } for (i = 0; i < numberOfReturnedPIDs; i++) { pid = Py_BuildValue("I", proclist[i]); if (!pid) goto error; if (PyList_Append(retlist, pid)) goto error; Py_DECREF(pid); } // free C array allocated for PIDs free(proclist); return retlist; error: Py_XDECREF(pid); Py_DECREF(retlist); if (proclist != NULL) free(proclist); return NULL; } /* * Kill a process given its PID. */ static PyObject* kill_process(PyObject* self, PyObject* args) { HANDLE hProcess; long pid; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (pid == 0) { return AccessDenied(); } hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { // see http://code.google.com/p/psutil/issues/detail?id=24 NoSuchProcess(); } else { PyErr_SetFromWindowsErr(0); } return NULL; } // kill the process if (! TerminateProcess(hProcess, 0)) { PyErr_SetFromWindowsErr(0); CloseHandle(hProcess); return NULL; } CloseHandle(hProcess); Py_INCREF(Py_None); return Py_None; } /* * Wait for process to terminate and return its exit code. */ static PyObject* process_wait(PyObject* self, PyObject* args) { HANDLE hProcess; DWORD ExitCode; DWORD retVal; long pid; long timeout; if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) { return NULL; } if (pid == 0) { return AccessDenied(); } hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { // no such process; we do not want to raise NSP but // return None instead. Py_INCREF(Py_None); return Py_None; } else { PyErr_SetFromWindowsErr(0); return NULL; } } // wait until the process has terminated Py_BEGIN_ALLOW_THREADS retVal = WaitForSingleObject(hProcess, timeout); Py_END_ALLOW_THREADS if (retVal == WAIT_FAILED) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(GetLastError()); } if (retVal == WAIT_TIMEOUT) { CloseHandle(hProcess); return Py_BuildValue("l", WAIT_TIMEOUT); } // get the exit code; note: subprocess module (erroneously?) uses // what returned by WaitForSingleObject if (GetExitCodeProcess(hProcess, &ExitCode) == 0) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(GetLastError()); } CloseHandle(hProcess); #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong((long) ExitCode); #else return PyInt_FromLong((long) ExitCode); #endif } /* * Return a Python tuple (user_time, kernel_time) */ static PyObject* get_process_cpu_times(PyObject* self, PyObject* args) { long pid; HANDLE hProcess; FILETIME ftCreate, ftExit, ftKernel, ftUser; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = 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) ); } /* * Alternative implementation of the one above but bypasses ACCESS DENIED. */ static PyObject* get_process_cpu_times_2(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; double user, kernel; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } user = (double)process->UserTime.HighPart * 429.4967296 + \ (double)process->UserTime.LowPart * 1e-7; kernel = (double)process->KernelTime.HighPart * 429.4967296 + \ (double)process->KernelTime.LowPart * 1e-7; free(buffer); return Py_BuildValue("(dd)", user, kernel); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject* get_process_create_time(PyObject* self, PyObject* args) { long pid; long long unix_time; DWORD exitCode; HANDLE hProcess; BOOL ret; FILETIME ftCreate, ftExit, ftKernel, ftUser; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } // special case for PIDs 0 and 4, return BOOT_TIME if (0 == pid || 4 == pid) { return get_system_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); } /* * Alternative implementation of the one above but bypasses ACCESS DENIED. */ static PyObject* get_process_create_time_2(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; long long unix_time; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } // special case for PIDs 0 and 4, return BOOT_TIME if (0 == pid || 4 == pid) { return get_system_boot_time(NULL, NULL); } /* Convert the LARGE_INTEGER union to a Unix time. It's the best I could find by googling and borrowing code here and there. The time returned has a precision of 1 second. */ unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32; unix_time += process->CreateTime.LowPart - 116444736000000000LL; unix_time /= 10000000; free(buffer); return Py_BuildValue("d", (double)unix_time); } /* * Return a Python integer indicating the number of CPUs on the system. */ static PyObject* get_num_cpus(PyObject* self, PyObject* args) { SYSTEM_INFO system_info; system_info.dwNumberOfProcessors = 0; GetSystemInfo(&system_info); if (system_info.dwNumberOfProcessors == 0){ // GetSystemInfo failed for some reason; return 1 as default return Py_BuildValue("I", 1); } return Py_BuildValue("I", system_info.dwNumberOfProcessors); } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject* get_process_cmdline(PyObject* self, PyObject* args) { long pid; int pid_return; PyObject* arglist; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if ((pid == 0) || (pid == 4)) { return Py_BuildValue("[]"); } pid_return = 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 arglist = psutil_get_arg_list(pid); if ( NULL == arglist ) { // carry on anyway, clear any exceptions too PyErr_Clear(); return Py_BuildValue("[]"); } return arglist; } /* * Return process executable path. */ static PyObject* get_process_exe(PyObject* self, PyObject* args) { long pid; HANDLE hProcess; wchar_t exe[MAX_PATH]; DWORD nSize = MAX_PATH; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION); if (NULL == hProcess) { return NULL; } if (GetProcessImageFileName(hProcess, &exe, nSize) == 0) { CloseHandle(hProcess); if (GetLastError() == ERROR_INVALID_PARAMETER) { // see https://code.google.com/p/psutil/issues/detail?id=414 AccessDenied(); } else { PyErr_SetFromWindowsErr(0); } return NULL; } CloseHandle(hProcess); return Py_BuildValue("s", exe); } /* * Return process memory information as a Python tuple. */ static PyObject* get_process_memory_info(PyObject* self, PyObject* args) { HANDLE hProcess; DWORD pid; #if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2 PROCESS_MEMORY_COUNTERS_EX cnt; #else PROCESS_MEMORY_COUNTERS cnt; #endif SIZE_T private = 0; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = psutil_handle_from_pid(pid); if (NULL == hProcess) { return NULL; } if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) { CloseHandle(hProcess); return PyErr_SetFromWindowsErr(0); } #if (_WIN32_WINNT >= 0x0501) // 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* get_process_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 (! get_process_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* get_virtual_mem(PyObject* self, PyObject* args) { MEMORYSTATUSEX memInfo; memInfo.dwLength = sizeof(MEMORYSTATUSEX); if (! GlobalMemoryStatusEx(&memInfo) ) { return PyErr_SetFromWindowsErr(0); } return Py_BuildValue("(LLLLLL)", memInfo.ullTotalPhys, // total memInfo.ullAvailPhys, // avail memInfo.ullTotalPageFile, // total page file memInfo.ullAvailPageFile, // avail page file memInfo.ullTotalVirtual, // total virtual memInfo.ullAvailVirtual // avail virtual ); } #define LO_T ((float)1e-7) #define HI_T (LO_T*4294967296.0) /* * 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* get_system_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* get_system_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 *arg = NULL; PyObject *retlist = PyList_New(0); if (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= 3 cwd = PyUnicode_FromObject(cwd_from_wchar); #else cwd = PyUnicode_AsUTF8String(cwd_from_wchar); #endif if (cwd == NULL) goto error; // decrement the reference count on our temp unicode str to avoid // mem leak returnPyObj = Py_BuildValue("N", cwd); if (!returnPyObj) goto error; Py_DECREF(cwd_from_wchar); CloseHandle(processHandle); free(currentDirectoryContent); return returnPyObj; error: Py_XDECREF(cwd_from_wchar); Py_XDECREF(cwd); Py_XDECREF(returnPyObj); if (currentDirectoryContent != NULL) free(currentDirectoryContent); if (processHandle != NULL) CloseHandle(processHandle); return NULL; } /* * Resume or suspends a process */ int suspend_resume_process(DWORD pid, int suspend) { // a huge thanks to http://www.codeproject.com/KB/threads/pausep.aspx HANDLE hThreadSnap = NULL; THREADENTRY32 te32 = {0}; if (pid == 0) { AccessDenied(); return FALSE; } hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap == INVALID_HANDLE_VALUE) { PyErr_SetFromWindowsErr(0); return FALSE; } // Fill in the size of the structure before using it te32.dwSize = sizeof(THREADENTRY32); if (! Thread32First(hThreadSnap, &te32)) { PyErr_SetFromWindowsErr(0); CloseHandle(hThreadSnap); return FALSE; } // Walk the thread snapshot to find all threads of the process. // If the thread belongs to the process, add its information // to the display list. do { if (te32.th32OwnerProcessID == pid) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID); if (hThread == NULL) { PyErr_SetFromWindowsErr(0); CloseHandle(hThread); CloseHandle(hThreadSnap); return FALSE; } if (suspend == 1) { if (SuspendThread(hThread) == (DWORD)-1) { PyErr_SetFromWindowsErr(0); CloseHandle(hThread); CloseHandle(hThreadSnap); return FALSE; } } else { if (ResumeThread(hThread) == (DWORD)-1) { PyErr_SetFromWindowsErr(0); CloseHandle(hThread); CloseHandle(hThreadSnap); return FALSE; } } CloseHandle(hThread); } } while (Thread32Next(hThreadSnap, &te32)); CloseHandle(hThreadSnap); return TRUE; } static PyObject* suspend_process(PyObject* self, PyObject* args) { long pid; int suspend = 1; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! suspend_resume_process(pid, suspend)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject* resume_process(PyObject* self, PyObject* args) { long pid; int suspend = 0; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! suspend_resume_process(pid, suspend)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject* get_process_num_threads(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; int num; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } num = (int)process->NumberOfThreads; free(buffer); return Py_BuildValue("i", num); } static PyObject* get_process_threads(PyObject* self, PyObject* args) { HANDLE hThread; THREADENTRY32 te32 = {0}; long pid; int pid_return; int rc; FILETIME ftDummy, ftKernel, ftUser; PyObject* retList = PyList_New(0); PyObject* pyTuple = NULL; HANDLE hThreadSnap = NULL; if (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) { pyTuple = NULL; hThread = NULL; hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID); if (hThread == NULL) { // thread has disappeared on us continue; } rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser); if (rc == 0) { PyErr_SetFromWindowsErr(0); goto error; } /* user and kernel times are represented as a FILETIME structure wich contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx To convert it into a float representing the seconds that the process has executed in user/kernel mode I borrowed the code below from Python's Modules/posixmodule.c */ pyTuple = Py_BuildValue("kdd", te32.th32ThreadID, (double)(ftUser.dwHighDateTime*429.4967296 + \ ftUser.dwLowDateTime*1e-7), (double)(ftKernel.dwHighDateTime*429.4967296 + \ ftKernel.dwLowDateTime*1e-7)); if (!pyTuple) goto error; if (PyList_Append(retList, pyTuple)) goto error; Py_DECREF(pyTuple); CloseHandle(hThread); } } while (Thread32Next(hThreadSnap, &te32)); CloseHandle(hThreadSnap); return retList; error: Py_XDECREF(pyTuple); Py_DECREF(retList); if (hThread != NULL) CloseHandle(hThread); if (hThreadSnap != NULL) { CloseHandle(hThreadSnap); } return NULL; } static PyObject* get_process_open_files(PyObject* self, PyObject* args) { long pid; HANDLE processHandle; DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; PyObject* filesList; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } processHandle = psutil_handle_from_pid_waccess(pid, access); if (processHandle == NULL) { return NULL; } filesList = psutil_get_open_files(pid, processHandle); CloseHandle(processHandle); if (filesList == NULL) { return PyErr_SetFromWindowsErr(0); } return filesList; } /* Accept a filename's drive in native format like "\Device\HarddiskVolume1\" and return the corresponding drive letter (e.g. "C:\\"). If no match is found return an empty string. */ static PyObject* win32_QueryDosDevice(PyObject* self, PyObject* args) { LPCTSTR lpDevicePath; TCHAR d = TEXT('A'); TCHAR szBuff[5]; if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) { return NULL; } while(d <= TEXT('Z')) { TCHAR szDeviceName[3] = {d,TEXT(':'),TEXT('\0')}; TCHAR szTarget[512] = {0}; if (QueryDosDevice(szDeviceName, szTarget, 511) != 0){ //_tprintf (TEXT("%c:\\ => %s\n"), d, szTarget); if(_tcscmp(lpDevicePath, szTarget) == 0) { _stprintf(szBuff, TEXT("%c:"), d); return Py_BuildValue("s", szBuff); } } d++; } return Py_BuildValue("s", ""); } /* * Return process username as a "DOMAIN//USERNAME" string. */ static PyObject* get_process_username(PyObject* self, PyObject* args) { long pid; HANDLE processHandle; HANDLE tokenHandle; PTOKEN_USER user; ULONG bufferSize; PTSTR name; ULONG nameSize; PTSTR domainName; ULONG domainNameSize; SID_NAME_USE nameUse; PTSTR fullName; PyObject* returnObject; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } processHandle = 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'; returnObject = Py_BuildValue("s", fullName); free(fullName); free(name); free(domainName); free(user); return returnObject; } #define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff) #ifndef AF_INET6 #define AF_INET6 23 #endif /* mingw support */ #ifndef _IPRTRMIB_H typedef struct _MIB_TCP6ROW_OWNER_PID { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; UCHAR ucRemoteAddr[16]; DWORD dwRemoteScopeId; DWORD dwRemotePort; DWORD dwState; DWORD dwOwningPid; } MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID; typedef struct _MIB_TCP6TABLE_OWNER_PID { DWORD dwNumEntries; MIB_TCP6ROW_OWNER_PID table[ANY_SIZE]; } MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID; #endif #ifndef __IPHLPAPI_H__ typedef struct in6_addr { union { UCHAR Byte[16]; USHORT Word[8]; } u; } IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR; typedef enum _UDP_TABLE_CLASS { UDP_TABLE_BASIC, UDP_TABLE_OWNER_PID, UDP_TABLE_OWNER_MODULE } UDP_TABLE_CLASS, *PUDP_TABLE_CLASS; typedef struct _MIB_UDPROW_OWNER_PID { DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID; typedef struct _MIB_UDPTABLE_OWNER_PID { DWORD dwNumEntries; MIB_UDPROW_OWNER_PID table[ANY_SIZE]; } MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID; #endif /* end of mingw support */ typedef struct _MIB_UDP6ROW_OWNER_PID { UCHAR ucLocalAddr[16]; DWORD dwLocalScopeId; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID; typedef struct _MIB_UDP6TABLE_OWNER_PID { DWORD dwNumEntries; MIB_UDP6ROW_OWNER_PID table[ANY_SIZE]; } MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; #define ConnDecrefPyObjs() Py_DECREF(_AF_INET); \ Py_DECREF(_AF_INET6);\ Py_DECREF(_SOCK_STREAM);\ Py_DECREF(_SOCK_DGRAM); // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; /* * Return a list of network connections opened by a process */ static PyObject* get_process_connections(PyObject* self, PyObject* args) { static long null_address[4] = { 0, 0, 0, 0 }; unsigned long pid; PyObject* connectionsList; PyObject* connectionTuple = NULL; PyObject *af_filter = NULL; PyObject *type_filter = NULL; PyObject *_AF_INET = PyLong_FromLong((long)AF_INET); PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6); PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM); PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM); typedef PSTR (NTAPI *_RtlIpv4AddressToStringA)(struct in_addr *, PSTR /* __out_ecount(16) */); _RtlIpv4AddressToStringA rtlIpv4AddressToStringA; typedef PSTR (NTAPI *_RtlIpv6AddressToStringA)(struct in6_addr *, PSTR /* __out_ecount(65) */); _RtlIpv6AddressToStringA rtlIpv6AddressToStringA; typedef DWORD (WINAPI *_GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, TCP_TABLE_CLASS, ULONG); _GetExtendedTcpTable getExtendedTcpTable; typedef DWORD (WINAPI *_GetExtendedUdpTable)(PVOID, PDWORD, BOOL, ULONG, UDP_TABLE_CLASS, ULONG); _GetExtendedUdpTable getExtendedUdpTable; PVOID table = NULL; DWORD tableSize; PMIB_TCPTABLE_OWNER_PID tcp4Table; PMIB_UDPTABLE_OWNER_PID udp4Table; PMIB_TCP6TABLE_OWNER_PID tcp6Table; PMIB_UDP6TABLE_OWNER_PID udp6Table; ULONG i; CHAR addressBufferLocal[65]; PyObject* addressTupleLocal = NULL; CHAR addressBufferRemote[65]; PyObject* addressTupleRemote = NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { ConnDecrefPyObjs(); return NULL; } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { ConnDecrefPyObjs(); PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); return NULL; } if (psutil_pid_is_running(pid) == 0) { ConnDecrefPyObjs(); return NoSuchProcess(); } /* Import some functions. */ { HMODULE ntdll; HMODULE iphlpapi; ntdll = LoadLibrary(TEXT("ntdll.dll")); rtlIpv4AddressToStringA = (_RtlIpv4AddressToStringA)GetProcAddress(ntdll, "RtlIpv4AddressToStringA"); rtlIpv6AddressToStringA = (_RtlIpv6AddressToStringA)GetProcAddress(ntdll, "RtlIpv6AddressToStringA"); /* TODO: Check these two function pointers */ iphlpapi = LoadLibrary(TEXT("iphlpapi.dll")); getExtendedTcpTable = (_GetExtendedTcpTable)GetProcAddress(iphlpapi, "GetExtendedTcpTable"); getExtendedUdpTable = (_GetExtendedUdpTable)GetProcAddress(iphlpapi, "GetExtendedUdpTable"); FreeLibrary(ntdll); FreeLibrary(iphlpapi); } if ((getExtendedTcpTable == NULL) || (getExtendedUdpTable == NULL)) { PyErr_SetString(PyExc_NotImplementedError, "feature not supported on this Windows version"); ConnDecrefPyObjs(); return NULL; } connectionsList = PyList_New(0); if (connectionsList == NULL) { ConnDecrefPyObjs(); return NULL; } /* TCP IPv4 */ if ((PySequence_Contains(af_filter, _AF_INET) == 1) && (PySequence_Contains(type_filter, _SOCK_STREAM) == 1)) { table = NULL; connectionTuple = NULL; addressTupleLocal = NULL; addressTupleRemote = NULL; tableSize = 0; getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); table = malloc(tableSize); if (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 (tcp4Table->table[i].dwOwningPid != pid) { continue; } if (tcp4Table->table[i].dwLocalAddr != 0 || tcp4Table->table[i].dwLocalPort != 0) { struct in_addr addr; addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr; rtlIpv4AddressToStringA(&addr, addressBufferLocal); addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort)); } else { addressTupleLocal = PyTuple_New(0); } if (addressTupleLocal == NULL) goto error; // On Windows <= XP, remote addr is filled even if socket // is in LISTEN mode in which case we just ignore it. if ((tcp4Table->table[i].dwRemoteAddr != 0 || tcp4Table->table[i].dwRemotePort != 0) && (tcp4Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) { struct in_addr addr; addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr; rtlIpv4AddressToStringA(&addr, addressBufferRemote); addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote, BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort)); } else { addressTupleRemote = PyTuple_New(0); } if (addressTupleRemote == NULL) goto error; connectionTuple = Py_BuildValue("(iiiNNi)", -1, AF_INET, SOCK_STREAM, addressTupleLocal, addressTupleRemote, tcp4Table->table[i].dwState ); if (!connectionTuple) goto error; if (PyList_Append(connectionsList, connectionTuple)) goto error; Py_DECREF(connectionTuple); } } free(table); } /* TCP IPv6 */ if ((PySequence_Contains(af_filter, _AF_INET6) == 1) && (PySequence_Contains(type_filter, _SOCK_STREAM) == 1)) { table = NULL; connectionTuple = NULL; addressTupleLocal = NULL; addressTupleRemote = NULL; tableSize = 0; getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0); table = malloc(tableSize); if (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 (tcp6Table->table[i].dwOwningPid != pid) { continue; } if (memcmp(tcp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || tcp6Table->table[i].dwLocalPort != 0) { struct in6_addr addr; memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferLocal); addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort)); } else { addressTupleLocal = PyTuple_New(0); } if (addressTupleLocal == NULL) goto error; // On Windows <= XP, remote addr is filled even if socket // is in LISTEN mode in which case we just ignore it. if ((memcmp(tcp6Table->table[i].ucRemoteAddr, null_address, 16) != 0 || tcp6Table->table[i].dwRemotePort != 0) && (tcp6Table->table[i].dwState != MIB_TCP_STATE_LISTEN)) { struct in6_addr addr; memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferRemote); addressTupleRemote = Py_BuildValue("(si)", addressBufferRemote, BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort)); } else { addressTupleRemote = PyTuple_New(0); } if (addressTupleRemote == NULL) goto error; connectionTuple = Py_BuildValue("(iiiNNi)", -1, AF_INET6, SOCK_STREAM, addressTupleLocal, addressTupleRemote, tcp6Table->table[i].dwState ); if (!connectionTuple) goto error; if (PyList_Append(connectionsList, connectionTuple)) goto error; Py_DECREF(connectionTuple); } } free(table); } /* UDP IPv4 */ if ((PySequence_Contains(af_filter, _AF_INET) == 1) && (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1)) { table = NULL; connectionTuple = NULL; addressTupleLocal = NULL; addressTupleRemote = NULL; tableSize = 0; getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0); table = malloc(tableSize); if (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 (udp4Table->table[i].dwOwningPid != pid) { continue; } if (udp4Table->table[i].dwLocalAddr != 0 || udp4Table->table[i].dwLocalPort != 0) { struct in_addr addr; addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr; rtlIpv4AddressToStringA(&addr, addressBufferLocal); addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort)); } else { addressTupleLocal = PyTuple_New(0); } if (addressTupleLocal == NULL) goto error; connectionTuple = Py_BuildValue("(iiiNNi)", -1, AF_INET, SOCK_DGRAM, addressTupleLocal, PyTuple_New(0), PSUTIL_CONN_NONE ); if (!connectionTuple) goto error; if (PyList_Append(connectionsList, connectionTuple)) goto error; Py_DECREF(connectionTuple); } } free(table); } /* UDP IPv6 */ if ((PySequence_Contains(af_filter, _AF_INET6) == 1) && (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1)) { table = NULL; connectionTuple = NULL; addressTupleLocal = NULL; addressTupleRemote = NULL; tableSize = 0; getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET6, UDP_TABLE_OWNER_PID, 0); table = malloc(tableSize); if (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 (udp6Table->table[i].dwOwningPid != pid) { continue; } if (memcmp(udp6Table->table[i].ucLocalAddr, null_address, 16) != 0 || udp6Table->table[i].dwLocalPort != 0) { struct in6_addr addr; memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16); rtlIpv6AddressToStringA(&addr, addressBufferLocal); addressTupleLocal = Py_BuildValue("(si)", addressBufferLocal, BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort)); } else { addressTupleLocal = PyTuple_New(0); } if (addressTupleLocal == NULL) goto error; connectionTuple = Py_BuildValue("(iiiNNi)", -1, AF_INET6, SOCK_DGRAM, addressTupleLocal, PyTuple_New(0), PSUTIL_CONN_NONE ); if (!connectionTuple) goto error; if (PyList_Append(connectionsList, connectionTuple)) goto error; Py_DECREF(connectionTuple); } } free(table); } ConnDecrefPyObjs(); return connectionsList; error: ConnDecrefPyObjs(); Py_XDECREF(connectionTuple); Py_XDECREF(addressTupleLocal); Py_XDECREF(addressTupleRemote); Py_DECREF(connectionsList); if (table != NULL) free(table); return NULL; } /* * Get process priority as a Python integer. */ static PyObject* get_process_priority(PyObject* self, PyObject* args) { long pid; DWORD priority; HANDLE hProcess; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = 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* set_process_priority(PyObject* self, PyObject* args) { long pid; int priority; int retval; HANDLE hProcess; DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION; if (! PyArg_ParseTuple(args, "li", &pid, &priority)) { return NULL; } hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess); if (hProcess == NULL) { return NULL; } retval = SetPriorityClass(hProcess, priority); CloseHandle(hProcess); if (retval == 0) { PyErr_SetFromWindowsErr(0); return NULL; } Py_INCREF(Py_None); return Py_None; } #if (_WIN32_WINNT >= 0x0600) // Windows Vista /* * Get process IO priority as a Python integer. */ static PyObject* get_process_io_priority(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* set_process_io_priority(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_INCREF(Py_None); return Py_None; } #endif /* * Return a Python tuple referencing process I/O counters. */ static PyObject* get_process_io_counters(PyObject* self, PyObject* args) { DWORD pid; HANDLE hProcess; IO_COUNTERS IoCounters; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = 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); } /* * Alternative implementation of the one above but bypasses ACCESS DENIED. */ static PyObject* get_process_io_counters_2(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; LONGLONG rcount, wcount, rbytes, wbytes; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } rcount = process->ReadOperationCount.QuadPart; wcount = process->WriteOperationCount.QuadPart; rbytes = process->ReadTransferCount.QuadPart; wbytes = process->WriteTransferCount.QuadPart; free(buffer); return Py_BuildValue("KKKK", rcount, wcount, rbytes, wbytes); } /* * Return process CPU affinity as a bitmask */ static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args) { DWORD pid; HANDLE hProcess; PDWORD_PTR proc_mask; PDWORD_PTR system_mask; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = 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* set_process_cpu_affinity(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_INCREF(Py_None); return Py_None; } /* * Return True if one of the process threads is in a waiting or * suspended status. */ static PyObject* is_process_suspended(PyObject* self, PyObject* args) { DWORD pid; ULONG i; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } for (i = 0; i < process->NumberOfThreads; i++) { if (process->Threads[i].ThreadState != Waiting || process->Threads[i].WaitReason != Suspended) { free(buffer); Py_RETURN_FALSE; } } free(buffer); Py_RETURN_TRUE; } /* * Return path's disk total and free as a Python tuple. */ static PyObject* get_disk_usage(PyObject* self, PyObject* args) { BOOL retval; ULARGE_INTEGER _, total, free; char *path; if (PyArg_ParseTuple(args, "u", &path)) { Py_BEGIN_ALLOW_THREADS retval = GetDiskFreeSpaceExW(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* get_net_io_counters(PyObject* self, PyObject* args) { int attempts = 0; int outBufLen = 15000; char ifname[2000]; DWORD dwRetVal = 0; MIB_IFROW *pIfRow = NULL; ULONG flags = 0; ULONG family = AF_UNSPEC; 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; } do { pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen); if (pAddresses == NULL) { PyErr_NoMemory(); goto error; } dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { free(pAddresses); pAddresses = NULL; } else { break; } attempts++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3)); if (dwRetVal != NO_ERROR) { PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed."); goto error; } pCurrAddresses = pAddresses; while (pCurrAddresses) { py_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("(IIIIIIII)", pIfRow->dwOutOctets, pIfRow->dwInOctets, pIfRow->dwOutUcastPkts, pIfRow->dwInUcastPkts, pIfRow->dwInErrors, pIfRow->dwOutErrors, pIfRow->dwInDiscards, pIfRow->dwOutDiscards); if (!py_nic_info) goto error; sprintf(ifname, "%wS", pCurrAddresses->FriendlyName); py_nic_name = Py_BuildValue("s", ifname); 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; } // fix for mingw32, see // https://code.google.com/p/psutil/issues/detail?id=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; /* * Return a Python dict of tuples for disk I/O information */ static PyObject* get_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_disk_info = 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_disk_info = NULL; sprintf(szDevice, "\\\\.\\PhysicalDrive%d", devNum); hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) { continue; } if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance, sizeof(diskPerformance), &dwSize, NULL)) { sprintf(szDeviceDisplay, "PhysicalDrive%d", devNum); py_disk_info = Py_BuildValue("(IILLLL)", diskPerformance.ReadCount, diskPerformance.WriteCount, diskPerformance.BytesRead, diskPerformance.BytesWritten, (diskPerformance.ReadTime.QuadPart * 10) / 1000, (diskPerformance.WriteTime.QuadPart * 10) / 1000); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_disk_info)) goto error; Py_XDECREF(py_disk_info); } else { // XXX we might get here with ERROR_INSUFFICIENT_BUFFER when // compiling with mingw32; not sure what to do. //return PyErr_SetFromWindowsErr(0); ;; } CloseHandle(hDevice); } return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (hDevice != NULL) CloseHandle(hDevice); return NULL; } static char *get_drive_type(int type) { switch (type) { case DRIVE_FIXED: return "fixed"; case DRIVE_CDROM: return "cdrom"; case DRIVE_REMOVABLE: return "removable"; case DRIVE_UNKNOWN: return "unknown"; case DRIVE_NO_ROOT_DIR: return "unmounted"; case DRIVE_REMOTE: return "remote"; case DRIVE_RAMDISK: return "ramdisk"; default: return "?"; } } #define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) /* * Return disk partitions as a list of tuples such as * (drive_letter, drive_letter, type, "") */ static PyObject* get_disk_partitions(PyObject* self, PyObject* args) { DWORD num_bytes; char drive_strings[255]; char* drive_letter = drive_strings; int all; int type; int ret; char opts[20]; LPTSTR fs_type[MAX_PATH + 1] = { 0 }; DWORD pflags = 0; PyObject* py_all; PyObject* py_retlist = PyList_New(0); PyObject* py_tuple = NULL; if (py_retlist == NULL) { return NULL; } // avoid to visualize a message box in case something goes wrong // see http://code.google.com/p/psutil/issues/detail?id=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(drive_letter, NULL, _ARRAYSIZE(drive_letter), NULL, NULL, &pflags, fs_type, _ARRAYSIZE(fs_type)); if (ret == 0) { // We might get here in case of a floppy hard drive, in // which case the error is (21, "device not ready"). // Let's pretend it didn't happen as we already have // the drive name and type ('removable'). strcat(opts, ""); SetLastError(0); } else { if (pflags & FILE_READ_ONLY_VOLUME) { strcat(opts, "ro"); } else { strcat(opts, "rw"); } if (pflags & FILE_VOLUME_IS_COMPRESSED) { strcat(opts, ",compressed"); } } if (strlen(opts) > 0) { strcat(opts, ","); } strcat(opts, get_drive_type(type)); py_tuple = Py_BuildValue("(ssss)", drive_letter, drive_letter, fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS opts); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); goto next; next: drive_letter = strchr(drive_letter, 0) + 1; } SetErrorMode(0); return py_retlist; error: SetErrorMode(0); Py_XDECREF(py_tuple); Py_DECREF(py_retlist); return NULL; } #ifdef UNICODE #define WTSOpenServer WTSOpenServerW #else #define WTSOpenServer WTSOpenServerA #endif /* * Return a Python dict of tuples for disk I/O information */ static PyObject* get_system_users(PyObject* self, PyObject* args) { 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; 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; iAddressFamily == 0) { // AF_INET sprintf(address_str, "%u.%u.%u.%u", address->Address[0], address->Address[1], address->Address[2], address->Address[3]); py_address = Py_BuildValue("s", address_str); if (!py_address) goto error; } else { py_address = Py_None; } // login time if (!WinStationQueryInformationW(hServer, sessionId, WinStationInformation, &station_info, sizeof(station_info), &returnLen)) { goto error; } unix_time = ((LONGLONG)station_info.ConnectTime.dwHighDateTime) << 32; unix_time += station_info.ConnectTime.dwLowDateTime - 116444736000000000LL; unix_time /= 10000000; py_tuple = Py_BuildValue("sOd", buffer_user, py_address, (double)unix_time); if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_XDECREF(py_address); Py_XDECREF(py_tuple); } WTSCloseServer(hServer); WTSFreeMemory(sessions); WTSFreeMemory(buffer_user); WTSFreeMemory(buffer_addr); FreeLibrary(hInstWinSta); return py_retlist; error: Py_XDECREF(py_tuple); Py_XDECREF(py_address); Py_DECREF(py_retlist); if (hInstWinSta != NULL) { FreeLibrary(hInstWinSta); } if (hServer != NULL) { WTSCloseServer(hServer); } if (sessions != NULL) { WTSFreeMemory(sessions); } if (buffer_user != NULL) { WTSFreeMemory(buffer_user); } if (buffer_addr != NULL) { WTSFreeMemory(buffer_addr); } return NULL; } /* * Return the number of handles opened by process. */ static PyObject* get_process_num_handles(PyObject* self, PyObject* args) { DWORD pid; HANDLE hProcess; DWORD handleCount; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } hProcess = 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); } /* * Alternative implementation of the one above but bypasses ACCESS DENIED. */ static PyObject* get_process_num_handles_2(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; ULONG count; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } count = process->HandleCount; free(buffer); return Py_BuildValue("k", count); } /* * Return the number of context switches executed by process. */ static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args) { DWORD pid; PSYSTEM_PROCESS_INFORMATION process; PVOID buffer; ULONG i; ULONG total = 0; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! get_process_info(pid, &process, &buffer)) { return NULL; } for (i=0; i < process->NumberOfThreads; i++) { total += process->Threads[i].ContextSwitches; } free(buffer); return Py_BuildValue("ki", total, 0); } static char *get_region_protection_string(ULONG protection) { switch (protection & 0xff) { case PAGE_NOACCESS: return ""; case PAGE_READONLY: return "r"; case PAGE_READWRITE: return "rw"; case PAGE_WRITECOPY: return "wc"; case PAGE_EXECUTE: return "x"; case PAGE_EXECUTE_READ: return "xr"; case PAGE_EXECUTE_READWRITE: return "xrw"; case PAGE_EXECUTE_WRITECOPY: return "xwc"; default: return "?"; } } /* * Return a list of process's memory mappings. */ static PyObject* get_process_memory_maps(PyObject* self, PyObject* args) { DWORD pid; HANDLE hProcess = NULL; MEMORY_BASIC_INFORMATION basicInfo; PVOID baseAddress; PVOID previousAllocationBase; CHAR mappedFileName[MAX_PATH]; SYSTEM_INFO system_info; LPVOID maxAddr; PyObject* py_list = PyList_New(0); PyObject* py_tuple = NULL; if (py_list == 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_list, py_tuple)) goto error; Py_DECREF(py_tuple); } previousAllocationBase = basicInfo.AllocationBase; baseAddress = (PCHAR)baseAddress + basicInfo.RegionSize; } CloseHandle(hProcess); return py_list; error: Py_XDECREF(py_tuple); Py_DECREF(py_list); if (hProcess != NULL) CloseHandle(hProcess); return NULL; } /* * Return a {pid:ppid, ...} dict for all running processes. */ static PyObject* get_ppid_map(PyObject* self, PyObject* args) { PyObject* pid = NULL; PyObject* 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 { pid = Py_BuildValue("I", pe.th32ProcessID); if (pid == NULL) goto error; ppid = Py_BuildValue("I", pe.th32ParentProcessID); if (ppid == NULL) goto error; if (PyDict_SetItem(py_retdict, pid, ppid)) goto error; } while (Process32Next(handle, &pe)); } CloseHandle(handle); return py_retdict; error: Py_XDECREF(pid); Py_XDECREF(ppid); Py_DECREF(py_retdict); CloseHandle(handle); return NULL; } // ------------------------ Python init --------------------------- static PyMethodDef PsutilMethods[] = { // --- per-process functions {"get_process_cmdline", get_process_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"get_process_exe", get_process_exe, METH_VARARGS, "Return path of the process executable"}, {"kill_process", kill_process, METH_VARARGS, "Kill the process identified by the given PID"}, {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"get_process_create_time", get_process_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"get_process_memory_info", get_process_memory_info, METH_VARARGS, "Return a tuple of process memory information"}, {"get_process_cwd", get_process_cwd, METH_VARARGS, "Return process current working directory"}, {"suspend_process", suspend_process, METH_VARARGS, "Suspend a process"}, {"resume_process", resume_process, METH_VARARGS, "Resume a process"}, {"get_process_open_files", get_process_open_files, METH_VARARGS, "Return files opened by process"}, {"get_process_username", get_process_username, METH_VARARGS, "Return the username of a process"}, {"get_process_connections", get_process_connections, METH_VARARGS, "Return the network connections of a process"}, {"get_process_num_threads", get_process_num_threads, METH_VARARGS, "Return the network connections of a process"}, {"get_process_threads", get_process_threads, METH_VARARGS, "Return process threads information as a list of tuple"}, {"process_wait", process_wait, METH_VARARGS, "Wait for process to terminate and return its exit code."}, {"get_process_priority", get_process_priority, METH_VARARGS, "Return process priority."}, {"set_process_priority", set_process_priority, METH_VARARGS, "Set process priority."}, #if (_WIN32_WINNT >= 0x0600) // Windows Vista {"get_process_io_priority", get_process_io_priority, METH_VARARGS, "Return process IO priority."}, {"set_process_io_priority", set_process_io_priority, METH_VARARGS, "Set process IO priority."}, #endif {"get_process_cpu_affinity", get_process_cpu_affinity, METH_VARARGS, "Return process CPU affinity as a bitmask."}, {"set_process_cpu_affinity", set_process_cpu_affinity, METH_VARARGS, "Set process CPU affinity."}, {"get_process_io_counters", get_process_io_counters, METH_VARARGS, "Get process I/O counters."}, {"is_process_suspended", is_process_suspended, METH_VARARGS, "Return True if one of the process threads is in a suspended state"}, {"get_process_num_handles", get_process_num_handles, METH_VARARGS, "Return the number of handles opened by process."}, {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process."}, {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS, "Return a list of process's memory mappings"}, {"get_ppid_map", get_ppid_map, METH_VARARGS, "Return a {pid:ppid, ...} dict for all running processes"}, // --- alternative pinfo interface {"get_process_cpu_times_2", get_process_cpu_times_2, METH_VARARGS, "Alternative implementation"}, {"get_process_create_time_2", get_process_create_time_2, METH_VARARGS, "Alternative implementation"}, {"get_process_num_handles_2", get_process_num_handles_2, METH_VARARGS, "Alternative implementation"}, {"get_process_io_counters_2", get_process_io_counters_2, METH_VARARGS, "Alternative implementation"}, {"get_process_memory_info_2", get_process_memory_info_2, METH_VARARGS, "Alternative implementation"}, // --- system-related functions {"get_pid_list", get_pid_list, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"pid_exists", pid_exists, METH_VARARGS, "Determine if the process exists in the current process list."}, {"get_num_cpus", get_num_cpus, METH_VARARGS, "Returns the number of CPUs on the system"}, {"get_system_boot_time", get_system_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"get_virtual_mem", get_virtual_mem, METH_VARARGS, "Return the total amount of physical memory, in bytes"}, {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, "Return system cpu times as a list"}, {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, {"get_disk_usage", get_disk_usage, METH_VARARGS, "Return path's disk total and free as a Python tuple."}, {"get_net_io_counters", get_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS, "Return dict of tuples of disks I/O information."}, {"get_system_users", get_system_users, METH_VARARGS, "Return a list of currently connected users."}, {"get_disk_partitions", get_disk_partitions, METH_VARARGS, "Return disk partitions."}, // --- windows API bindings {"win32_QueryDosDevice", win32_QueryDosDevice, METH_VARARGS, "QueryDosDevice binding"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) static struct module_state _state; #endif #if PY_MAJOR_VERSION >= 3 static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_mswindows_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_mswindows", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_mswindows_traverse, psutil_mswindows_clear, NULL }; #define INITERROR return NULL PyObject* PyInit__psutil_mswindows(void) #else #define INITERROR return void init_psutil_mswindows(void) #endif { struct module_state *st = NULL; #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods); #endif if (module == NULL) { INITERROR; } st = GETSTATE(module); st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } // 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_mswindows.py PyModule_AddIntConstant(module, "INFINITE", INFINITE); PyModule_AddIntConstant(module, "ERROR_ACCESS_DENIED", ERROR_ACCESS_DENIED); SetSeDebug(); #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-1.2.1/psutil/_psutil_mswindows.h0000664000175000017500000000715712243206601022267 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_mswindows */ #include #include // --- per-process functions static PyObject* get_process_cmdline(PyObject* self, PyObject* args); static PyObject* get_process_exe(PyObject* self, PyObject* args); static PyObject* get_process_cpu_times(PyObject* self, PyObject* args); static PyObject* get_process_create_time(PyObject* self, PyObject* args); static PyObject* get_process_memory_info(PyObject* self, PyObject* args); static PyObject* get_process_cwd(PyObject* self, PyObject* args); static PyObject* get_process_open_files(PyObject* self, PyObject* args); static PyObject* get_process_username(PyObject* self, PyObject* args); static PyObject* get_process_connections(PyObject* self, PyObject* args); static PyObject* get_process_num_threads(PyObject* self, PyObject* args); static PyObject* get_process_threads(PyObject* self, PyObject* args); static PyObject* get_process_priority(PyObject* self, PyObject* args); static PyObject* set_process_priority(PyObject* self, PyObject* args); #if (PSUTIL_WINVER >= 0x0600) // Windows Vista static PyObject* get_process_io_priority(PyObject* self, PyObject* args); static PyObject* set_process_io_priority(PyObject* self, PyObject* args); #endif static PyObject* get_process_io_counters(PyObject* self, PyObject* args); static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args); static PyObject* set_process_cpu_affinity(PyObject* self, PyObject* args); static PyObject* get_process_num_handles(PyObject* self, PyObject* args); static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args); static PyObject* get_process_memory_maps(PyObject* self, PyObject* args); static PyObject* get_ppid_map(PyObject* self, PyObject* args); static PyObject* get_process_cpu_times_2(PyObject* self, PyObject* args); static PyObject* get_process_create_time_2(PyObject* self, PyObject* args); static PyObject* get_process_num_handles_2(PyObject* self, PyObject* args); static PyObject* get_process_io_counters_2(PyObject* self, PyObject* args); static PyObject* get_process_memory_info_2(PyObject* self, PyObject* args); static PyObject* suspend_process(PyObject* self, PyObject* args); static PyObject* resume_process(PyObject* self, PyObject* args); static PyObject* is_process_suspended(PyObject* self, PyObject* args); static PyObject* process_wait(PyObject* self, PyObject* args); static PyObject* kill_process(PyObject* self, PyObject* args); // --- system-related functions static PyObject* get_pid_list(PyObject* self, PyObject* args); static PyObject* get_num_cpus(PyObject* self, PyObject* args); static PyObject* get_system_boot_time(PyObject* self, PyObject* args); static PyObject* get_virtual_mem(PyObject* self, PyObject* args); static PyObject* get_system_cpu_times(PyObject* self, PyObject* args); static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args); static PyObject* pid_exists(PyObject* self, PyObject* args); static PyObject* get_disk_usage(PyObject* self, PyObject* args); static PyObject* get_disk_partitions(PyObject* self, PyObject* args); static PyObject* get_net_io_counters(PyObject* self, PyObject* args); static PyObject* get_disk_io_counters(PyObject* self, PyObject* args); static PyObject* get_system_users(PyObject* self, PyObject* args); // --- windows API bindings static PyObject* win32_QueryDosDevice(PyObject* self, PyObject* args); // --- internal int suspend_resume_process(DWORD pid, int suspend); psutil-1.2.1/psutil/_psutil_sunos.c0000664000175000017500000010706012244714321021375 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 #include #include #include #include #include #include // for MNTTAB #include #include #include #include #include #include #include #include #include #include #include "_psutil_sunos.h" #define TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec) /* * 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* get_process_basic_info(PyObject* self, PyObject* args) { int pid; char path[100]; psinfo_t info; if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; sprintf(path, "/proc/%i/psinfo", 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 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* get_process_name_and_args(PyObject* self, PyObject* args) { int pid; char path[100]; psinfo_t info; if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; sprintf(path, "/proc/%i/psinfo", 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* get_process_cpu_times(PyObject* self, PyObject* args) { int pid; char path[100]; pstatus_t info; if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; sprintf(path, "/proc/%i/status", pid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; // results are more precise than os.times() return Py_BuildValue("dd", TV2DOUBLE(info.pr_utime), TV2DOUBLE(info.pr_stime)); } /* * Return process uids/gids as a Python tuple. */ static PyObject* get_process_cred(PyObject* self, PyObject* args) { int pid; char path[100]; prcred_t info; if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; sprintf(path, "/proc/%i/cred", 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* get_process_num_ctx_switches(PyObject* self, PyObject* args) { int pid; char path[100]; prusage_t info; if (! PyArg_ParseTuple(args, "i", &pid)) return NULL; sprintf(path, "/proc/%i/usage", 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* get_process_io_counters(PyObject* self, PyObject* args) { int pid; char path[100]; prusage_t info; if (! PyArg_ParseTuple(args, "i", &pid)) { return NULL; } sprintf(path, "/proc/%i/usage", 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* query_process_thread(PyObject* self, PyObject* args) { int pid, tid; char path[100]; lwpstatus_t info; if (! PyArg_ParseTuple(args, "ii", &pid, &tid)) return NULL; sprintf(path, "/proc/%i/lwp/%i/lwpstatus", pid, tid); if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; return Py_BuildValue("dd", TV2DOUBLE(info.pr_utime), TV2DOUBLE(info.pr_stime)); } /* * Return information about system virtual memory. */ static PyObject* get_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* get_system_users(PyObject* self, PyObject* args) { struct utmpx *ut; PyObject *ret_list = PyList_New(0); PyObject *tuple = NULL; PyObject *user_proc = NULL; if (ret_list == NULL) return NULL; while (NULL != (ut = getutxent())) { if (ut->ut_type == USER_PROCESS) user_proc = Py_True; else user_proc = Py_False; tuple = Py_BuildValue("(sssfO)", ut->ut_user, // username ut->ut_line, // tty ut->ut_host, // hostname (float)ut->ut_tv.tv_sec, // tstamp user_proc // (bool) user process ); if (tuple == NULL) goto error; if (PyList_Append(ret_list, tuple)) goto error; Py_DECREF(tuple); } endutent(); return ret_list; error: Py_XDECREF(tuple); Py_DECREF(ret_list); if (ut != NULL) endutent(); return NULL; } /* * Return disk mounted partitions as a list of tuples including device, * mount point and filesystem type. */ static PyObject* get_disk_partitions(PyObject* self, PyObject* args) { FILE *file; 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* get_system_per_cpu_times(PyObject* self, PyObject* args) { kstat_ctl_t *kc; kstat_t *ksp; cpu_stat_t cs; int numcpus; int i; 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; } numcpus = sysconf(_SC_NPROCESSORS_ONLN) - 1; for (i=0; i<=numcpus; i++) { ksp = kstat_lookup(kc, "cpu_stat", i, NULL); if (ksp == NULL) { PyErr_SetFromErrno(PyExc_OSError); goto error; } 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); } 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* get_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* get_process_memory_maps(PyObject* self, PyObject* args) { int pid; int fd = -1; char path[100]; 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; PyObject* pytuple = NULL; PyObject* py_retlist = PyList_New(0); if (py_retlist == NULL) { return NULL; } if (! PyArg_ParseTuple(args, "i", &pid)) { goto error; } sprintf(path, "/proc/%i/status", pid); if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) { goto error; } sprintf(path, "/proc/%i/xmap", 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]"; } } } pytuple = 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 (!pytuple) goto error; if (PyList_Append(py_retlist, pytuple)) goto error; Py_DECREF(pytuple); // increment pointer p += 1; } close(fd); free(xmap); return py_retlist; error: if (fd != -1) close(fd); Py_XDECREF(pytuple); Py_DECREF(py_retlist); if (xmap != NULL) free(xmap); return NULL; } /* * Return a list of tuples for network I/O statistics. */ static PyObject* get_net_io_counters(PyObject* self, PyObject* args) { kstat_ctl_t *kc = NULL; kstat_t *ksp; kstat_named_t *rbytes, *wbytes, *rpkts, *wpkts, *ierrs, *oerrs; PyObject* py_retdict = PyDict_New(); PyObject* py_ifc_info = NULL; if (py_retdict == NULL) return NULL; kc = kstat_open(); if (kc == NULL) 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; /* // XXX "lo" (localhost) interface makes kstat_data_lookup() fail // (maybe because "ifconfig -a" says it's a virtual interface?). if ((strcmp(ksp->ks_module, "link") != 0) && (strcmp(ksp->ks_module, "lo") != 0)) { goto skip; */ if ((strcmp(ksp->ks_module, "link") != 0)) { goto next; } if (kstat_read(kc, ksp, NULL) == -1) { errno = 0; continue; } 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 defined(_INT64_TYPE) py_ifc_info = Py_BuildValue("(KKKKkkii)", rbytes->value.ui64, wbytes->value.ui64, rpkts->value.ui64, wpkts->value.ui64, ierrs->value.ui32, oerrs->value.ui32, #else py_ifc_info = Py_BuildValue("(kkkkkkii)", rbytes->value.ui32, wbytes->value.ui32, rpkts->value.ui32, wpkts->value.ui32, ierrs->value.ui32, oerrs->value.ui32, #endif 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); return py_retdict; error: Py_XDECREF(py_ifc_info); Py_DECREF(py_retdict); if (kc != NULL) kstat_close(kc); return NULL; } #define EXPER_IP_AND_ALL_IRES (1024+4) // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; /* * Return TCP and UDP connections opened by process. * * 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* get_process_connections(PyObject* self, PyObject* args) { long pid; int sd = NULL; 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; 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; PyObject *af_filter = NULL; PyObject *type_filter = NULL; if (py_retlist == NULL) return NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) goto error; if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } 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) { //perror("malloc"); //break; PyErr_NoMemory(); goto error; } 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++) { // check PID if (tp->tcpConnCreationProcess != 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("(iiiNNi)", -1, AF_INET, SOCK_STREAM, py_laddr, py_raddr, state); 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++) { // check PID if (tp6->tcp6ConnCreationProcess != 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("(iiiNNi)", -1, AF_INET6, SOCK_STREAM, py_laddr, py_raddr, state); if (!py_tuple) { goto error; } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #endif 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++) { // check PID if (ude->udpCreationProcess != pid) 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("(iiiNNi)", -1, AF_INET, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE); if (!py_tuple) { goto error; } if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } } #if defined(AF_INET6) 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++) { // check PID if (ude6->udp6CreationProcess != 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("(iiiNNi)", -1, AF_INET6, SOCK_DGRAM, py_laddr, py_raddr, PSUTIL_CONN_NONE); 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); // TODO : free databuf if (sd != NULL) close(sd); return NULL; } static PyObject* get_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; } } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- process-related functions {"get_process_basic_info", get_process_basic_info, METH_VARARGS, "Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"}, {"get_process_name_and_args", get_process_name_and_args, METH_VARARGS, "Return process name and args."}, {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, "Return process user and system CPU times."}, {"get_process_cred", get_process_cred, METH_VARARGS, "Return process uids/gids."}, {"query_process_thread", query_process_thread, METH_VARARGS, "Return info about a process thread"}, {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS, "Return process memory mappings"}, {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"get_process_connections", get_process_connections, METH_VARARGS, "Return TCP and UDP connections opened by process."}, // --- system-related functions {"get_swap_mem", get_swap_mem, METH_VARARGS, "Return information about system swap memory."}, {"get_system_users", get_system_users, METH_VARARGS, "Return currently connected users."}, {"get_disk_partitions", get_disk_partitions, METH_VARARGS, "Return disk partitions."}, {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS, "Return system per-CPU times."}, {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS, "Return a Python dict of tuples for disk I/O statistics."}, {"get_net_io_counters", get_net_io_counters, METH_VARARGS, "Return a Python dict of tuples for network I/O statistics."}, {"get_boot_time", get_boot_time, METH_VARARGS, "Return system boot time in seconds since the EPOCH."}, {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 PyObject * 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, "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); PyModule_AddIntConstant(module, "TCPS_IDLE", TCPS_IDLE); // sunos specific PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND); // sunos specific PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE); if (module == NULL) { INITERROR; } #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-1.2.1/psutil/_psutil_linux.h0000664000175000017500000000133512243206601021364 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 module methods for _psutil_linux */ #include static PyObject* linux_ioprio_get(PyObject* self, PyObject* args); static PyObject* linux_ioprio_set(PyObject* self, PyObject* args); static PyObject* get_disk_partitions(PyObject* self, PyObject* args); static PyObject* get_sysinfo(PyObject* self, PyObject* args); static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args); static PyObject* set_process_cpu_affinity(PyObject* self, PyObject* args); static PyObject* get_system_users(PyObject* self, PyObject* args); psutil-1.2.1/psutil/_psutil_bsd.h0000664000175000017500000000507712243206601021004 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. * * BSD platform-specific module methods for _psutil_bsd */ #include // --- per-process functions static PyObject* get_process_cpu_times(PyObject* self, PyObject* args); static PyObject* get_process_name(PyObject* self, PyObject* args); static PyObject* get_process_exe(PyObject* self, PyObject* args); static PyObject* get_process_cmdline(PyObject* self, PyObject* args); static PyObject* get_process_ppid(PyObject* self, PyObject* args); static PyObject* get_process_uids(PyObject* self, PyObject* args); static PyObject* get_process_gids(PyObject* self, PyObject* args); static PyObject* get_process_connections(PyObject* self, PyObject* args); static PyObject* get_process_create_time(PyObject* self, PyObject* args); static PyObject* get_process_memory_info(PyObject* self, PyObject* args); static PyObject* get_process_num_threads(PyObject* self, PyObject* args); static PyObject* get_process_num_fds(PyObject* self, PyObject* args); static PyObject* get_process_threads(PyObject* self, PyObject* args); static PyObject* get_process_status(PyObject* self, PyObject* args); static PyObject* get_process_io_counters(PyObject* self, PyObject* args); static PyObject* get_process_tty_nr(PyObject* self, PyObject* args); static PyObject* get_process_memory_maps(PyObject* self, PyObject* args); static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* get_process_open_files(PyObject* self, PyObject* args); static PyObject* get_process_cwd(PyObject* self, PyObject* args); #endif // --- system-related functions static PyObject* get_pid_list(PyObject* self, PyObject* args); static PyObject* get_num_cpus(PyObject* self, PyObject* args); static PyObject* get_virtual_mem(PyObject* self, PyObject* args); static PyObject* get_swap_mem(PyObject* self, PyObject* args); static PyObject* get_system_cpu_times(PyObject* self, PyObject* args); #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args); #endif static PyObject* get_system_boot_time(PyObject* self, PyObject* args); static PyObject* get_disk_partitions(PyObject* self, PyObject* args); static PyObject* get_net_io_counters(PyObject* self, PyObject* args); static PyObject* get_disk_io_counters(PyObject* self, PyObject* args); static PyObject* get_system_users(PyObject* self, PyObject* args); psutil-1.2.1/psutil/_psutil_osx.h0000664000175000017500000000444612243206601021044 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. * * OS X platform-specific module methods for _psutil_osx */ #include // --- per-process functions static PyObject* get_process_name(PyObject* self, PyObject* args); static PyObject* get_process_cmdline(PyObject* self, PyObject* args); static PyObject* get_process_cwd(PyObject* self, PyObject* args); static PyObject* get_process_exe(PyObject* self, PyObject* args); static PyObject* get_process_ppid(PyObject* self, PyObject* args); static PyObject* get_process_uids(PyObject* self, PyObject* args); static PyObject* get_process_gids(PyObject* self, PyObject* args); static PyObject* get_process_cpu_times(PyObject* self, PyObject* args); static PyObject* get_process_create_time(PyObject* self, PyObject* args); static PyObject* get_process_memory_info(PyObject* self, PyObject* args); static PyObject* get_process_num_threads(PyObject* self, PyObject* args); static PyObject* get_process_status(PyObject* self, PyObject* args); static PyObject* get_process_threads(PyObject* self, PyObject* args); static PyObject* get_process_open_files(PyObject* self, PyObject* args); static PyObject* get_process_connections(PyObject* self, PyObject* args); static PyObject* get_process_num_fds(PyObject* self, PyObject* args); static PyObject* get_process_tty_nr(PyObject* self, PyObject* args); static PyObject* get_process_memory_maps(PyObject* self, PyObject* args); // --- system-related functions static PyObject* get_pid_list(PyObject* self, PyObject* args); static PyObject* get_num_cpus(PyObject* self, PyObject* args); static PyObject* get_virtual_mem(PyObject* self, PyObject* args); static PyObject* get_swap_mem(PyObject* self, PyObject* args); static PyObject* get_system_cpu_times(PyObject* self, PyObject* args); static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args); static PyObject* get_system_boot_time(PyObject* self, PyObject* args); static PyObject* get_disk_partitions(PyObject* self, PyObject* args); static PyObject* get_net_io_counters(PyObject* self, PyObject* args); static PyObject* get_disk_io_counters(PyObject* self, PyObject* args); static PyObject* get_system_users(PyObject* self, PyObject* args); psutil-1.2.1/psutil/_psutil_posix.h0000664000175000017500000000060212243206601021363 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. * * POSIX specific module methods for _psutil_posix */ #include static PyObject* posix_getpriority(PyObject* self, PyObject* args); static PyObject* posix_setpriority(PyObject* self, PyObject* args); psutil-1.2.1/psutil/_psmswindows.py0000664000175000017500000004216212243463073021436 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. """Windows platform implementation.""" import errno import os import sys import warnings import _psutil_mswindows from _psutil_mswindows import ERROR_ACCESS_DENIED from psutil._common import * from psutil._compat import PY3, xrange, wraps from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired # process priority constants: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx from _psutil_mswindows import (ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS, INFINITE) # Windows specific extended namespace __extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS", # "CONN_DELETE_TCB", ] # --- module level constants (gets pushed up to psutil module) # Since these constants get determined at import time we do not want to # crash immediately; instead we'll set them to None and most likely # we'll crash later as they're used for determining process CPU stats # and creation_time try: NUM_CPUS = _psutil_mswindows.get_num_cpus() except Exception: NUM_CPUS = None warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) try: BOOT_TIME = _psutil_mswindows.get_system_boot_time() except Exception: BOOT_TIME = None warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) try: TOTAL_PHYMEM = _psutil_mswindows.get_virtual_mem()[0] except Exception: TOTAL_PHYMEM = None warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) CONN_DELETE_TCB = "DELETE_TCB" WAIT_TIMEOUT = 0x00000102 # 258 in decimal ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED]) TCP_STATUSES = { _psutil_mswindows.MIB_TCP_STATE_ESTAB: CONN_ESTABLISHED, _psutil_mswindows.MIB_TCP_STATE_SYN_SENT: CONN_SYN_SENT, _psutil_mswindows.MIB_TCP_STATE_SYN_RCVD: CONN_SYN_RECV, _psutil_mswindows.MIB_TCP_STATE_FIN_WAIT1: CONN_FIN_WAIT1, _psutil_mswindows.MIB_TCP_STATE_FIN_WAIT2: CONN_FIN_WAIT2, _psutil_mswindows.MIB_TCP_STATE_TIME_WAIT: CONN_TIME_WAIT, _psutil_mswindows.MIB_TCP_STATE_CLOSED: CONN_CLOSE, _psutil_mswindows.MIB_TCP_STATE_CLOSE_WAIT: CONN_CLOSE_WAIT, _psutil_mswindows.MIB_TCP_STATE_LAST_ACK: CONN_LAST_ACK, _psutil_mswindows.MIB_TCP_STATE_LISTEN: CONN_LISTEN, _psutil_mswindows.MIB_TCP_STATE_CLOSING: CONN_CLOSING, _psutil_mswindows.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB, _psutil_mswindows.PSUTIL_CONN_NONE: CONN_NONE, } @memoize def _win32_QueryDosDevice(s): return _psutil_mswindows.win32_QueryDosDevice(s) def _convert_raw_path(s): # convert paths using native DOS format like: # "\Device\HarddiskVolume1\Windows\systemew\file.txt" # into: "C:\Windows\systemew\file.txt" if PY3 and not isinstance(s, str): s = s.decode('utf8') rawdrive = '\\'.join(s.split('\\')[:3]) driveletter = _win32_QueryDosDevice(rawdrive) return os.path.join(driveletter, s[len(rawdrive):]) # --- public functions get_system_boot_time = _psutil_mswindows.get_system_boot_time # ...so that we can test it from test_memory_leask.py get_num_cpus = _psutil_mswindows.get_num_cpus() nt_virtmem_info = namedtuple('vmem', ' '.join([ # all platforms 'total', 'available', 'percent', 'used', 'free'])) def virtual_memory(): """System virtual memory as a namedtuple.""" mem = _psutil_mswindows.get_virtual_mem() totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem # total = totphys avail = availphys free = availphys used = total - avail percent = usage_percent((total - avail), total, _round=1) return nt_virtmem_info(total, avail, percent, used, free) def swap_memory(): """Swap system memory as a (total, used, free, sin, sout) tuple.""" mem = _psutil_mswindows.get_virtual_mem() total = mem[2] free = mem[3] used = total - free percent = usage_percent(used, total, _round=1) return nt_swapmeminfo(total, used, free, percent, 0, 0) def get_disk_usage(path): """Return disk usage associated with path.""" try: total, free = _psutil_mswindows.get_disk_usage(path) except WindowsError: if not os.path.exists(path): raise OSError(errno.ENOENT, "No such file or directory: '%s'" % path) raise used = total - free percent = usage_percent(used, total, _round=1) return nt_diskinfo(total, used, free, percent) def disk_partitions(all): """Return disk partitions.""" rawlist = _psutil_mswindows.get_disk_partitions(all) return [nt_partition(*x) for x in rawlist] _cputimes_ntuple = namedtuple('cputimes', 'user system idle') def get_system_cpu_times(): """Return system CPU times as a named tuple.""" user, system, idle = _psutil_mswindows.get_system_cpu_times() return _cputimes_ntuple(user, system, idle) def get_system_per_cpu_times(): """Return system per-CPU times as a list of named tuples.""" ret = [] for cpu_t in _psutil_mswindows.get_system_per_cpu_times(): user, system, idle = cpu_t item = _cputimes_ntuple(user, system, idle) ret.append(item) return ret def get_system_users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = _psutil_mswindows.get_system_users() for item in rawlist: user, hostname, tstamp = item nt = nt_user(user, None, hostname, tstamp) retlist.append(nt) return retlist get_pid_list = _psutil_mswindows.get_pid_list pid_exists = _psutil_mswindows.pid_exists net_io_counters = _psutil_mswindows.get_net_io_counters disk_io_counters = _psutil_mswindows.get_disk_io_counters get_ppid_map = _psutil_mswindows.get_ppid_map # not meant to be public def wrap_exceptions(fun): """Decorator which translates bare OSError and WindowsError exceptions into NoSuchProcess and AccessDenied. """ @wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: raise AccessDenied(self.pid, self._process_name) if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._process_name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_process_name"] def __init__(self, pid): self.pid = pid self._process_name = None @wrap_exceptions def get_process_name(self): """Return process name, 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: return os.path.basename(self.get_process_exe()) @wrap_exceptions def get_process_exe(self): # Note: os.path.exists(path) may return False even if the file # is there, see: # http://stackoverflow.com/questions/3112546/os-path-exists-lies return _convert_raw_path(_psutil_mswindows.get_process_exe(self.pid)) @wrap_exceptions def get_process_cmdline(self): """Return process cmdline as a list of arguments.""" return _psutil_mswindows.get_process_cmdline(self.pid) def get_process_ppid(self): """Return process parent pid.""" try: return get_ppid_map()[self.pid] except KeyError: raise NoSuchProcess(self.pid, self._process_name) def _get_raw_meminfo(self): try: return _psutil_mswindows.get_process_memory_info(self.pid) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: return _psutil_mswindows.get_process_memory_info_2(self.pid) raise @wrap_exceptions def get_memory_info(self): """Returns a tuple or RSS/VMS memory usage in bytes.""" # on Windows RSS == WorkingSetSize and VSM == PagefileUsage # fields of PROCESS_MEMORY_COUNTERS struct: # http://msdn.microsoft.com/en-us/library/windows/desktop/ms684877(v=vs.85).aspx t = self._get_raw_meminfo() return nt_meminfo(t[2], t[7]) _nt_ext_mem = namedtuple('meminfo', ' '.join([ 'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool', 'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool', 'pagefile', 'peak_pagefile', 'private'])) @wrap_exceptions def get_ext_memory_info(self): return self._nt_ext_mem(*self._get_raw_meminfo()) nt_mmap_grouped = namedtuple('mmap', 'path rss') nt_mmap_ext = namedtuple('mmap', 'addr perms path rss') def get_memory_maps(self): try: raw = _psutil_mswindows.get_process_memory_maps(self.pid) except OSError: # XXX - can't use wrap_exceptions decorator as we're # returning a generator; probably needs refactoring. err = sys.exc_info()[1] if err.errno in (errno.EPERM, errno.EACCES, ERROR_ACCESS_DENIED): raise AccessDenied(self.pid, self._process_name) if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._process_name) raise else: for addr, perm, path, rss in raw: path = _convert_raw_path(path) addr = hex(addr) yield (addr, perm, path, rss) @wrap_exceptions def kill_process(self): """Terminates the process with the given PID.""" return _psutil_mswindows.kill_process(self.pid) @wrap_exceptions def process_wait(self, timeout=None): if timeout is None: timeout = INFINITE else: # WaitForSingleObject() expects time in milliseconds timeout = int(timeout * 1000) ret = _psutil_mswindows.process_wait(self.pid, timeout) if ret == WAIT_TIMEOUT: raise TimeoutExpired(self.pid, self._process_name) return ret @wrap_exceptions def get_process_username(self): """Return the name of the user that owns the process""" if self.pid in (0, 4): return 'NT AUTHORITY\\SYSTEM' return _psutil_mswindows.get_process_username(self.pid) @wrap_exceptions def get_process_create_time(self): # special case for kernel process PIDs; return system boot time if self.pid in (0, 4): return BOOT_TIME try: return _psutil_mswindows.get_process_create_time(self.pid) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: return _psutil_mswindows.get_process_create_time_2(self.pid) raise @wrap_exceptions def get_process_num_threads(self): return _psutil_mswindows.get_process_num_threads(self.pid) @wrap_exceptions def get_process_threads(self): rawlist = _psutil_mswindows.get_process_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = nt_thread(thread_id, utime, stime) retlist.append(ntuple) return retlist @wrap_exceptions def get_cpu_times(self): try: ret = _psutil_mswindows.get_process_cpu_times(self.pid) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: ret = _psutil_mswindows.get_process_cpu_times_2(self.pid) else: raise return nt_cputimes(*ret) @wrap_exceptions def suspend_process(self): return _psutil_mswindows.suspend_process(self.pid) @wrap_exceptions def resume_process(self): return _psutil_mswindows.resume_process(self.pid) @wrap_exceptions def get_process_cwd(self): if self.pid in (0, 4): raise AccessDenied(self.pid, self._process_name) # return a normalized pathname since the native C function appends # "\\" at the and of the path path = _psutil_mswindows.get_process_cwd(self.pid) return os.path.normpath(path) @wrap_exceptions def get_open_files(self): if self.pid in (0, 4): return [] retlist = [] # Filenames come in in native format like: # "\Device\HarddiskVolume1\Windows\systemew\file.txt" # Convert the first part in the corresponding drive letter # (e.g. "C:\") by using Windows's QueryDosDevice() raw_file_names = _psutil_mswindows.get_process_open_files(self.pid) for file in raw_file_names: file = _convert_raw_path(file) if isfile_strict(file) and file not in retlist: ntuple = nt_openfile(file, -1) retlist.append(ntuple) return retlist @wrap_exceptions def get_connections(self, kind='inet'): if kind not in conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = _psutil_mswindows.get_process_connections(self.pid, families, types) ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] nt = nt_connection(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret @wrap_exceptions def get_process_nice(self): return _psutil_mswindows.get_process_priority(self.pid) @wrap_exceptions def set_process_nice(self, value): return _psutil_mswindows.set_process_priority(self.pid, value) # available on Windows >= Vista if hasattr(_psutil_mswindows, "get_process_io_priority"): @wrap_exceptions def get_process_ionice(self): return _psutil_mswindows.get_process_io_priority(self.pid) @wrap_exceptions def set_process_ionice(self, value, _): if _: raise TypeError("set_process_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 _psutil_mswindows.set_process_io_priority(self.pid, value) @wrap_exceptions def get_process_io_counters(self): try: ret = _psutil_mswindows.get_process_io_counters(self.pid) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: ret = _psutil_mswindows.get_process_io_counters_2(self.pid) else: raise return nt_io(*ret) @wrap_exceptions def get_process_status(self): suspended = _psutil_mswindows.is_process_suspended(self.pid) if suspended: return STATUS_STOPPED else: return STATUS_RUNNING @wrap_exceptions def get_process_cpu_affinity(self): from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x] bitmask = _psutil_mswindows.get_process_cpu_affinity(self.pid) return from_bitmask(bitmask) @wrap_exceptions def set_process_cpu_affinity(self, value): def to_bitmask(l): if not l: raise ValueError("invalid argument %r" % l) out = 0 for b in l: out |= 2 ** b return out # SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER # is returned for an invalid CPU but this seems not to be true, # therefore we check CPUs validy beforehand. allcpus = list(range(len(get_system_per_cpu_times()))) for cpu in value: if cpu not in allcpus: raise ValueError("invalid CPU %r" % cpu) bitmask = to_bitmask(value) _psutil_mswindows.set_process_cpu_affinity(self.pid, bitmask) @wrap_exceptions def get_num_handles(self): try: return _psutil_mswindows.get_process_num_handles(self.pid) except OSError: err = sys.exc_info()[1] if err.errno in ACCESS_DENIED_SET: return _psutil_mswindows.get_process_num_handles_2(self.pid) raise @wrap_exceptions def get_num_ctx_switches(self): tupl = _psutil_mswindows.get_process_num_ctx_switches(self.pid) return nt_ctxsw(*tupl) psutil-1.2.1/psutil/_psutil_linux.c0000664000175000017500000003042412243745763021401 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 "_psutil_linux.h" // Linux >= 2.6.13 #define HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set) // Linux >= 2.6.36 (supposedly) and glibc >= 13 #define HAVE_PRLIMIT \ (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \ (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \ defined(__NR_prlimit64) #if HAVE_PRLIMIT #define _FILE_OFFSET_BITS 64 #include #include #endif #if 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* linux_ioprio_get(PyObject* self, PyObject* args) { long pid; int ioprio, ioclass, iodata; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid); if (ioprio == -1) { return PyErr_SetFromErrno(PyExc_OSError); } ioclass = IOPRIO_PRIO_CLASS(ioprio); iodata = IOPRIO_PRIO_DATA(ioprio); return Py_BuildValue("ii", ioclass, iodata); } /* * A wrapper around ioprio_set(); sets process I/O priority. * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE * or 0. iodata goes from 0 to 7 depending on ioclass specified. */ static PyObject* linux_ioprio_set(PyObject* self, PyObject* args) { long pid; int ioprio, ioclass, iodata; int retval; if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) { return NULL; } ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata); retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio); if (retval == -1) { return PyErr_SetFromErrno(PyExc_OSError); } Py_INCREF(Py_None); return Py_None; } #endif #if 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* linux_prlimit(PyObject* self, PyObject* args) { long pid; int ret, resource; struct rlimit old, new; struct rlimit *newp = NULL; PyObject *soft = NULL; PyObject *hard = NULL; if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard)) { return NULL; } // get if (soft == NULL && hard == NULL) { ret = prlimit(pid, resource, NULL, &old); if (ret == -1) return PyErr_SetFromErrno(PyExc_OSError); #if defined(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(HAVE_LARGEFILE_SUPPORT) new.rlim_cur = PyLong_AsLongLong(soft); if (new.rlim_cur == (rlim_t)-1 && PyErr_Occurred()) return NULL; new.rlim_max = PyLong_AsLongLong(hard); if (new.rlim_max == (rlim_t)-1 && PyErr_Occurred()) return NULL; #else new.rlim_cur = PyLong_AsLong(soft); if (new.rlim_cur == (rlim_t)-1 && PyErr_Occurred()) return NULL; new.rlim_max = PyLong_AsLong(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_INCREF(Py_None); return Py_None; } } #endif /* * Return disk mounted partitions as a list of tuples including device, * mount point and filesystem type */ static PyObject* get_disk_partitions(PyObject* self, PyObject* args) { FILE *file = NULL; struct mntent *entry; PyObject* py_retlist = PyList_New(0); PyObject* py_tuple = NULL; 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* get_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 long (the bitmask) */ static PyObject* get_process_cpu_affinity(PyObject* self, PyObject* args) { unsigned long mask; unsigned int len = sizeof(mask); long pid; if (!PyArg_ParseTuple(args, "i", &pid)) { return NULL; } if (sched_getaffinity(pid, len, (cpu_set_t *)&mask) < 0) { return PyErr_SetFromErrno(PyExc_OSError); } return Py_BuildValue("l", mask); } /* * Set process CPU affinity; expects a bitmask */ static PyObject* set_process_cpu_affinity(PyObject* self, PyObject* args) { unsigned long mask; unsigned int len = sizeof(mask); long pid; if (!PyArg_ParseTuple(args, "lk", &pid, &mask)) { return NULL; } if (sched_setaffinity(pid, len, (cpu_set_t *)&mask)) { return PyErr_SetFromErrno(PyExc_OSError); } Py_INCREF(Py_None); return Py_None; } /* * Return currently connected users as a list of tuples. */ static PyObject* get_system_users(PyObject* self, PyObject* args) { PyObject *ret_list = PyList_New(0); PyObject *tuple = NULL; PyObject *user_proc = NULL; struct utmp *ut; if (ret_list == NULL) return NULL; setutent(); while (NULL != (ut = getutent())) { tuple = NULL; user_proc = NULL; if (ut->ut_type == USER_PROCESS) user_proc = Py_True; else user_proc = Py_False; tuple = Py_BuildValue("(sssfO)", ut->ut_user, // username ut->ut_line, // tty ut->ut_host, // hostname (float)ut->ut_tv.tv_sec, // tstamp user_proc // (bool) user process ); if (! tuple) goto error; if (PyList_Append(ret_list, tuple)) goto error; Py_DECREF(tuple); } endutent(); return ret_list; error: Py_XDECREF(tuple); Py_XDECREF(user_proc); Py_DECREF(ret_list); endutent(); return NULL; } /* * Define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions #if HAVE_IOPRIO {"ioprio_get", linux_ioprio_get, METH_VARARGS, "Get process I/O priority"}, {"ioprio_set", linux_ioprio_set, METH_VARARGS, "Set process I/O priority"}, #endif #if HAVE_PRLIMIT {"prlimit", linux_prlimit, METH_VARARGS, "Get or set process resource limits."}, #endif {"set_process_cpu_affinity", set_process_cpu_affinity, METH_VARARGS, "Set process CPU affinity; expects a bitmask."}, // --- system related functions {"get_disk_partitions", get_disk_partitions, METH_VARARGS, "Return disk mounted partitions as a list of tuples including " "device, mount point and filesystem type"}, {"get_sysinfo", get_sysinfo, METH_VARARGS, "A wrapper around sysinfo(), return system memory usage statistics"}, {"get_process_cpu_affinity", get_process_cpu_affinity, METH_VARARGS, "Return process CPU affinity as a Python long (the bitmask)."}, {"get_system_users", get_system_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_linux_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_linux", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_linux_traverse, psutil_linux_clear, NULL }; #define INITERROR return NULL PyObject * PyInit__psutil_linux(void) #else #define INITERROR return void init_psutil_linux(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods); #endif #if HAVE_PRLIMIT PyModule_AddIntConstant(module, "RLIM_INFINITY", RLIM_INFINITY); 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); #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 if (module == NULL) { INITERROR; } #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-1.2.1/psutil/_psutil_posix.c0000664000175000017500000000511412243206601021361 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 "_psutil_posix.h" /* * Given a PID return process priority as a Python integer. */ static PyObject* posix_getpriority(PyObject* self, PyObject* args) { long pid; int priority; errno = 0; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } priority = getpriority(PRIO_PROCESS, pid); if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } return Py_BuildValue("i", priority); } /* * Given a PID and a value change process priority. */ static PyObject* posix_setpriority(PyObject* self, PyObject* args) { long pid; int priority; int retval; if (! PyArg_ParseTuple(args, "li", &pid, &priority)) { return NULL; } retval = setpriority(PRIO_PROCESS, pid, priority); if (retval == -1) { return PyErr_SetFromErrno(PyExc_OSError); } Py_INCREF(Py_None); return Py_None; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { {"getpriority", posix_getpriority, METH_VARARGS, "Return process priority"}, {"setpriority", posix_setpriority, METH_VARARGS, "Set process priority"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_posix_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_posix", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_posix_traverse, psutil_posix_clear, NULL }; #define INITERROR return NULL PyObject * PyInit__psutil_posix(void) #else #define INITERROR return void init_psutil_posix(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods); #endif if (module == NULL) { INITERROR; } #if PY_MAJOR_VERSION >= 3 return module; #endif } psutil-1.2.1/psutil/_compat.py0000664000175000017500000002267712243463240020331 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. """Module which provides compatibility with older Python versions.""" __all__ = ["PY3", "int", "long", "xrange", "exec_", "callable", "namedtuple", "property", "defaultdict"] import sys try: import __builtin__ except ImportError: import builtins as __builtin__ # py3 PY3 = sys.version_info >= (3,) if PY3: int = int long = int xrange = range unicode = str exec_ = getattr(__builtin__, "exec") print_ = getattr(__builtin__, "print") def u(s): return s else: int = int long = long xrange = xrange unicode = unicode def u(s): return unicode(s, "unicode_escape") def exec_(code, globs=None, locs=None): if globs is None: frame = _sys._getframe(1) globs = frame.f_globals if locs is None: locs = frame.f_locals del frame elif locs is None: locs = globs exec("""exec code in globs, locs""") def print_(s): sys.stdout.write(s + '\n') sys.stdout.flush() # removed in 3.0, reintroduced in 3.2 try: callable = callable except NameError: def callable(obj): return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) # --- stdlib additions try: from collections import namedtuple except ImportError: from operator import itemgetter as _itemgetter from keyword import iskeyword as _iskeyword import sys as _sys def namedtuple(typename, field_names, verbose=False, rename=False): """A collections.namedtuple implementation written in Python to support Python versions < 2.6. Taken from: http://code.activestate.com/recipes/500261/ """ # Parse and validate the field names. Validation serves two # purposes, generating informative error messages and preventing # template injection attacks. if isinstance(field_names, basestring): # names separated by whitespace and/or commas field_names = field_names.replace(',', ' ').split() field_names = tuple(map(str, field_names)) if rename: names = list(field_names) seen = set() for i, name in enumerate(names): if (not min(c.isalnum() or c == '_' for c in name) or _iskeyword(name) or not name or name[0].isdigit() or name.startswith('_') or name in seen): names[i] = '_%d' % i seen.add(name) field_names = tuple(names) for name in (typename,) + field_names: if not min(c.isalnum() or c == '_' for c in name): raise ValueError('Type names and field names can only contain ' 'alphanumeric characters and underscores: %r' % name) if _iskeyword(name): raise ValueError('Type names and field names cannot be a keyword: %r' % name) if name[0].isdigit(): raise ValueError('Type names and field names cannot start with a ' 'number: %r' % name) seen_names = set() for name in field_names: if name.startswith('_') and not rename: raise ValueError('Field names cannot start with an underscore: %r' % name) if name in seen_names: raise ValueError('Encountered duplicate field name: %r' % name) seen_names.add(name) # Create and fill-in the class template numfields = len(field_names) # tuple repr without parens or quotes argtxt = repr(field_names).replace("'", "")[1:-1] reprtxt = ', '.join('%s=%%r' % name for name in field_names) template = '''class %(typename)s(tuple): '%(typename)s(%(argtxt)s)' \n __slots__ = () \n _fields = %(field_names)r \n def __new__(_cls, %(argtxt)s): return _tuple.__new__(_cls, (%(argtxt)s)) \n @classmethod def _make(cls, iterable, new=tuple.__new__, len=len): 'Make a new %(typename)s object from a sequence or iterable' result = new(cls, iterable) if len(result) != %(numfields)d: raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) return result \n def __repr__(self): return '%(typename)s(%(reprtxt)s)' %% self \n def _asdict(self): 'Return a new dict which maps field names to their values' return dict(zip(self._fields, self)) \n def _replace(_self, **kwds): 'Return a new %(typename)s object replacing specified fields with new values' result = _self._make(map(kwds.pop, %(field_names)r, _self)) if kwds: raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) return result \n def __getnewargs__(self): return tuple(self) \n\n''' % locals() for i, name in enumerate(field_names): template += ' %s = _property(_itemgetter(%d))\n' % (name, i) if verbose: sys.stdout.write(template + '\n') sys.stdout.flush() # Execute the template string in a temporary namespace namespace = dict( _itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, _property=property, _tuple=tuple) try: exec_(template, namespace) except SyntaxError: e = sys.exc_info()[1] raise SyntaxError(e.message + ':\n' + template) result = namespace[typename] # For pickling to work, the __module__ variable needs to be set # to the frame where the named tuple is created. Bypass this # step in enviroments where sys._getframe is not defined (Jython # for example) or sys._getframe is not defined for arguments # greater than 0 (IronPython). try: result.__module__ = _sys._getframe( 1).f_globals.get('__name__', '__main__') except (AttributeError, ValueError): pass return result # hack to support property.setter/deleter on python < 2.6 # http://docs.python.org/library/functions.html?highlight=property#property if hasattr(property, 'setter'): property = property else: class property(__builtin__.property): __metaclass__ = type def __init__(self, fget, *args, **kwargs): super(property, self).__init__(fget, *args, **kwargs) self.__doc__ = fget.__doc__ def getter(self, method): return property(method, self.fset, self.fdel) def setter(self, method): return property(self.fget, method, self.fdel) def deleter(self, method): return property(self.fget, self.fset, method) # py 2.5 collections.defauldict # Taken from: # http://code.activestate.com/recipes/523034-emulate-collectionsdefaultdict/ # credits: Jason Kirtland try: from collections import defaultdict except ImportError: class defaultdict(dict): def __init__(self, default_factory=None, *a, **kw): if (default_factory is not None and \ not hasattr(default_factory, '__call__')): raise TypeError('first argument must be callable') dict.__init__(self, *a, **kw) self.default_factory = default_factory def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return self.__missing__(key) def __missing__(self, key): if self.default_factory is None: raise KeyError(key) self[key] = value = self.default_factory() return value def __reduce__(self): if self.default_factory is None: args = tuple() else: args = self.default_factory, return type(self), args, None, None, self.items() def copy(self): return self.__copy__() def __copy__(self): return type(self)(self.default_factory, self) def __deepcopy__(self, memo): import copy return type(self)(self.default_factory, copy.deepcopy(self.items())) def __repr__(self): return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self)) # py 2.5 functools.wraps try: from functools import wraps except ImportError: def wraps(original): def inner(fn): # see functools.WRAPPER_ASSIGNMENTS for attribute in ['__module__', '__name__', '__doc__' ]: setattr(fn, attribute, getattr(original, attribute)) # see functools.WRAPPER_UPDATES for attribute in ['__dict__', ]: if hasattr(fn, attribute): getattr(fn, attribute).update(getattr(original, attribute)) else: setattr(fn, attribute, getattr(original, attribute).copy()) return fn return inner psutil-1.2.1/psutil/error.py0000664000175000017500000000115612243206601020021 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. """This module is deprecated as exceptions are defined in _error.py and are supposed to be accessed from 'psutil' namespace as in: - psutil.NoSuchProcess - psutil.AccessDenied - psutil.TimeoutExpired """ import warnings from psutil._error import * warnings.warn("psutil.error module is deprecated and scheduled for removal; " \ "use psutil namespace instead", category=DeprecationWarning, stacklevel=2) psutil-1.2.1/psutil/_error.py0000664000175000017500000000412212243463412020161 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 exception classes. Not supposed to be used / imported directly. Instead use psutil.NoSuchProcess, etc. """ class Error(Exception): """Base exception class. All other psutil exceptions inherit from this one. """ class NoSuchProcess(Error): """Exception raised when a process with a certain PID doesn't or no longer exists (zombie). """ def __init__(self, pid, name=None, msg=None): Error.__init__(self) self.pid = pid self.name = name self.msg = msg if msg is None: if name: details = "(pid=%s, name=%s)" % (self.pid, repr(self.name)) else: details = "(pid=%s)" % self.pid self.msg = "process no longer exists " + details def __str__(self): return self.msg class AccessDenied(Error): """Exception raised when permission to perform an action is denied.""" def __init__(self, pid=None, name=None, msg=None): Error.__init__(self) self.pid = pid self.name = name self.msg = msg if msg is None: if (pid is not None) and (name is not None): self.msg = "(pid=%s, name=%s)" % (pid, repr(name)) elif (pid is not None): self.msg = "(pid=%s)" % self.pid else: self.msg = "" def __str__(self): return self.msg class TimeoutExpired(Error): """Raised on Process.wait(timeout) if timeout expires and process is still alive. """ def __init__(self, pid=None, name=None): Error.__init__(self) self.pid = pid self.name = name if (pid is not None) and (name is not None): self.msg = "(pid=%s, name=%s)" % (pid, repr(name)) elif (pid is not None): self.msg = "(pid=%s)" % self.pid else: self.msg = "" def __str__(self): return self.msg psutil-1.2.1/psutil/_pslinux.py0000664000175000017500000011674412243743630020553 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 platform implementation.""" from __future__ import division import base64 import errno import os import re import socket import struct import sys import warnings import _psutil_linux import _psutil_posix from _psutil_linux import * # needed for RLIMIT_* constants from psutil import _psposix from psutil._common import * from psutil._compat import PY3, xrange, long, namedtuple, wraps from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired __extra__all__ = [ # 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", # other "phymem_buffers", "cached_phymem"] HAS_PRLIMIT = hasattr(_psutil_linux, "prlimit") # RLIMIT_* constants, not guaranteed to be present on all kernels if HAS_PRLIMIT: for name in dir(_psutil_linux): 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") # ioprio_* constants http://linux.die.net/man/2/ioprio_get IOPRIO_CLASS_NONE = 0 IOPRIO_CLASS_RT = 1 IOPRIO_CLASS_BE = 2 IOPRIO_CLASS_IDLE = 3 # taken from /fs/proc/array.c PROC_STATUSES = { "R": STATUS_RUNNING, "S": STATUS_SLEEPING, "D": STATUS_DISK_SLEEP, "T": STATUS_STOPPED, "t": STATUS_TRACING_STOP, "Z": STATUS_ZOMBIE, "X": STATUS_DEAD, "x": STATUS_DEAD, "K": STATUS_WAKE_KILL, "W": STATUS_WAKING } # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { "01": CONN_ESTABLISHED, "02": CONN_SYN_SENT, "03": CONN_SYN_RECV, "04": CONN_FIN_WAIT1, "05": CONN_FIN_WAIT2, "06": CONN_TIME_WAIT, "07": CONN_CLOSE, "08": CONN_CLOSE_WAIT, "09": CONN_LAST_ACK, "0A": CONN_LISTEN, "0B": CONN_CLOSING } def get_system_boot_time(): """Return the system boot time expressed in seconds since the epoch.""" f = open('/proc/stat', 'r') try: for line in f: if line.startswith('btime'): return float(line.strip().split()[1]) raise RuntimeError("line 'btime' not found") finally: f.close() def get_num_cpus(): """Return the number of CPUs on the system""" try: return os.sysconf("SC_NPROCESSORS_ONLN") except ValueError: # as a second fallback we try to parse /proc/cpuinfo num = 0 f = open('/proc/cpuinfo', 'r') try: lines = f.readlines() finally: f.close() for line in lines: if line.lower().startswith('processor'): num += 1 # unknown format (e.g. amrel/sparc architectures), see: # http://code.google.com/p/psutil/issues/detail?id=200 # try to parse /proc/stat as a last resort if num == 0: f = open('/proc/stat', 'r') try: lines = f.readlines() finally: f.close() search = re.compile('cpu\d') for line in lines: line = line.split(' ')[0] if search.match(line): num += 1 if num == 0: raise RuntimeError("couldn't determine platform's NUM_CPUS") return num # Since these constants get determined at import time we do not want to # crash immediately; instead we'll set them to None and most likely # we'll crash later as they're used for determining process CPU stats # and creation_time try: BOOT_TIME = get_system_boot_time() except Exception: BOOT_TIME = None warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) try: NUM_CPUS = get_num_cpus() except Exception: NUM_CPUS = None warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) try: TOTAL_PHYMEM = _psutil_linux.get_sysinfo()[0] except Exception: TOTAL_PHYMEM = None warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) # --- system memory nt_virtmem_info = namedtuple('vmem', ' '.join([ # all platforms 'total', 'available', 'percent', 'used', 'free', # linux specific 'active', 'inactive', 'buffers', 'cached'])) def virtual_memory(): total, free, buffers, shared, _, _ = _psutil_linux.get_sysinfo() cached = active = inactive = None f = open('/proc/meminfo', 'r') try: for line in f: if line.startswith('Cached:'): cached = int(line.split()[1]) * 1024 elif line.startswith('Active:'): active = int(line.split()[1]) * 1024 elif line.startswith('Inactive:'): inactive = int(line.split()[1]) * 1024 if cached is not None \ and active is not None \ and inactive is not None: break else: # we might get here when dealing with exotic Linux flavors, see: # http://code.google.com/p/psutil/issues/detail?id=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 finally: f.close() avail = free + buffers + cached used = total - free percent = usage_percent((total - avail), total, _round=1) return nt_virtmem_info(total, avail, percent, used, free, active, inactive, buffers, cached) def swap_memory(): _, _, _, _, total, free = _psutil_linux.get_sysinfo() used = total - free percent = usage_percent(used, total, _round=1) # get pgin/pgouts f = open("/proc/vmstat", "r") sin = sout = None try: for line in f: # values are expressed in 4 kilo bytes, we want bytes instead if line.startswith('pswpin'): sin = int(line.split(' ')[1]) * 4 * 1024 elif line.startswith('pswpout'): sout = int(line.split(' ')[1]) * 4 * 1024 if sin is not None and sout is not None: break else: # we might get here when dealing with exotic Linux flavors, see: # http://code.google.com/p/psutil/issues/detail?id=313 msg = "'sin' and 'sout' swap memory stats couldn't " \ "be determined and were set to 0" warnings.warn(msg, RuntimeWarning) sin = sout = 0 finally: f.close() return nt_swapmeminfo(total, used, free, percent, sin, sout) @deprecated('psutil.virtual_memory().cached') def cached_phymem(): return virtual_memory().cached @deprecated('psutil.virtual_memory().buffers') def phymem_buffers(): return virtual_memory().buffers # --- CPU @memoize def _get_cputimes_ntuple(): """ Return a (nt, rindex) tuple 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]]] """ f = open('/proc/stat', 'r') try: values = f.readline().split()[1:] finally: f.close() fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq'] rindex = 8 vlen = len(values) if vlen >= 8: # Linux >= 2.6.11 fields.append('steal') rindex += 1 if vlen >= 9: # Linux >= 2.6.24 fields.append('guest') rindex += 1 if vlen >= 10: # Linux >= 3.2.0 fields.append('guest_nice') rindex += 1 return (namedtuple('cputimes', ' '.join(fields)), rindex) def get_system_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. """ f = open('/proc/stat', 'r') try: values = f.readline().split() finally: f.close() nt, rindex = _get_cputimes_ntuple() fields = values[1:rindex] fields = [float(x) / CLOCK_TICKS for x in fields] return nt(*fields) def get_system_per_cpu_times(): """Return a list of namedtuple representing the CPU times for every CPU available on the system. """ nt, rindex = _get_cputimes_ntuple() cpus = [] f = open('/proc/stat', 'r') try: # get rid of the first line which refers to system wide CPU stats f.readline() for line in f: if line.startswith('cpu'): fields = line.split()[1:rindex] fields = [float(x) / CLOCK_TICKS for x in fields] entry = nt(*fields) cpus.append(entry) return cpus finally: f.close() # --- disks def disk_partitions(all=False): """Return mounted disk partitions as a list of nameduples""" phydevs = [] f = open("/proc/filesystems", "r") try: for line in f: if not line.startswith("nodev"): phydevs.append(line.strip()) finally: f.close() retlist = [] partitions = _psutil_linux.get_disk_partitions() for partition in partitions: device, mountpoint, fstype, opts = partition if device == 'none': device = '' if not all: if device == '' or fstype not in phydevs: continue ntuple = nt_partition(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist get_disk_usage = _psposix.get_disk_usage # --- other system functions def get_system_users(): """Return currently connected users as a list of namedtuples.""" retlist = [] rawlist = _psutil_linux.get_system_users() for item in rawlist: user, tty, hostname, tstamp, user_process = item # 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': hostname = 'localhost' nt = nt_user(user, tty or None, hostname, tstamp) retlist.append(nt) return retlist # --- processes def get_pid_list(): """Returns a list of PIDs currently running on the system.""" pids = [int(x) for x in os.listdir('/proc') if x.isdigit()] return pids def pid_exists(pid): """Check For the existence of a unix pid.""" return _psposix.pid_exists(pid) # --- network def net_io_counters(): """Return network I/O statistics for every network interface installed on the system as a dict of raw tuples. """ f = open("/proc/net/dev", "r") try: lines = f.readlines() finally: f.close() retdict = {} for line in lines[2:]: colon = line.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 # --- 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 = [] f = open("/proc/partitions", "r") try: lines = f.readlines()[2:] finally: f.close() 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: # http://code.google.com/p/psutil/issues/detail?id=338 partitions.append(name) # retdict = {} f = open("/proc/diskstats", "r") try: lines = f.readlines() finally: f.close() for line in lines: # http://www.mjmwired.net/kernel/Documentation/iostats.txt _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \ line.split()[:11] if name in partitions: rbytes = int(rbytes) * SECTOR_SIZE wbytes = int(wbytes) * SECTOR_SIZE reads = int(reads) writes = int(writes) rtime = int(rtime) wtime = int(wtime) retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime) return retdict # --- decorators def wrap_exceptions(fun): """Decorator which translates bare OSError and IOError exceptions into NoSuchProcess and AccessDenied. """ @wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except EnvironmentError: # ENOENT (no such file or directory) gets raised on open(). # ESRCH (no such process) can get raised on read() if # process is gone in meantime. err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise return wrapper class Process(object): """Linux process implementation.""" __slots__ = ["pid", "_process_name"] def __init__(self, pid): self.pid = pid self._process_name = None @wrap_exceptions def get_process_name(self): f = open("/proc/%s/stat" % self.pid) try: name = f.read().split(' ')[1].replace('(', '').replace(')', '') finally: f.close() # XXX - gets changed later and probably needs refactoring return name def get_process_exe(self): try: exe = os.readlink("/proc/%s/exe" % self.pid) except (OSError, IOError): err = sys.exc_info()[1] if err.errno == errno.ENOENT: # no such file error; might be raised also if the # path actually exists for system processes with # low pids (about 0-20) if os.path.lexists("/proc/%s/exe" % self.pid): return "" else: # ok, it is a process which has gone away raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise # readlink() might return paths containing null bytes causing # problems when used with other fs-related functions (os.*, # open(), ...) exe = exe.replace('\x00', '') # Certain names have ' (deleted)' appended. Usually this is # bogus as the file actually exists. Either way that's not # important as we don't want to discriminate executables which # have been deleted. if exe.endswith(" (deleted)") and not os.path.exists(exe): exe = exe[:-10] return exe @wrap_exceptions def get_process_cmdline(self): f = open("/proc/%s/cmdline" % self.pid) try: # return the args as a list return [x for x in f.read().split('\x00') if x] finally: f.close() @wrap_exceptions def get_process_terminal(self): tmap = _psposix._get_terminal_map() f = open("/proc/%s/stat" % self.pid) try: tty_nr = int(f.read().split(' ')[6]) finally: f.close() try: return tmap[tty_nr] except KeyError: return None if os.path.exists('/proc/%s/io' % os.getpid()): @wrap_exceptions def get_process_io_counters(self): fname = "/proc/%s/io" % self.pid f = open(fname) try: rcount = wcount = rbytes = wbytes = None for line in f: if rcount is None and line.startswith("syscr"): rcount = int(line.split()[1]) elif wcount is None and line.startswith("syscw"): wcount = int(line.split()[1]) elif rbytes is None and line.startswith("read_bytes"): rbytes = int(line.split()[1]) elif wbytes is None and line.startswith("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 nt_io(rcount, wcount, rbytes, wbytes) finally: f.close() else: def get_process_io_counters(self): raise NotImplementedError("couldn't find /proc/%s/io (kernel " "too old?)" % self.pid) @wrap_exceptions def get_cpu_times(self): f = open("/proc/%s/stat" % self.pid) try: st = f.read().strip() finally: f.close() # ignore the first two values ("pid (exe)") st = st[st.find(')') + 2:] values = st.split(' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS return nt_cputimes(utime, stime) @wrap_exceptions def process_wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except TimeoutExpired: raise TimeoutExpired(self.pid, self._process_name) @wrap_exceptions def get_process_create_time(self): f = open("/proc/%s/stat" % self.pid) try: st = f.read().strip() finally: f.close() # ignore the first two values ("pid (exe)") st = st[st.rfind(')') + 2:] values = st.split(' ') # According to documentation, starttime is in field 21 and the # unit is jiffies (clock ticks). # We first divide it for clock ticks and then add uptime returning # seconds since the epoch, in UTC. starttime = (float(values[19]) / CLOCK_TICKS) + BOOT_TIME return starttime @wrap_exceptions def get_memory_info(self): f = open("/proc/%s/statm" % self.pid) try: vms, rss = f.readline().split()[:2] return nt_meminfo(int(rss) * PAGESIZE, int(vms) * PAGESIZE) finally: f.close() _nt_ext_mem = namedtuple('meminfo', 'rss vms shared text lib data dirty') @wrap_exceptions def get_ext_memory_info(self): # ============================================================ # | FIELD | DESCRIPTION | AKA | TOP | # ============================================================ # | rss | resident set size | | RES | # | vms | total program size | size | VIRT | # | shared | shared pages (from shared mappings) | | SHR | # | text | text ('code') | trs | CODE | # | lib | library (unused in Linux 2.6) | lrs | | # | data | data + stack | drs | DATA | # | dirty | dirty pages (unused in Linux 2.6) | dt | | # ============================================================ f = open("/proc/%s/statm" % self.pid) try: vms, rss, shared, text, lib, data, dirty = \ [int(x) * PAGESIZE for x in f.readline().split()[:7]] finally: f.close() return self._nt_ext_mem(rss, vms, shared, text, lib, data, dirty) _mmap_base_fields = ['path', 'rss', 'size', 'pss', 'shared_clean', 'shared_dirty', 'private_clean', 'private_dirty', 'referenced', 'anonymous', 'swap', ] nt_mmap_grouped = namedtuple('mmap', ' '.join(_mmap_base_fields)) nt_mmap_ext = namedtuple('mmap', 'addr perms ' + ' '.join(_mmap_base_fields)) def get_memory_maps(self): """Return process's mapped memory regions as a list of nameduples. Fields are explained in 'man proc'; here is an updated (Apr 2012) version: http://goo.gl/fmebo """ f = None try: f = open("/proc/%s/smaps" % self.pid) first_line = f.readline() current_block = [first_line] def get_blocks(): data = {} for line in f: fields = line.split(None, 5) if 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 interpret" " line %r" % line) yield (current_block.pop(), data) if first_line: # smaps file can be empty for header, data in get_blocks(): hfields = header.split(None, 5) try: addr, perms, offset, dev, inode, path = hfields except ValueError: addr, perms, offset, dev, inode, path = hfields + [''] if not path: path = '[anon]' else: path = path.strip() yield (addr, perms, path, data['Rss:'], data.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)) f.close() except EnvironmentError: # XXX - Can't use wrap_exceptions decorator as we're # returning a generator; this probably needs some # refactoring in order to avoid this code duplication. if f is not None: f.close() err = sys.exc_info()[1] if err.errno in (errno.ENOENT, errno.ESRCH): raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise except: if f is not None: f.close() raise f.close() if not os.path.exists('/proc/%s/smaps' % os.getpid()): def get_memory_maps(self, ext): 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 def get_process_cwd(self): # readlink() might return paths containing null bytes causing # problems when used with other fs-related functions (os.*, # open(), ...) path = os.readlink("/proc/%s/cwd" % self.pid) return path.replace('\x00', '') @wrap_exceptions def get_num_ctx_switches(self): vol = unvol = None f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith("voluntary_ctxt_switches"): vol = int(line.split()[1]) elif line.startswith("nonvoluntary_ctxt_switches"): unvol = int(line.split()[1]) if vol is not None and unvol is not None: return nt_ctxsw(vol, unvol) raise 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) finally: f.close() @wrap_exceptions def get_process_num_threads(self): f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith("Threads:"): return int(line.split()[1]) raise NotImplementedError("line not found") finally: f.close() @wrap_exceptions def get_process_threads(self): thread_ids = os.listdir("/proc/%s/task" % self.pid) thread_ids.sort() retlist = [] hit_enoent = False for thread_id in thread_ids: try: f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id)) except EnvironmentError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: # no such file or directory; it means thread # disappeared on us hit_enoent = True continue raise try: st = f.read().strip() finally: f.close() # ignore the first two values ("pid (exe)") st = st[st.find(')') + 2:] values = st.split(' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS ntuple = nt_thread(int(thread_id), utime, stime) retlist.append(ntuple) if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) return retlist @wrap_exceptions def get_process_nice(self): #f = open('/proc/%s/stat' % self.pid, 'r') # try: # data = f.read() # return int(data.split()[18]) # finally: # f.close() # Use C implementation return _psutil_posix.getpriority(self.pid) @wrap_exceptions def set_process_nice(self, value): return _psutil_posix.setpriority(self.pid, value) @wrap_exceptions def get_process_cpu_affinity(self): from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x] bitmask = _psutil_linux.get_process_cpu_affinity(self.pid) return from_bitmask(bitmask) @wrap_exceptions def set_process_cpu_affinity(self, value): def to_bitmask(l): if not l: raise ValueError("invalid argument %r" % l) out = 0 for b in l: if not isinstance(b, (int, long)) or b < 0: raise ValueError("invalid argument %r" % b) out |= 2 ** b return out bitmask = to_bitmask(value) try: _psutil_linux.set_process_cpu_affinity(self.pid, bitmask) except OSError: err = sys.exc_info()[1] if err.errno == errno.EINVAL: allcpus = tuple(range(len(get_system_per_cpu_times()))) for cpu in value: 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(_psutil_linux, "ioprio_get"): @wrap_exceptions def get_process_ionice(self): ioclass, value = _psutil_linux.ioprio_get(self.pid) return nt_ionice(ioclass, value) @wrap_exceptions def set_process_ionice(self, ioclass, value): if ioclass in (IOPRIO_CLASS_NONE, None): if value: raise ValueError("can't specify value with IOPRIO_CLASS_NONE") ioclass = IOPRIO_CLASS_NONE value = 0 if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): if value is None: value = 4 elif ioclass == IOPRIO_CLASS_IDLE: if value: raise ValueError("can't specify value with IOPRIO_CLASS_IDLE") value = 0 else: value = 0 if not 0 <= value <= 8: raise ValueError( "value argument range expected is between 0 and 8") return _psutil_linux.ioprio_set(self.pid, ioclass, value) if HAS_PRLIMIT: @wrap_exceptions def process_rlimit(self, resource, limits=None): if limits is None: # get return _psutil_linux.prlimit(self.pid, resource) else: # set if len(limits) != 2: raise ValueError( "second argument must be a (soft, hard) tuple") soft, hard = limits _psutil_linux.prlimit(self.pid, resource, soft, hard) @wrap_exceptions def get_process_status(self): f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith("State:"): letter = line.split()[1] # XXX is '?' legit? (we're not supposed to return # it anyway) return PROC_STATUSES.get(letter, '?') finally: f.close() @wrap_exceptions def get_open_files(self): retlist = [] files = os.listdir("/proc/%s/fd" % self.pid) hit_enoent = False for fd in files: file = "/proc/%s/fd/%s" % (self.pid, fd) if os.path.islink(file): try: file = os.readlink(file) except OSError: # ENOENT == file which is gone in the meantime err = sys.exc_info()[1] if err.errno == errno.ENOENT: hit_enoent = True continue raise else: # If file is not an absolute path there's no way # to tell whether it's a regular file or not, # so we skip it. A regular file is always supposed # to be absolutized though. if file.startswith('/') and isfile_strict(file): ntuple = nt_openfile(file, int(fd)) retlist.append(ntuple) if hit_enoent: # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) return retlist @wrap_exceptions def get_connections(self, kind='inet'): """Return connections opened by process as a list of namedtuples. The kind parameter filters for connections that fit the following criteria: Kind Value Number of connections using inet IPv4 and IPv6 inet4 IPv4 inet6 IPv6 tcp TCP tcp4 TCP over IPv4 tcp6 TCP over IPv6 udp UDP udp4 UDP over IPv4 udp6 UDP over IPv6 all the sum of all the possible families and protocols """ # Note: in case of UNIX sockets we're only able to determine the # local bound path while the remote endpoint is not retrievable: # http://goo.gl/R3GHM inodes = {} # os.listdir() is gonna raise a lot of access denied # exceptions in case of unprivileged user; that's fine: # lsof does the same so it's unlikely that we can to better. for fd in os.listdir("/proc/%s/fd" % self.pid): try: inode = os.readlink("/proc/%s/fd/%s" % (self.pid, fd)) except OSError: continue if inode.startswith('socket:['): # the process is using a socket inode = inode[8:][:-1] inodes[inode] = fd if not inodes: # no connections for this process return [] def process(file, family, type_): retlist = [] try: f = open(file, 'r') except IOError: # IPv6 not supported on this platform err = sys.exc_info()[1] if err.errno == errno.ENOENT and file.endswith('6'): return [] else: raise try: f.readline() # skip the first line for line in f: # IPv4 / IPv6 if family in (socket.AF_INET, socket.AF_INET6): _, laddr, raddr, status, _, _, _, _, _, inode = \ line.split()[:10] if inode in inodes: laddr = self._decode_address(laddr, family) raddr = self._decode_address(raddr, family) if type_ == socket.SOCK_STREAM: status = TCP_STATUSES[status] else: status = CONN_NONE fd = int(inodes[inode]) conn = nt_connection(fd, family, type_, laddr, raddr, status) retlist.append(conn) elif family == socket.AF_UNIX: tokens = line.split() _, _, _, _, type_, _, inode = tokens[0:7] if inode in inodes: if len(tokens) == 8: path = tokens[-1] else: path = "" fd = int(inodes[inode]) type_ = int(type_) conn = nt_connection(fd, family, type_, path, None, CONN_NONE) retlist.append(conn) else: raise ValueError(family) return retlist finally: f.close() tcp4 = ("tcp", socket.AF_INET, socket.SOCK_STREAM) tcp6 = ("tcp6", socket.AF_INET6, socket.SOCK_STREAM) udp4 = ("udp", socket.AF_INET, socket.SOCK_DGRAM) udp6 = ("udp6", socket.AF_INET6, socket.SOCK_DGRAM) unix = ("unix", socket.AF_UNIX, None) tmap = { "all": (tcp4, tcp6, udp4, udp6, unix), "tcp": (tcp4, tcp6), "tcp4": (tcp4,), "tcp6": (tcp6,), "udp": (udp4, udp6), "udp4": (udp4,), "udp6": (udp6,), "unix": (unix,), "inet": (tcp4, tcp6, udp4, udp6), "inet4": (tcp4, udp4), "inet6": (tcp6, udp6), } if kind not in tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in tmap]))) ret = [] for f, family, type_ in tmap[kind]: ret += process("/proc/net/%s" % f, family, type_) # raise NSP if the process disappeared on us os.stat('/proc/%s' % self.pid) return ret @wrap_exceptions def get_num_fds(self): return len(os.listdir("/proc/%s/fd" % self.pid)) @wrap_exceptions def get_process_ppid(self): f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith("PPid:"): # PPid: nnnn return int(line.split()[1]) raise NotImplementedError("line not found") finally: f.close() @wrap_exceptions def get_process_uids(self): f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith('Uid:'): _, real, effective, saved, fs = line.split() return nt_uids(int(real), int(effective), int(saved)) raise NotImplementedError("line not found") finally: f.close() @wrap_exceptions def get_process_gids(self): f = open("/proc/%s/status" % self.pid) try: for line in f: if line.startswith('Gid:'): _, real, effective, saved, fs = line.split() return nt_gids(int(real), int(effective), int(saved)) raise NotImplementedError("line not found") finally: f.close() @staticmethod def _decode_address(addr, family): """Accept an "ip:port" address as displayed in /proc/net/* and convert it into a human readable form, like: "0500000A:0016" -> ("10.0.0.5", 22) "0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521) The IP address portion is a little or big endian four-byte hexadecimal number; that is, the least significant byte is listed first, so we need to reverse the order of the bytes to convert it to an IP address. The port is represented as a two-byte hexadecimal number. Reference: http://linuxdevcenter.com/pub/a/linux/2000/11/16/LinuxAdmin.html """ ip, port = addr.split(':') port = int(port, 16) if PY3: ip = ip.encode('ascii') # this usually refers to a local socket in listen mode with # no end-points connected if not port: return () if family == socket.AF_INET: # see: http://code.google.com/p/psutil/issues/detail?id=201 if sys.byteorder == 'little': ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1]) else: ip = socket.inet_ntop(family, base64.b16decode(ip)) else: # IPv6 # old version - let's keep it, just in case... # ip = ip.decode('hex') # return socket.inet_ntop(socket.AF_INET6, # ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4))) ip = base64.b16decode(ip) # see: http://code.google.com/p/psutil/issues/detail?id=201 if sys.byteorder == 'little': ip = socket.inet_ntop( socket.AF_INET6, struct.pack('>4I', *struct.unpack('<4I', ip))) else: ip = socket.inet_ntop( socket.AF_INET6, struct.pack('<4I', *struct.unpack('<4I', ip))) return (ip, port) psutil-1.2.1/psutil/_psutil_osx.c0000664000175000017500000015311212243206601021032 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" /* * 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; } /* * Return a Python list of all the PIDs running on the system. */ static PyObject* get_pid_list(PyObject* self, PyObject* args) { kinfo_proc *proclist = NULL; kinfo_proc *orig_address = NULL; size_t num_processes; size_t idx; PyObject *pid = NULL; PyObject *retlist = PyList_New(0); if (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++) { pid = Py_BuildValue("i", proclist->kp_proc.p_pid); if (!pid) goto error; if (PyList_Append(retlist, pid)) goto error; Py_DECREF(pid); proclist++; } free(orig_address); } return retlist; error: Py_XDECREF(pid); Py_DECREF(retlist); if (orig_address != NULL) free(orig_address); return NULL; } /* * Return process name from kinfo_proc as a Python string. */ static PyObject* get_process_name(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (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* get_process_cwd(PyObject* self, PyObject* args) { long pid; struct proc_vnodepathinfo pathinfo; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo, sizeof(pathinfo))) { return NULL; } return Py_BuildValue("s", pathinfo.pvi_cdir.vip_path); } /* * Return path of the process executable. */ static PyObject* get_process_exe(PyObject* self, PyObject* args) { long pid; char buf[PATH_MAX]; int ret; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } ret = proc_pidpath(pid, &buf, sizeof(buf)); if (ret == 0) { if (! psutil_pid_exists(pid)) { return NoSuchProcess(); } else { return AccessDenied(); } } return Py_BuildValue("s", buf); } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject* get_process_cmdline(PyObject* self, PyObject* args) { long pid; PyObject* arglist = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } // get the commandline, defined in arch/osx/process_info.c arglist = psutil_get_arg_list(pid); return arglist; } /* * Return process parent pid from kinfo_proc as a Python integer. */ static PyObject* get_process_ppid(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (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* get_process_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* get_process_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* get_process_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* get_process_memory_maps(PyObject* self, PyObject* args) { char buf[PATH_MAX]; char addr_str[34]; char perms[8]; int pagesize = getpagesize(); long pid; kern_return_t err = KERN_SUCCESS; mach_port_t task = 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) { if (! psutil_pid_exists(pid)) { NoSuchProcess(); } else { // pid exists, so return AccessDenied error since task_for_pid() // failed AccessDenied(); } goto error; } while (1) { py_tuple = NULL; struct vm_region_submap_info_64 info; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; err = vm_region_recurse_64(task, &address, &size, &depth, (vm_region_info_64_t)&info, &count); if (err == KERN_INVALID_ADDRESS) { break; } if (info.is_submap) { depth++; } else { // Free/Reset the char[]s to avoid weird paths memset(buf, 0, sizeof(buf)); memset(addr_str, 0, sizeof(addr_str)); memset(perms, 0, sizeof(perms)); sprintf(addr_str, "%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 a Python integer indicating the number of CPUs on the system. */ static PyObject* get_num_cpus(PyObject* self, PyObject* args) { int mib[2]; int ncpu; size_t len; mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof(ncpu); if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("i", ncpu); } #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) /* * Return a Python tuple (user_time, kernel_time) */ static PyObject* get_process_cpu_times(PyObject* self, PyObject* args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { return NULL; } return Py_BuildValue("(dd)", (float)pti.pti_total_user / 1000000000.0, (float)pti.pti_total_system / 1000000000.0); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject* get_process_create_time(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("d", TV2DOUBLE(kp.kp_proc.p_starttime)); } /* * Return extended memory info about a process. */ static PyObject* get_process_memory_info(PyObject* self, PyObject* args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { return NULL; } // Note: determining other memory stats on OSX is a mess: // http://www.opensource.apple.com/source/top/top-67/libtop.c?txt // I just give up... //struct proc_regioninfo pri; //psutil_proc_pidinfo(pid, PROC_PIDREGIONINFO, &pri, sizeof(pri)) return Py_BuildValue("(KKkk)", pti.pti_resident_size, // resident memory size (rss) pti.pti_virtual_size, // virtual memory size (vms) pti.pti_faults, // number of page faults (pages) pti.pti_pageins // number of actual pageins (pages) ); } /* * Return number of threads used by process as a Python integer. */ static PyObject* get_process_num_threads(PyObject* self, PyObject* args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { return NULL; } return Py_BuildValue("k", pti.pti_threadnum); } /* * Return the number of context switches performed by process. */ static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args) { long pid; struct proc_taskinfo pti; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) { return NULL; } // unvoluntary value seems not to be available; // pti.pti_csw probably refers to the sum of the two (getrusage() // numbers seems to confirm this theory). return Py_BuildValue("ki", pti.pti_csw, 0); } /* * Return system virtual memory stats */ static PyObject* get_virtual_mem(PyObject* self, PyObject* args) { int mib[2]; uint64_t total; size_t len = sizeof(total); vm_statistics_data_t vm; int pagesize = getpagesize(); // physical mem mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; if (sysctl(mib, 2, &total, &len, NULL, 0)) { if (errno != 0) PyErr_SetFromErrno(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* get_swap_mem(PyObject* self, PyObject* args) { int mib[2]; size_t size; struct xsw_usage totals; vm_statistics_data_t vmstat; int pagesize = getpagesize(); mib[0] = CTL_VM; mib[1] = VM_SWAPUSAGE; size = sizeof(totals); if (sysctl(mib, 2, &totals, &size, NULL, 0) == -1) { if (errno != 0) PyErr_SetFromErrno(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* get_system_cpu_times(PyObject* self, PyObject* args) { mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; kern_return_t error; host_cpu_load_info_data_t r_load; 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* get_system_per_cpu_times(PyObject* self, PyObject* args) { natural_t cpu_count; processor_info_array_t info_array; mach_msg_type_number_t info_count; kern_return_t error; processor_cpu_load_info_data_t* cpu_load_info = NULL; 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* get_system_boot_time(PyObject* self, PyObject* args) { /* fetch sysctl "kern.boottime" */ static int request[2] = { CTL_KERN, KERN_BOOTTIME }; struct timeval result; size_t result_len = sizeof result; time_t boot_time = 0; if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) { PyErr_SetFromErrno(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* get_disk_partitions(PyObject* self, PyObject* args) { int num; int i; long len; uint64_t flags; char opts[400]; struct statfs *fs = NULL; PyObject* py_retlist = PyList_New(0); PyObject* py_tuple = NULL; 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* get_process_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* get_process_threads(PyObject* self, PyObject* args) { long pid; int err, j, ret; kern_return_t kr; unsigned int info_count = TASK_BASIC_INFO_COUNT; mach_port_t task = 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* retList = PyList_New(0); PyObject* pyTuple = NULL; if (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) { if (! psutil_pid_exists(pid)) { NoSuchProcess(); } else { AccessDenied(); } goto error; } info_count = TASK_BASIC_INFO_COUNT; err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count); if (err != KERN_SUCCESS) { // errcode 4 is "invalid argument" (access denied) if (err == 4) { AccessDenied(); } else { // otherwise throw a runtime error with appropriate error code PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed"); } goto error; } err = task_threads(task, &thread_list, &thread_count); if (err != KERN_SUCCESS) { PyErr_Format(PyExc_RuntimeError, "task_threads() failed"); goto error; } for (j = 0; j < thread_count; j++) { pyTuple = NULL; thread_info_count = THREAD_INFO_MAX; kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo_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; pyTuple = Py_BuildValue("Iff", j+1, (float)basic_info_th->user_time.microseconds / 1000000.0, (float)basic_info_th->system_time.microseconds / 1000000.0 ); if (!pyTuple) goto error; if (PyList_Append(retList, pyTuple)) goto error; Py_DECREF(pyTuple); } ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); if (ret != KERN_SUCCESS) { PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); } mach_port_deallocate(mach_task_self(), task); return retList; error: if (task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), task); Py_XDECREF(pyTuple); Py_DECREF(retList); if (thread_list != NULL) { ret = vm_deallocate(task, (vm_address_t)thread_list, thread_count * sizeof(int)); if (ret != KERN_SUCCESS) { PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2); } } return NULL; } /* * Return process open files as a Python tuple. * References: * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd * - /usr/include/sys/proc_info.h */ static PyObject* get_process_open_files(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer = NULL; struct proc_fdinfo *fdp_pointer; struct vnode_fdinfowithpath vi; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; if (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++) { tuple = NULL; fdp_pointer = &fds_pointer[i]; if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDVNODEPATHINFO, &vi, sizeof(vi)); // --- errors checking if (nb <= 0) { if ((errno == ENOENT) || (errno == EBADF)) { // no such file or directory or bad file descriptor; // let's assume the file has been closed or removed continue; } // may be be ignored later if errno != 0 PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); goto error; } if (nb < sizeof(vi)) { PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); goto error; } // --- /errors checking // --- construct python list tuple = Py_BuildValue("(si)", vi.pvip.vip_path, (int)fdp_pointer->proc_fd); if (!tuple) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(tuple); // --- /construct python list } } free(fds_pointer); return retList; error: Py_XDECREF(tuple); Py_DECREF(retList); if (fds_pointer != NULL) { free(fds_pointer); } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else if (! psutil_pid_exists(pid)) { return NoSuchProcess(); } else { // exception has already been set earlier return NULL; } } // 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* get_process_connections(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int iterations; int i; int nb; struct proc_fdinfo *fds_pointer = NULL; struct proc_fdinfo *fdp_pointer; struct socket_fdinfo si; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; PyObject *laddr = NULL; PyObject *raddr = NULL; PyObject *af_filter = NULL; PyObject *type_filter = NULL; if (retList == NULL) return NULL; if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { goto error; } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } if (pid == 0) { return retList; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { goto error; } fds_pointer = malloc(pidinfo_result); 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++) { tuple = NULL; laddr = NULL; raddr = NULL; errno = 0; fdp_pointer = &fds_pointer[i]; if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) { nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); // --- errors checking if (nb <= 0) { if (errno == EBADF) { // let's assume socket has been closed continue; } if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); } else { PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed"); } goto error; } if (nb < sizeof(si)) { PyErr_Format(PyExc_RuntimeError, "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)"); goto error; } // --- /errors checking // int fd, family, type, lport, rport, state; char lip[200], rip[200]; int inseq; PyObject* _family; PyObject* _type; fd = (int)fdp_pointer->proc_fd; family = si.psi.soi_family; type = si.psi.soi_type; // apply filters _family = PyLong_FromLong((long)family); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); if (inseq == 0) { continue; } _type = PyLong_FromLong((long)type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_type); if (inseq == 0) { continue; } if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } if ((family == AF_INET) || (family == AF_INET6)) { if (family == AF_INET) { inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4, lip, sizeof(lip)); inet_ntop(AF_INET, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4, rip, sizeof(rip)); } else { inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6, lip, sizeof(lip)); inet_ntop(AF_INET6, &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6, rip, sizeof(rip)); } // check for inet_ntop failures if (errno != 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; } lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport); if (type == SOCK_STREAM) { state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state; } else { state = PSUTIL_CONN_NONE; } laddr = Py_BuildValue("(si)", lip, lport); if (!laddr) goto error; if (rport != 0) { raddr = Py_BuildValue("(si)", rip, rport); } else { raddr = Py_BuildValue("()"); } if (!raddr) goto error; // construct the python list tuple = Py_BuildValue("(iiiNNi)", fd, family, type, laddr, raddr, state); if (!tuple) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(tuple); } else if (family == AF_UNIX) { // construct the python list tuple = Py_BuildValue("(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 (!tuple) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(tuple); } } } free(fds_pointer); return retList; error: Py_XDECREF(tuple); Py_XDECREF(laddr); Py_XDECREF(raddr); Py_DECREF(retList); if (fds_pointer != NULL) { free(fds_pointer); } if (errno != 0) { return PyErr_SetFromErrno(PyExc_OSError); } else if (! 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* get_process_num_fds(PyObject* self, PyObject* args) { long pid; int pidinfo_result; int num; struct proc_fdinfo *fds_pointer; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); if (pidinfo_result <= 0) { return PyErr_SetFromErrno(PyExc_OSError); } fds_pointer = malloc(pidinfo_result); 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* get_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* get_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* get_system_users(PyObject* self, PyObject* args) { struct utmpx *utx; PyObject *ret_list = PyList_New(0); PyObject *tuple = NULL; if (ret_list == NULL) return NULL; while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; tuple = Py_BuildValue("(sssf)", utx->ut_user, // username utx->ut_line, // tty utx->ut_host, // hostname (float)utx->ut_tv.tv_sec // start time ); if (!tuple) { endutxent(); goto error; } if (PyList_Append(ret_list, tuple)) { endutxent(); goto error; } Py_DECREF(tuple); } endutxent(); return ret_list; error: Py_XDECREF(tuple); Py_DECREF(ret_list); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions {"get_process_name", get_process_name, METH_VARARGS, "Return process name"}, {"get_process_cmdline", get_process_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"get_process_exe", get_process_exe, METH_VARARGS, "Return path of the process executable"}, {"get_process_cwd", get_process_cwd, METH_VARARGS, "Return process current working directory."}, {"get_process_ppid", get_process_ppid, METH_VARARGS, "Return process ppid as an integer"}, {"get_process_uids", get_process_uids, METH_VARARGS, "Return process real user id as an integer"}, {"get_process_gids", get_process_gids, METH_VARARGS, "Return process real group id as an integer"}, {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"get_process_create_time", get_process_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"get_process_memory_info", get_process_memory_info, METH_VARARGS, "Return memory information about a process"}, {"get_process_num_threads", get_process_num_threads, METH_VARARGS, "Return number of threads used by process"}, {"get_process_status", get_process_status, METH_VARARGS, "Return process status as an integer"}, {"get_process_threads", get_process_threads, METH_VARARGS, "Return process threads as a list of tuples"}, {"get_process_open_files", get_process_open_files, METH_VARARGS, "Return files opened by process as a list of tuples"}, {"get_process_num_fds", get_process_num_fds, METH_VARARGS, "Return the number of fds opened by process."}, {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"get_process_connections", get_process_connections, METH_VARARGS, "Get process TCP and UDP connections as a list of tuples"}, {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS, "Return process tty number as an integer"}, {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, // --- system-related functions {"get_pid_list", get_pid_list, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"get_num_cpus", get_num_cpus, METH_VARARGS, "Return number of CPUs on the system"}, {"get_virtual_mem", get_virtual_mem, METH_VARARGS, "Return system virtual memory stats"}, {"get_swap_mem", get_swap_mem, METH_VARARGS, "Return stats about swap memory, in bytes"}, {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, {"get_system_boot_time", get_system_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"get_disk_partitions", get_disk_partitions, METH_VARARGS, "Return a list of tuples including device, mount point and " "fs type for all partitions mounted on the system."}, {"get_net_io_counters", get_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS, "Return dict of tuples of disks I/O information."}, {"get_system_users", get_system_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_osx_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_osx", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_osx_traverse, psutil_osx_clear, NULL }; #define INITERROR return NULL PyObject * PyInit__psutil_osx(void) #else #define INITERROR return void init_psutil_osx(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods); #endif // process status constants, defined in: // http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149 PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SZOMB", SZOMB); // 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-1.2.1/psutil/_psutil_sunos.h0000664000175000017500000000252412244714321021401 0ustar giampaologiampaolo00000000000000/* * $Id$ * * 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 module functions for _psutil_sunos extension */ #include // processes static PyObject* query_process_thread(PyObject* self, PyObject* args); static PyObject* get_process_basic_info(PyObject* self, PyObject* args); static PyObject* get_process_name_and_args(PyObject* self, PyObject* args); static PyObject* get_process_cpu_times(PyObject* self, PyObject* args); static PyObject* get_process_cred(PyObject* self, PyObject* args); static PyObject* get_process_memory_maps(PyObject* self, PyObject* args); static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args); static PyObject* get_process_connections(PyObject* self, PyObject* args); // system static PyObject* get_swap_mem(PyObject* self, PyObject* args); static PyObject* get_system_users(PyObject* self, PyObject* args); static PyObject* get_disk_partitions(PyObject* self, PyObject* args); static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args); static PyObject* get_disk_io_counters(PyObject* self, PyObject* args); static PyObject* get_net_io_counters(PyObject* self, PyObject* args); static PyObject* get_boot_time(PyObject* self, PyObject* args); psutil-1.2.1/psutil/_psosx.py0000664000175000017500000002546112243460724020220 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 platform implementation.""" import errno import os import sys import warnings import _psutil_osx import _psutil_posix from psutil import _psposix from psutil._common import * from psutil._compat import namedtuple, wraps from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired __extra__all__ = [] # --- constants # Since these constants get determined at import time we do not want to # crash immediately; instead we'll set them to None and most likely # we'll crash later as they're used for determining process CPU stats # and creation_time try: NUM_CPUS = _psutil_osx.get_num_cpus() except Exception: NUM_CPUS = None warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) try: BOOT_TIME = _psutil_osx.get_system_boot_time() except Exception: BOOT_TIME = None warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) try: TOTAL_PHYMEM = _psutil_osx.get_virtual_mem()[0] except Exception: TOTAL_PHYMEM = None warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) PAGESIZE = os.sysconf("SC_PAGE_SIZE") # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h TCP_STATUSES = { _psutil_osx.TCPS_ESTABLISHED: CONN_ESTABLISHED, _psutil_osx.TCPS_SYN_SENT: CONN_SYN_SENT, _psutil_osx.TCPS_SYN_RECEIVED: CONN_SYN_RECV, _psutil_osx.TCPS_FIN_WAIT_1: CONN_FIN_WAIT1, _psutil_osx.TCPS_FIN_WAIT_2: CONN_FIN_WAIT2, _psutil_osx.TCPS_TIME_WAIT: CONN_TIME_WAIT, _psutil_osx.TCPS_CLOSED: CONN_CLOSE, _psutil_osx.TCPS_CLOSE_WAIT: CONN_CLOSE_WAIT, _psutil_osx.TCPS_LAST_ACK: CONN_LAST_ACK, _psutil_osx.TCPS_LISTEN: CONN_LISTEN, _psutil_osx.TCPS_CLOSING: CONN_CLOSING, _psutil_osx.PSUTIL_CONN_NONE: CONN_NONE, } PROC_STATUSES = { _psutil_osx.SIDL: STATUS_IDLE, _psutil_osx.SRUN: STATUS_RUNNING, _psutil_osx.SSLEEP: STATUS_SLEEPING, _psutil_osx.SSTOP: STATUS_STOPPED, _psutil_osx.SZOMB: STATUS_ZOMBIE, } # --- functions get_system_boot_time = _psutil_osx.get_system_boot_time # ...so that we can test it from test_memory_leask.py get_num_cpus = _psutil_osx.get_num_cpus() nt_virtmem_info = namedtuple('vmem', ' '.join([ # all platforms 'total', 'available', 'percent', 'used', 'free', # OSX specific 'active', 'inactive', 'wired'])) def virtual_memory(): """System virtual memory as a namedtuple.""" total, active, inactive, wired, free = _psutil_osx.get_virtual_mem() avail = inactive + free used = active + inactive + wired percent = usage_percent((total - avail), total, _round=1) return nt_virtmem_info(total, avail, percent, used, free, active, inactive, wired) def swap_memory(): """Swap system memory as a (total, used, free, sin, sout) tuple.""" total, used, free, sin, sout = _psutil_osx.get_swap_mem() percent = usage_percent(used, total, _round=1) return nt_swapmeminfo(total, used, free, percent, sin, sout) _cputimes_ntuple = namedtuple('cputimes', 'user nice system idle') def get_system_cpu_times(): """Return system CPU times as a namedtuple.""" user, nice, system, idle = _psutil_osx.get_system_cpu_times() return _cputimes_ntuple(user, nice, system, idle) def get_system_per_cpu_times(): """Return system CPU times as a named tuple""" ret = [] for cpu_t in _psutil_osx.get_system_per_cpu_times(): user, nice, system, idle = cpu_t item = _cputimes_ntuple(user, nice, system, idle) ret.append(item) return ret def disk_partitions(all=False): retlist = [] partitions = _psutil_osx.get_disk_partitions() for partition in partitions: device, mountpoint, fstype, opts = partition if device == 'none': device = '' if not all: if not os.path.isabs(device) or not os.path.exists(device): continue ntuple = nt_partition(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def get_system_users(): retlist = [] rawlist = _psutil_osx.get_system_users() for item in rawlist: user, tty, hostname, tstamp = item if tty == '~': continue # reboot or shutdown if not tstamp: continue nt = nt_user(user, tty or None, hostname or None, tstamp) retlist.append(nt) return retlist get_pid_list = _psutil_osx.get_pid_list pid_exists = _psposix.pid_exists get_disk_usage = _psposix.get_disk_usage net_io_counters = _psutil_osx.get_net_io_counters disk_io_counters = _psutil_osx.get_disk_io_counters def wrap_exceptions(fun): """Decorator which translates bare OSError exceptions into NoSuchProcess and AccessDenied. """ @wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError: err = sys.exc_info()[1] if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_process_name"] def __init__(self, pid): self.pid = pid self._process_name = None @wrap_exceptions def get_process_name(self): """Return process name as a string of limited len (15).""" return _psutil_osx.get_process_name(self.pid) @wrap_exceptions def get_process_exe(self): return _psutil_osx.get_process_exe(self.pid) @wrap_exceptions def get_process_cmdline(self): """Return process cmdline as a list of arguments.""" if not pid_exists(self.pid): raise NoSuchProcess(self.pid, self._process_name) return _psutil_osx.get_process_cmdline(self.pid) @wrap_exceptions def get_process_ppid(self): """Return process parent pid.""" return _psutil_osx.get_process_ppid(self.pid) @wrap_exceptions def get_process_cwd(self): return _psutil_osx.get_process_cwd(self.pid) @wrap_exceptions def get_process_uids(self): real, effective, saved = _psutil_osx.get_process_uids(self.pid) return nt_uids(real, effective, saved) @wrap_exceptions def get_process_gids(self): real, effective, saved = _psutil_osx.get_process_gids(self.pid) return nt_gids(real, effective, saved) @wrap_exceptions def get_process_terminal(self): tty_nr = _psutil_osx.get_process_tty_nr(self.pid) tmap = _psposix._get_terminal_map() try: return tmap[tty_nr] except KeyError: return None @wrap_exceptions def get_memory_info(self): """Return a tuple with the process' RSS and VMS size.""" rss, vms = _psutil_osx.get_process_memory_info(self.pid)[:2] return nt_meminfo(rss, vms) _nt_ext_mem = namedtuple('meminfo', 'rss vms pfaults pageins') @wrap_exceptions def get_ext_memory_info(self): """Return a tuple with the process' RSS and VMS size.""" rss, vms, pfaults, pageins = _psutil_osx.get_process_memory_info(self.pid) return self._nt_ext_mem(rss, vms, pfaults * PAGESIZE, pageins * PAGESIZE) @wrap_exceptions def get_cpu_times(self): user, system = _psutil_osx.get_process_cpu_times(self.pid) return nt_cputimes(user, system) @wrap_exceptions def get_process_create_time(self): """Return the start time of the process as a number of seconds since the epoch.""" return _psutil_osx.get_process_create_time(self.pid) @wrap_exceptions def get_num_ctx_switches(self): return nt_ctxsw(*_psutil_osx.get_process_num_ctx_switches(self.pid)) @wrap_exceptions def get_process_num_threads(self): """Return the number of threads belonging to the process.""" return _psutil_osx.get_process_num_threads(self.pid) @wrap_exceptions def get_open_files(self): """Return files opened by process.""" if self.pid == 0: return [] files = [] rawlist = _psutil_osx.get_process_open_files(self.pid) for path, fd in rawlist: if isfile_strict(path): ntuple = nt_openfile(path, fd) files.append(ntuple) return files @wrap_exceptions def get_connections(self, kind='inet'): """Return etwork connections opened by a process as a list of namedtuples. """ if kind not in conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = _psutil_osx.get_process_connections(self.pid, families, types) ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] nt = nt_connection(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret @wrap_exceptions def get_num_fds(self): if self.pid == 0: return 0 return _psutil_osx.get_process_num_fds(self.pid) @wrap_exceptions def process_wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except TimeoutExpired: raise TimeoutExpired(self.pid, self._process_name) @wrap_exceptions def get_process_nice(self): return _psutil_posix.getpriority(self.pid) @wrap_exceptions def set_process_nice(self, value): return _psutil_posix.setpriority(self.pid, value) @wrap_exceptions def get_process_status(self): code = _psutil_osx.get_process_status(self.pid) # XXX is '?' legit? (we're not supposed to return it anyway) return PROC_STATUSES.get(code, '?') @wrap_exceptions def get_process_threads(self): """Return the number of threads belonging to the process.""" rawlist = _psutil_osx.get_process_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = nt_thread(thread_id, utime, stime) retlist.append(ntuple) return retlist nt_mmap_grouped = namedtuple( 'mmap', 'path rss private swapped dirtied ref_count shadow_depth') nt_mmap_ext = namedtuple( 'mmap', 'addr perms path rss private swapped dirtied ref_count shadow_depth') @wrap_exceptions def get_memory_maps(self): return _psutil_osx.get_process_memory_maps(self.pid) psutil-1.2.1/psutil/_psutil_common.h0000664000175000017500000000040212243206601021507 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* NoSuchProcess(void); PyObject* AccessDenied(void); psutil-1.2.1/psutil/__init__.py0000664000175000017500000016377512244724306020457 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 is a module providing convenience functions for managing processes and gather system information in a portable way by using Python. """ from __future__ import division __version__ = "1.2.1" version_info = tuple([int(num) for num in __version__.split('.')]) __all__ = [ # exceptions "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired", # constants "NUM_CPUS", "TOTAL_PHYMEM", "BOOT_TIME", "version_info", "__version__", "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", "STATUS_WAKING", "STATUS_LOCKED", "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", # classes "Process", "Popen", # functions "pid_exists", "get_pid_list", "process_iter", "wait_procs", # proc "virtual_memory", "swap_memory", # memory "cpu_times", "cpu_percent", "cpu_times_percent", # cpu "net_io_counters", # network "disk_io_counters", "disk_partitions", "disk_usage", # disk "get_users", "get_boot_time", # others ] import sys import os import time import signal import warnings import errno import subprocess try: import pwd except ImportError: pwd = None from psutil._error import Error, NoSuchProcess, AccessDenied, TimeoutExpired from psutil._common import cached_property from psutil._compat import property, callable, defaultdict, namedtuple from psutil._compat import (wraps as _wraps, PY3 as _PY3) from psutil._common import (deprecated as _deprecated, nt_disk_iostat as _nt_disk_iostat, nt_net_iostat as _nt_net_iostat, nt_sysmeminfo as _nt_sysmeminfo) from psutil._common import (STATUS_RUNNING, STATUS_IDLE, STATUS_SLEEPING, STATUS_DISK_SLEEP, STATUS_STOPPED, STATUS_TRACING_STOP, STATUS_ZOMBIE, STATUS_DEAD, STATUS_WAKING, STATUS_LOCKED) from psutil._common import (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) if sys.platform.startswith("linux"): import psutil._pslinux as _psplatform from psutil._pslinux import (phymem_buffers, cached_phymem) from psutil._pslinux import (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE) # Linux >= 2.6.36 if _psplatform.HAS_PRLIMIT: from psutil._pslinux import (RLIM_INFINITY, RLIMIT_AS, RLIMIT_CORE, RLIMIT_CPU, RLIMIT_DATA, RLIMIT_FSIZE, RLIMIT_LOCKS, RLIMIT_MEMLOCK, RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_RSS, RLIMIT_STACK) # Kinda ugly but considerably faster than using hasattr() and # setattr() against the module object (we are at import time # and we demand speed). try: RLIMIT_MSGQUEUE = _psplatform.RLIMIT_MSGQUEUE except AttributeError: pass try: RLIMIT_NICE = _psplatform.RLIMIT_NICE except AttributeError: pass try: RLIMIT_RTPRIO = _psplatform.RLIMIT_RTPRIO except AttributeError: pass try: RLIMIT_RTTIME = _psplatform.RLIMIT_RTTIME except AttributeError: pass try: RLIMIT_SIGPENDING = _psplatform.RLIMIT_SIGPENDING except AttributeError: pass elif sys.platform.startswith("win32"): import psutil._psmswindows as _psplatform from psutil._psmswindows import (ABOVE_NORMAL_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS, CONN_DELETE_TCB) elif sys.platform.startswith("darwin"): import psutil._psosx as _psplatform elif sys.platform.startswith("freebsd"): import psutil._psbsd as _psplatform elif sys.platform.startswith("sunos"): import psutil._pssunos as _psplatform from psutil._pssunos import (CONN_IDLE, CONN_BOUND) else: raise NotImplementedError('platform %s is not supported' % sys.platform) __all__.extend(_psplatform.__extra__all__) NUM_CPUS = _psplatform.NUM_CPUS BOOT_TIME = _psplatform.BOOT_TIME TOTAL_PHYMEM = _psplatform.TOTAL_PHYMEM def _assert_pid_not_reused(fun): """Decorator which raises NoSuchProcess in case a process is no longer running or its PID has been reused. """ @_wraps(fun) def wrapper(self, *args, **kwargs): if not self.is_running(): raise NoSuchProcess(self.pid, self._platform_impl._process_name) return fun(self, *args, **kwargs) return wrapper class Process(object): """Represents an OS process.""" def __init__(self, pid=None): """Create a new Process object for the given pid. If pid is omitted current process pid is assumed. Raises 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 are: - parent - get_children() - set_nice() - set_rlimit() - 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 """ if pid is None: pid = os.getpid() else: if not _PY3: if 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._gone = False self._ppid = None # platform-specific modules define an _psplatform.Process # implementation class self._platform_impl = _psplatform.Process(pid) self._last_sys_cpu_times = None self._last_proc_cpu_times = None # cache creation time for later use in is_running() method try: self.create_time except AccessDenied: pass except NoSuchProcess: raise NoSuchProcess(pid, None, 'no process found with pid %s' % pid) def __str__(self): try: pid = self.pid name = repr(self.name) except NoSuchProcess: details = "(pid=%s (terminated))" % self.pid except AccessDenied: details = "(pid=%s)" % (self.pid) else: details = "(pid=%s, name=%s)" % (pid, name) return "%s.%s%s" % (self.__class__.__module__, self.__class__.__name__, details) def __repr__(self): return "<%s at %s>" % (self.__str__(), id(self)) # --- utility methods def as_dict(self, attrs=[], ad_value=None): """Utility method returning process information as a hashable dictionary. If 'attrs' is specified it must be a list of strings reflecting available Process class's attribute names (e.g. ['get_cpu_times', 'name']) else all public (read only) attributes are assumed. 'ad_value' is the value which gets assigned to a dict key in case AccessDenied exception is raised when retrieving that particular process information. """ excluded_names = set(['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 'is_running', 'as_dict', 'parent', 'get_children', 'nice', 'get_rlimit']) retdict = dict() for name in set(attrs or dir(self)): if name.startswith('_'): continue if name.startswith('set_'): continue if name in excluded_names: continue try: attr = getattr(self, name) if callable(attr): if name == 'get_cpu_percent': ret = attr(interval=0) else: ret = attr() else: ret = attr except AccessDenied: ret = ad_value except NotImplementedError: # in case of not implemented functionality (may happen # on old or exotic systems) we want to crash only if # the user explicitly asked for that particular attr if attrs: raise continue if name.startswith('get'): if name[3] == '_': name = name[4:] elif name == 'getcwd': name = 'cwd' retdict[name] = ret return retdict @property @_assert_pid_not_reused 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: try: parent = Process(ppid) if parent.create_time <= self.create_time: return parent # ...else ppid has been reused by another process except NoSuchProcess: pass # --- actual API @property def pid(self): """The process pid.""" return self._pid @property def ppid(self): """The process parent pid.""" # 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://code.google.com/p/psutil/issues/detail?id=321 # http://stackoverflow.com/questions/356722/ # XXX should we check creation time here rather than in # Process.parent? if os.name == 'posix': return self._platform_impl.get_process_ppid() else: if self._ppid is None: self._ppid = self._platform_impl.get_process_ppid() return self._ppid @cached_property def name(self): """The process name.""" name = self._platform_impl.get_process_name() if os.name == '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 # XXX - perhaps needs refactoring self._platform_impl._process_name = name return name @cached_property def exe(self): """The process executable path. May also be an empty string.""" def guess_it(fallback): # try to guess exe from cmdline[0] in absence of a native # exe representation cmdline = self.cmdline if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'): exe = cmdline[0] # the possible exe # 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 try: exe = self._platform_impl.get_process_exe() except AccessDenied: err = sys.exc_info()[1] return guess_it(fallback=err) else: if not exe: # underlying implementation can legitimately return an # empty string; if that's the case we don't want to # raise AD while guessing from the cmdline try: exe = guess_it(fallback=exe) except AccessDenied: pass return exe @property def cmdline(self): """The command line process has been called with.""" return self._platform_impl.get_process_cmdline() @property def status(self): """The process current status as a STATUS_* constant.""" return self._platform_impl.get_process_status() if os.name == 'posix': @property def uids(self): """Return a named tuple denoting the process real, effective, and saved user ids. """ return self._platform_impl.get_process_uids() @property def gids(self): """Return a named tuple denoting the process real, effective, and saved group ids. """ return self._platform_impl.get_process_gids() @property def terminal(self): """The terminal associated with this process, if any, else None. """ return self._platform_impl.get_process_terminal() @property def username(self): """The name of the user that owns the process. On UNIX this is calculated by using *real* process uid. """ if os.name == 'posix': if pwd is None: # might happen if python was installed from sources raise ImportError( "requires pwd module shipped with standard python") return pwd.getpwuid(self.uids.real).pw_name else: return self._platform_impl.get_process_username() @cached_property def create_time(self): """The process creation time as a floating point number expressed in seconds since the epoch, in UTC. """ return self._platform_impl.get_process_create_time() def getcwd(self): """Return a string representing the process current working directory. """ return self._platform_impl.get_process_cwd() # Linux, BSD and Windows only if hasattr(_psplatform.Process, "get_process_io_counters"): def get_io_counters(self): """Return process I/O statistics as a namedtuple including the number of read/write calls performed and the amount of bytes read and written by the process. """ return self._platform_impl.get_process_io_counters() def get_nice(self): """Get process niceness (priority).""" return self._platform_impl.get_process_nice() @_assert_pid_not_reused def set_nice(self, value): """Set process niceness (priority) pre-emptively checking whether PID has been reused.""" return self._platform_impl.set_process_nice(value) # Linux and Windows >= Vista only if hasattr(_psplatform.Process, "get_process_ionice"): def get_ionice(self): """Return process I/O niceness (priority). On Linux this is a (ioclass, value) namedtuple. On Windows it's an integer which can be equal to 2 (normal), 1 (low) or 0 (very low). Available on Linux and Windows > Vista only. """ return self._platform_impl.get_process_ionice() def set_ionice(self, ioclass, value=None): """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. """ return self._platform_impl.set_process_ionice(ioclass, value) # Linux only if hasattr(_psplatform.Process, "process_rlimit"): def get_rlimit(self, resource): """Get process resource limits as a (soft, hard) tuple. 'resource' is one of the RLIMIT_* constants. See "man prlimit" for further info. """ # if pid is 0 prlimit() applies to the calling process and # we don't want that if self.pid == 0: raise ValueError("can't use this method for PID 0 process") return self._platform_impl.process_rlimit(resource) @_assert_pid_not_reused def set_rlimit(self, resource, limits): """Set process resource limits pre-emptively checking whether PID has been reused. 'resource' is one of the RLIMIT_* constants. 'limits' is supposed to be a (soft, hard) tuple. See "man prlimit" for further info. """ # if pid is 0 prlimit() applies to the calling process and # we don't want that if self.pid == 0: raise ValueError("can't use this method for PID 0 process") self._platform_impl.process_rlimit(resource, limits) # Windows and Linux only if hasattr(_psplatform.Process, "get_process_cpu_affinity"): def get_cpu_affinity(self): """Get process current CPU affinity.""" return self._platform_impl.get_process_cpu_affinity() def set_cpu_affinity(self, cpus): """Set process current CPU affinity. 'cpus' is a list of CPUs for which you want to set the affinity (e.g. [0, 1]). """ return self._platform_impl.set_process_cpu_affinity(cpus) if os.name == 'nt': def get_num_handles(self): """Return the number of handles opened by this process (Windows only). """ return self._platform_impl.get_num_handles() if os.name == 'posix': def get_num_fds(self): """Return the number of file descriptors opened by this process (POSIX only). """ return self._platform_impl.get_num_fds() def get_num_ctx_switches(self): """Return the number voluntary and involuntary context switches performed by this process. """ return self._platform_impl.get_num_ctx_switches() def get_num_threads(self): """Return the number of threads used by this process.""" return self._platform_impl.get_process_num_threads() def get_threads(self): """Return threads opened by process as a list of namedtuples including thread id and thread CPU times (user/system). """ return self._platform_impl.get_process_threads() @_assert_pid_not_reused def get_children(self, recursive=False): """Return the children of this process as a list of Process objects 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) >>> p.get_children() B, C, D >>> p.get_children(recursive=True) B, X, Y, C, D Note that in the example above if process X disappears process Y won't be returned either as the reference to process A is lost. """ if hasattr(_psplatform, 'get_ppid_map'): # Windows only: obtain a {pid:ppid, ...} dict for all running # processes in one shot (faster). ppid_map = _psplatform.get_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: 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: pass else: # construct a dict where 'values' are all the processes # having 'key' as their parent table = defaultdict(list) if ppid_map is None: for p in process_iter(): try: table[p.ppid].append(p) except NoSuchProcess: pass else: for pid, ppid in ppid_map.items(): try: p = Process(pid) table[ppid].append(p) except NoSuchProcess: 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: pass else: if intime: ret.append(child) if child.pid not in checkpids: checkpids.append(child.pid) return ret def get_cpu_percent(self, interval=0.1): """Return a float representing the current process CPU utilization as a percentage. When interval is > 0.0 compares process times to system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares process times to system CPU times elapsed since last call, returning immediately (non-blocking). In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls. Examples: >>> p = psutil.Process(os.getpid()) >>> # blocking >>> p.get_cpu_percent(interval=1) 2.0 >>> # non-blocking (percentage since last call) >>> p.get_cpu_percent(interval=0) 2.9 >>> """ blocking = interval is not None and interval > 0.0 if blocking: st1 = sum(cpu_times()) pt1 = self._platform_impl.get_cpu_times() time.sleep(interval) st2 = sum(cpu_times()) pt2 = self._platform_impl.get_cpu_times() else: st1 = self._last_sys_cpu_times pt1 = self._last_proc_cpu_times st2 = sum(cpu_times()) pt2 = self._platform_impl.get_cpu_times() if st1 is None or pt1 is None: self._last_sys_cpu_times = st2 self._last_proc_cpu_times = pt2 return 0.0 delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system) delta_time = st2 - st1 # reset values for next call in case of interval == None self._last_sys_cpu_times = st2 self._last_proc_cpu_times = pt2 try: # the utilization split between all CPUs overall_percent = (delta_proc / delta_time) * 100 except ZeroDivisionError: # interval was too low return 0.0 # the utilization of a single CPU single_cpu_percent = overall_percent * NUM_CPUS # On POSIX a percentage > 100 is legitimate: # http://stackoverflow.com/questions/1032357/comprehending-top-cpu-usage # On windows we use this ugly hack in order to avoid float # precision issues. if os.name != 'posix': if single_cpu_percent > 100.0: return 100.0 return round(single_cpu_percent, 1) def get_cpu_times(self): """Return a tuple whose values are process CPU user and system times. The same as os.times() but per-process. """ return self._platform_impl.get_cpu_times() def get_memory_info(self): """Return a tuple representing RSS (Resident Set Size) and VMS (Virtual Memory Size) in bytes. On UNIX RSS and VMS are the same values shown by ps. On Windows RSS and VMS refer to "Mem Usage" and "VM Size" columns of taskmgr.exe. """ return self._platform_impl.get_memory_info() def get_ext_memory_info(self): """Return a namedtuple with variable fields depending on the platform representing extended memory information about the process. All numbers are expressed in bytes. """ return self._platform_impl.get_ext_memory_info() def get_memory_percent(self): """Compare physical system memory to process resident memory (RSS) and calculate process memory utilization as a percentage. """ rss = self._platform_impl.get_memory_info()[0] try: return (rss / float(TOTAL_PHYMEM)) * 100 except ZeroDivisionError: return 0.0 def get_memory_maps(self, grouped=True): """Return process's mapped memory regions as a list of nameduples whose fields are variable depending on the platform. If 'grouped' is True the mapped regions with the same 'path' are grouped together and the different memory fields are summed. If 'grouped' is False every mapped region is shown as a single entity and the namedtuple will also include the mapped region's address space ('addr') and permission set ('perms'). """ it = self._platform_impl.get_memory_maps() if grouped: d = {} for tupl in it: path = tupl[2] nums = tupl[3:] try: d[path] = map(lambda x, y: x + y, d[path], nums) except KeyError: d[path] = nums nt = self._platform_impl.nt_mmap_grouped return [nt(path, *d[path]) for path in d] else: nt = self._platform_impl.nt_mmap_ext return [nt(*x) for x in it] def get_open_files(self): """Return files opened by process as a list of namedtuples including absolute file name and file descriptor number. """ return self._platform_impl.get_open_files() def get_connections(self, kind='inet'): """Return connections opened by process as a list of namedtuples. The kind parameter filters for connections that fit the following criteria: Kind Value Connections using inet IPv4 and IPv6 inet4 IPv4 inet6 IPv6 tcp TCP tcp4 TCP over IPv4 tcp6 TCP over IPv6 udp UDP udp4 UDP over IPv4 udp6 UDP over IPv6 unix UNIX socket (both UDP and TCP protocols) all the sum of all the possible families and protocols """ return self._platform_impl.get_connections(kind) def is_running(self): """Return whether this process is running. It also checks if PID has been reused by another process in which case returns 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. # pid + creation time, on the other hand, is supposed to # identify a process univocally. return self.create_time == \ self._platform_impl.get_process_create_time() except NoSuchProcess: self._gone = True return False @_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 os.name == 'posix': try: os.kill(self.pid, sig) except OSError: err = sys.exc_info()[1] name = self._platform_impl._process_name if err.errno == errno.ESRCH: self._gone = True raise NoSuchProcess(self.pid, name) if err.errno == errno.EPERM: raise AccessDenied(self.pid, name) raise else: if sig == signal.SIGTERM: self._platform_impl.kill_process() else: raise ValueError("only SIGTERM is supported on Windows") @_assert_pid_not_reused def suspend(self): """Suspend process execution with SIGSTOP pre-emptively checking whether PID has been reused. On Windows it suspends all process threads. """ if hasattr(self._platform_impl, "suspend_process"): # windows self._platform_impl.suspend_process() else: # posix self.send_signal(signal.SIGSTOP) @_assert_pid_not_reused def resume(self): """Resume process execution with SIGCONT pre-emptively checking whether PID has been reused. On Windows it resumes all process threads. """ if hasattr(self._platform_impl, "resume_process"): # windows self._platform_impl.resume_process() else: # posix self.send_signal(signal.SIGCONT) def terminate(self): """Terminate the process with SIGTERM pre-emptively checking whether PID has been reused. On Windows this is an alias for kill(). """ self.send_signal(signal.SIGTERM) @_assert_pid_not_reused def kill(self): """Kill the current process with SIGKILL pre-emptively checking whether PID has been reused.""" if os.name == 'posix': self.send_signal(signal.SIGKILL) else: self._platform_impl.kill_process() def wait(self, timeout=None): """Wait for process to terminate and, if process is a children of the current one also return its exit code, else None. If the process is already terminated immediately return None instead of raising NoSuchProcess. If timeout (in seconds) is specified and process is still alive after the timeout expired raise TimeoutExpired. """ if timeout is not None and not timeout >= 0: raise ValueError("timeout must be a positive integer") return self._platform_impl.process_wait(timeout) # --- deprecated API @property def nice(self): """Get or set process niceness (priority). Deprecated, use get_nice() instead. """ msg = "this property is deprecated; use Process.get_nice() method instead" warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return self.get_nice() @nice.setter def nice(self, value): # invoked on "p.nice = num"; change process niceness # deprecated in favor of set_nice() msg = "this property is deprecated; use Process.set_nice() method instead" warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return self.set_nice(value) class Popen(Process): """A more convenient interface to stdlib subprocess module. It starts a sub process and deals with it exactly as when using subprocess.Popen class but in addition also provides all the property and methods of psutil.Process class in a single interface: >>> import psutil >>> from subprocess import PIPE >>> p = psutil.Popen(["/usr/bin/python", "-c", "print 'hi'"], stdout=PIPE) >>> p.name 'python' >>> p.uids user(real=1000, effective=1000, saved=1000) >>> p.username 'giampaolo' >>> p.communicate() ('hi\n', None) >>> p.terminate() >>> p.wait(timeout=2) 0 >>> For method names common to both classes such as kill(), terminate() and wait(), psutil.Process implementation takes precedence. For a complete documentation refers to: http://docs.python.org/library/subprocess.html """ def __init__(self, *args, **kwargs): # Here we avoid to call the original Process constructor # because if the process spawned by subprocess.Popen # terminates too quickly we'll get NoSuchProcess, see: # https://code.google.com/p/psutil/issues/detail?id=193 self.__subproc = subprocess.Popen(*args, **kwargs) self._pid = self.__subproc.pid self._gone = False self._ppid = None self._platform_impl = _psplatform.Process(self._pid) self._last_sys_cpu_times = None self._last_proc_cpu_times = None try: self.create_time except AccessDenied: pass except NoSuchProcess: raise NoSuchProcess(self._pid, None, "no process found with pid %s" % self._pid) def __dir__(self): return list(set(dir(Popen) + dir(subprocess.Popen))) def __getattribute__(self, name): try: return object.__getattribute__(self, name) except AttributeError: try: return object.__getattribute__(self.__subproc, name) except AttributeError: raise AttributeError("%s instance has no attribute '%s'" % (self.__class__.__name__, name)) # ===================================================================== # --- system processes related functions # ===================================================================== def get_pid_list(): """Return a list of current running PIDs.""" return _psplatform.get_pid_list() def pid_exists(pid): """Return True if given PID exists in the current process list. This is faster than doing "pid in psutil.get_pid_list()" and should be preferred. """ return _psplatform.pid_exists(pid) _pmap = {} def process_iter(): """Return a generator yielding a Process class instance for all running processes on the local machine. Every new Process instance is only created once and then cached into an internal table which is updated every time this is used. 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(get_pid_list()) b = set(_pmap.keys()) new_pids = a - b gone_pids = b - a for pid in gone_pids: remove(pid) for pid, proc in sorted(list(_pmap.items()) + list(dict.fromkeys(new_pids).items())): try: if proc is None: # new process yield add(pid) else: # use is_running() to check whether PID has been reused by # another process in which case yield a new Process instance if proc.is_running(): yield proc else: yield add(pid) except NoSuchProcess: remove(pid) except AccessDenied: # Process creation time can't be determined hence there's # no way to tell whether the pid of the cached process # has been reused. Just return the cached version. yield proc def wait_procs(procs, timeout, 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 'retcode' attribute indicating process exit status (may be None). 'callback' is a callable 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. 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: >>> def on_terminate(proc): ... print("process {} terminated".format(proc)) ... >>> for p in procs: ... p.terminate() ... >>> gone, still_alive = wait_procs(procs, 3, callback=on_terminate) >>> for p in still_alive: ... p.kill() """ def assert_gone(proc, timeout): try: retcode = proc.wait(timeout=timeout) except TimeoutExpired: pass else: if retcode is not None or not proc.is_running(): proc.retcode = retcode gone.add(proc) if callback is not None: callback(proc) timer = getattr(time, 'monotonic', time.time) gone = set() alive = set(procs) if callback is not None and not callable(callback): raise TypeError("callback %r is not a callable" % callable) deadline = timer() + timeout while alive: if 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. try: max_timeout = 1.0 / (len(alive) - len(gone)) except ZeroDivisionError: max_timeout = 1.0 # one alive remaining timeout = min((deadline - timer()), max_timeout) if timeout <= 0: break assert_gone(proc, 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: assert_gone(proc, 0) alive = alive - gone return (list(gone), list(alive)) # ===================================================================== # --- CPU related functions # ===================================================================== def cpu_times(percpu=False): """Return system-wide CPU times as a namedtuple object. Every CPU time represents the time CPU has spent in the given mode. The attributes availability varies depending on the platform. Here follows a list of all available attributes: - user - system - idle - nice (UNIX) - iowait (Linux) - irq (Linux, FreeBSD) - softirq (Linux) - steal (Linux >= 2.6.11) - guest (Linux >= 2.6.24) - guest_nice (Linux >= 3.2.0) When percpu is True return a list of nameduples for each CPU. First element of the list refers to first CPU, second element to second CPU and so on. The order of the list is consistent across calls. """ if not percpu: return _psplatform.get_system_cpu_times() else: return _psplatform.get_system_per_cpu_times() _last_cpu_times = cpu_times() _last_per_cpu_times = cpu_times(percpu=True) def cpu_percent(interval=0.1, percpu=False): """Return a float representing the current system-wide CPU utilization as a percentage. When interval is > 0.0 compares system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares system CPU times elapsed since last call or module import, returning immediately. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls. When percpu is True returns a list of floats representing the utilization as a percentage for each CPU. First element of the list refers to first CPU, second element to second CPU and so on. The order of the list is consistent across calls. 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=0) 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 _last_cpu_times = cpu_times() return calculate(t1, _last_cpu_times) # per-cpu usage else: ret = [] if blocking: tot1 = cpu_times(percpu=True) time.sleep(interval) else: tot1 = _last_per_cpu_times _last_per_cpu_times = cpu_times(percpu=True) for t1, t2 in zip(tot1, _last_per_cpu_times): ret.append(calculate(t1, t2)) return ret # 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 _ptime_cpu_perc_nt = None def cpu_times_percent(interval=0.1, 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 WINDOWS = os.name == 'nt' def calculate(t1, t2): global _ptime_cpu_perc_nt 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) if WINDOWS: # XXX # Work around: # https://code.google.com/p/psutil/issues/detail?id=392 # 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 on # Windows where 'system' CPU time can be smaller # compared to the previous call, resulting in corrupted # percentages (< 0 or > 100). # 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 elif field_perc < 0.0: field_perc = 0.0 nums.append(field_perc) if _ptime_cpu_perc_nt is None: _ptime_cpu_perc_nt = namedtuple('cpupercent', ' '.join(t1._fields)) return _ptime_cpu_perc_nt(*nums) # system-wide usage if not percpu: if blocking: t1 = cpu_times() time.sleep(interval) else: t1 = _last_cpu_times_2 _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 _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. """ return _psplatform.virtual_memory() def swap_memory(): """Return system swap memory statistics as a namedtuple including the following attributes: - total: total swap memory in bytes - used: used swap memory in bytes - free: free swap memory in bytes - percent: the percentage usage - sin: no. of bytes the system has swapped in from disk (cumulative) - sout: no. of bytes the system has swapped out from disk (cumulative) 'sin' and 'sout' on Windows are meaningless and always set to 0. """ return _psplatform.swap_memory() # ===================================================================== # --- disks/paritions related functions # ===================================================================== def disk_usage(path): """Return disk usage statistics about the given path as a namedtuple including total, used and free space expressed in bytes plus the percentage usage. """ return _psplatform.get_disk_usage(path) def disk_partitions(all=False): """Return mounted partitions as a list of namedtuples including device, mount point, filesystem type and mount options (a raw string separated by commas which may vary depending on the platform). If "all" parameter is False return physical devices only and ignore all others. """ return _psplatform.disk_partitions(all) def disk_io_counters(perdisk=False): """Return system disk I/O statistics as a namedtuple including the following attributes: - read_count: number of reads - write_count: number of writes - read_bytes: number of bytes read - write_bytes: number of bytes written - read_time: time spent reading from disk (in milliseconds) - write_time: time spent writing to disk (in milliseconds) If perdisk is True return the same information for every physical disk installed on the system as a dictionary with partition names as the keys and the namedutuple described above as the values. 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] = _nt_disk_iostat(*fields) return rawdict else: return _nt_disk_iostat(*[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 attributes: - bytes_sent: number of bytes sent - bytes_recv: number of bytes received - packets_sent: number of packets sent - packets_recv: number of packets received - errin: total number of errors while receiving - errout: total number of errors while sending - dropin: total number of incoming packets which were dropped - dropout: total number of outgoing packets which were dropped (always 0 on OSX and BSD) If pernic is True return the same information for every network interface installed on the system as a dictionary with network interface names as the keys and the namedtuple described above as the values. """ rawdict = _psplatform.net_io_counters() if not rawdict: raise RuntimeError("couldn't find any network interface") if pernic: for nic, fields in rawdict.items(): rawdict[nic] = _nt_net_iostat(*fields) return rawdict else: return _nt_net_iostat(*[sum(x) for x in zip(*rawdict.values())]) # ===================================================================== # --- other system related functions # ===================================================================== def get_boot_time(): """Return the system boot time expressed in seconds since the epoch. This is also available as psutil.BOOT_TIME. """ return _psplatform.get_system_boot_time() def get_users(): """Return users currently connected on the system as a list of namedtuples including the following attributes. - user: the name of the user - terminal: the tty or pseudo-tty associated with the user, if any. - host: the host name associated with the entry, if any. - started: the creation time as a floating point number expressed in seconds since the epoch. """ return _psplatform.get_system_users() # ===================================================================== # --- deprecated functions # ===================================================================== @_deprecated() def get_process_list(): """Return a list of Process class instances for all running processes on the local machine (deprecated). """ return list(process_iter()) @_deprecated() def phymem_usage(): """Return the amount of total, used and free physical memory on the system in bytes plus the percentage usage. Deprecated by psutil.virtual_memory(). """ mem = virtual_memory() return _nt_sysmeminfo(mem.total, mem.used, mem.free, mem.percent) @_deprecated("psutil.swap_memory()") def virtmem_usage(): return swap_memory() @_deprecated("psutil.phymem_usage().free") def avail_phymem(): return phymem_usage().free @_deprecated("psutil.phymem_usage().used") def used_phymem(): return phymem_usage().used @_deprecated("psutil.virtmem_usage().total") def total_virtmem(): return virtmem_usage().total @_deprecated("psutil.virtmem_usage().used") def used_virtmem(): return virtmem_usage().used @_deprecated("psutil.virtmem_usage().free") def avail_virtmem(): return virtmem_usage().free @_deprecated("psutil.net_io_counters()") def network_io_counters(pernic=False): return net_io_counters(pernic) def test(): """List info of all currently running processes emulating ps aux output. """ import datetime from psutil._compat import print_ today_day = datetime.date.today() templ = "%-10s %5s %4s %4s %7s %7s %-13s %5s %7s %s" attrs = ['pid', 'get_cpu_percent', 'get_memory_percent', 'name', 'get_cpu_times', 'create_time', 'get_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 sorted(process_iter(), key=lambda p: p.pid): try: pinfo = p.as_dict(attrs, ad_value='') except NoSuchProcess: pass else: if pinfo['create_time']: ctime = datetime.datetime.fromtimestamp(pinfo['create_time']) if ctime.date() == today_day: ctime = ctime.strftime("%H:%M") else: ctime = ctime.strftime("%b%d") 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 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 '?')) del property, cached_property, division if sys.version_info < (3, 0): del num if __name__ == "__main__": test() psutil-1.2.1/psutil/_psutil_common.c0000664000175000017500000000155012243206601021507 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-1.2.1/psutil/_common.py0000664000175000017500000001321212243462277020330 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. """Common objects shared by all _ps* modules.""" from __future__ import division import errno import os import socket import stat import sys import warnings from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM from psutil._compat import namedtuple, wraps # --- 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" # BSD STATUS_LOCKED = "locked" # BSD STATUS_WAITING = "waiting" # BSD 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" # --- 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(f): """A simple memoize decorator for functions.""" cache = {} def memf(*x): if x not in cache: cache[x] = f(*x) return cache[x] return memf class cached_property(object): """A memoize decorator for class properties.""" enabled = True def __init__(self, func): self.func = func def __get__(self, instance, type): ret = self.func(instance) if self.enabled: instance.__dict__[self.func.__name__] = ret return ret # http://goo.gl/jYLvf def deprecated(replacement=None): """A decorator which can be used to mark functions as deprecated.""" def outer(fun): msg = "psutil.%s is deprecated" % fun.__name__ if replacement is not None: msg += "; use %s instead" % replacement if fun.__doc__ is None: fun.__doc__ = msg @wraps(fun) def inner(*args, **kwargs): warnings.warn(msg, category=DeprecationWarning, stacklevel=2) return fun(*args, **kwargs) return inner return outer def isfile_strict(path): """Same as os.path.isfile() but does not swallow EACCES / EPERM exceptions, see: http://mail.python.org/pipermail/python-dev/2012-June/120787.html """ try: st = os.stat(path) except OSError: err = sys.exc_info()[1] if err.errno in (errno.EPERM, errno.EACCES): raise return False else: return stat.S_ISREG(st.st_mode) # --- Process.get_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, socket # --- namedtuples # system nt_sysmeminfo = namedtuple('usage', 'total used free percent') # XXX - would 'available' be better than 'free' as for virtual_memory() nt? nt_swapmeminfo = namedtuple('swap', 'total used free percent sin sout') nt_diskinfo = namedtuple('usage', 'total used free percent') nt_partition = namedtuple('partition', 'device mountpoint fstype opts') nt_net_iostat = namedtuple( 'iostat', 'bytes_sent bytes_recv packets_sent packets_recv errin errout dropin dropout') nt_disk_iostat = namedtuple( 'iostat', 'read_count write_count read_bytes write_bytes read_time write_time') nt_user = namedtuple('user', 'name terminal host started') # processes nt_meminfo = namedtuple('meminfo', 'rss vms') nt_cputimes = namedtuple('cputimes', 'user system') nt_openfile = namedtuple('openfile', 'path fd') nt_thread = namedtuple('thread', 'id user_time system_time') nt_uids = namedtuple('user', 'real effective saved') nt_gids = namedtuple('group', 'real effective saved') nt_io = namedtuple('io', 'read_count write_count read_bytes write_bytes') nt_ionice = namedtuple('ionice', 'ioclass value') nt_ctxsw = namedtuple('amount', 'voluntary involuntary') # --- misc # backward compatibility layer for Process.get_connections() ntuple class nt_connection(namedtuple('connection', 'fd family type laddr raddr status')): __slots__ = () @property def local_address(self): warnings.warn("'local_address' field is deprecated; use 'laddr'" "instead", category=DeprecationWarning, stacklevel=2) return self.laddr @property def remote_address(self): warnings.warn("'remote_address' field is deprecated; use 'raddr'" "instead", category=DeprecationWarning, stacklevel=2) return self.raddr psutil-1.2.1/psutil/_psbsd.py0000664000175000017500000003110712243461126020146 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. """FreeBSD platform implementation.""" import errno import os import sys import warnings import _psutil_bsd import _psutil_posix from psutil import _psposix from psutil._common import * from psutil._compat import namedtuple, wraps from psutil._error import AccessDenied, NoSuchProcess, TimeoutExpired __extra__all__ = [] # --- constants # Since these constants get determined at import time we do not want to # crash immediately; instead we'll set them to None and most likely # we'll crash later as they're used for determining process CPU stats # and creation_time try: NUM_CPUS = _psutil_bsd.get_num_cpus() except Exception: NUM_CPUS = None warnings.warn("couldn't determine platform's NUM_CPUS", RuntimeWarning) try: TOTAL_PHYMEM = _psutil_bsd.get_virtual_mem()[0] except Exception: TOTAL_PHYMEM = None warnings.warn("couldn't determine platform's TOTAL_PHYMEM", RuntimeWarning) try: BOOT_TIME = _psutil_bsd.get_system_boot_time() except Exception: BOOT_TIME = None warnings.warn("couldn't determine platform's BOOT_TIME", RuntimeWarning) PROC_STATUSES = { _psutil_bsd.SSTOP: STATUS_STOPPED, _psutil_bsd.SSLEEP: STATUS_SLEEPING, _psutil_bsd.SRUN: STATUS_RUNNING, _psutil_bsd.SIDL: STATUS_IDLE, _psutil_bsd.SWAIT: STATUS_WAITING, _psutil_bsd.SLOCK: STATUS_LOCKED, _psutil_bsd.SZOMB: STATUS_ZOMBIE, } TCP_STATUSES = { _psutil_bsd.TCPS_ESTABLISHED: CONN_ESTABLISHED, _psutil_bsd.TCPS_SYN_SENT: CONN_SYN_SENT, _psutil_bsd.TCPS_SYN_RECEIVED: CONN_SYN_RECV, _psutil_bsd.TCPS_FIN_WAIT_1: CONN_FIN_WAIT1, _psutil_bsd.TCPS_FIN_WAIT_2: CONN_FIN_WAIT2, _psutil_bsd.TCPS_TIME_WAIT: CONN_TIME_WAIT, _psutil_bsd.TCPS_CLOSED: CONN_CLOSE, _psutil_bsd.TCPS_CLOSE_WAIT: CONN_CLOSE_WAIT, _psutil_bsd.TCPS_LAST_ACK: CONN_LAST_ACK, _psutil_bsd.TCPS_LISTEN: CONN_LISTEN, _psutil_bsd.TCPS_CLOSING: CONN_CLOSING, _psutil_bsd.PSUTIL_CONN_NONE: CONN_NONE, } PAGESIZE = os.sysconf("SC_PAGE_SIZE") nt_virtmem_info = namedtuple('vmem', ' '.join([ # all platforms 'total', 'available', 'percent', 'used', 'free', # FreeBSD specific 'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])) def virtual_memory(): """System virtual memory as a namedutple.""" mem = _psutil_bsd.get_virtual_mem() total, free, active, inactive, wired, cached, buffers, shared = mem avail = inactive + cached + free used = active + wired + cached percent = usage_percent((total - avail), total, _round=1) return nt_virtmem_info(total, avail, percent, used, free, active, inactive, buffers, cached, shared, wired) def swap_memory(): """System swap memory as (total, used, free, sin, sout) namedtuple.""" total, used, free, sin, sout = \ [x * PAGESIZE for x in _psutil_bsd.get_swap_mem()] percent = usage_percent(used, total, _round=1) return nt_swapmeminfo(total, used, free, percent, sin, sout) _cputimes_ntuple = namedtuple('cputimes', 'user nice system idle irq') def get_system_cpu_times(): """Return system per-CPU times as a named tuple""" user, nice, system, idle, irq = _psutil_bsd.get_system_cpu_times() return _cputimes_ntuple(user, nice, system, idle, irq) def get_system_per_cpu_times(): """Return system CPU times as a named tuple""" ret = [] for cpu_t in _psutil_bsd.get_system_per_cpu_times(): user, nice, system, idle, irq = cpu_t item = _cputimes_ntuple(user, nice, system, idle, irq) ret.append(item) return ret # XXX # Ok, this is very dirty. # On FreeBSD < 8 we cannot gather per-cpu information, see: # http://code.google.com/p/psutil/issues/detail?id=226 # If NUM_CPUS > 1, on first call we return single cpu times to avoid a # crash at psutil import time. # Next calls will fail with NotImplementedError if not hasattr(_psutil_bsd, "get_system_per_cpu_times"): def get_system_per_cpu_times(): if NUM_CPUS == 1: return [get_system_cpu_times] if get_system_per_cpu_times.__called__: raise NotImplementedError("supported only starting from FreeBSD 8") get_system_per_cpu_times.__called__ = True return [get_system_cpu_times] get_system_per_cpu_times.__called__ = False def disk_partitions(all=False): retlist = [] partitions = _psutil_bsd.get_disk_partitions() for partition in partitions: device, mountpoint, fstype, opts = partition if device == 'none': device = '' if not all: if not os.path.isabs(device) or not os.path.exists(device): continue ntuple = nt_partition(device, mountpoint, fstype, opts) retlist.append(ntuple) return retlist def get_system_users(): retlist = [] rawlist = _psutil_bsd.get_system_users() for item in rawlist: user, tty, hostname, tstamp = item if tty == '~': continue # reboot or shutdown nt = nt_user(user, tty or None, hostname, tstamp) retlist.append(nt) return retlist get_pid_list = _psutil_bsd.get_pid_list pid_exists = _psposix.pid_exists get_disk_usage = _psposix.get_disk_usage net_io_counters = _psutil_bsd.get_net_io_counters disk_io_counters = _psutil_bsd.get_disk_io_counters # not public; it's here because we need to test it from test_memory_leask.py get_num_cpus = _psutil_bsd.get_num_cpus() get_system_boot_time = _psutil_bsd.get_system_boot_time def wrap_exceptions(fun): """Decorator which translates bare OSError exceptions into NoSuchProcess and AccessDenied. """ @wraps(fun) def wrapper(self, *args, **kwargs): try: return fun(self, *args, **kwargs) except OSError: err = sys.exc_info()[1] if err.errno == errno.ESRCH: raise NoSuchProcess(self.pid, self._process_name) if err.errno in (errno.EPERM, errno.EACCES): raise AccessDenied(self.pid, self._process_name) raise return wrapper class Process(object): """Wrapper class around underlying C implementation.""" __slots__ = ["pid", "_process_name"] def __init__(self, pid): self.pid = pid self._process_name = None @wrap_exceptions def get_process_name(self): """Return process name as a string of limited len (15).""" return _psutil_bsd.get_process_name(self.pid) @wrap_exceptions def get_process_exe(self): """Return process executable pathname.""" return _psutil_bsd.get_process_exe(self.pid) @wrap_exceptions def get_process_cmdline(self): """Return process cmdline as a list of arguments.""" return _psutil_bsd.get_process_cmdline(self.pid) @wrap_exceptions def get_process_terminal(self): tty_nr = _psutil_bsd.get_process_tty_nr(self.pid) tmap = _psposix._get_terminal_map() try: return tmap[tty_nr] except KeyError: return None @wrap_exceptions def get_process_ppid(self): """Return process parent pid.""" return _psutil_bsd.get_process_ppid(self.pid) # XXX - available on FreeBSD >= 8 only if hasattr(_psutil_bsd, "get_process_cwd"): @wrap_exceptions def get_process_cwd(self): """Return process current working directory.""" # sometimes we get an empty string, in which case we turn # it into None return _psutil_bsd.get_process_cwd(self.pid) or None @wrap_exceptions def get_process_uids(self): """Return real, effective and saved user ids.""" real, effective, saved = _psutil_bsd.get_process_uids(self.pid) return nt_uids(real, effective, saved) @wrap_exceptions def get_process_gids(self): """Return real, effective and saved group ids.""" real, effective, saved = _psutil_bsd.get_process_gids(self.pid) return nt_gids(real, effective, saved) @wrap_exceptions def get_cpu_times(self): """return a tuple containing process user/kernel time.""" user, system = _psutil_bsd.get_process_cpu_times(self.pid) return nt_cputimes(user, system) @wrap_exceptions def get_memory_info(self): """Return a tuple with the process' RSS and VMS size.""" rss, vms = _psutil_bsd.get_process_memory_info(self.pid)[:2] return nt_meminfo(rss, vms) _nt_ext_mem = namedtuple('meminfo', 'rss vms text data stack') @wrap_exceptions def get_ext_memory_info(self): return self._nt_ext_mem(*_psutil_bsd.get_process_memory_info(self.pid)) @wrap_exceptions def get_process_create_time(self): """Return the start time of the process as a number of seconds since the epoch.""" return _psutil_bsd.get_process_create_time(self.pid) @wrap_exceptions def get_process_num_threads(self): """Return the number of threads belonging to the process.""" return _psutil_bsd.get_process_num_threads(self.pid) @wrap_exceptions def get_num_ctx_switches(self): return nt_ctxsw(*_psutil_bsd.get_process_num_ctx_switches(self.pid)) @wrap_exceptions def get_num_fds(self): """Return the number of file descriptors opened by this process.""" return _psutil_bsd.get_process_num_fds(self.pid) @wrap_exceptions def get_process_threads(self): """Return the number of threads belonging to the process.""" rawlist = _psutil_bsd.get_process_threads(self.pid) retlist = [] for thread_id, utime, stime in rawlist: ntuple = nt_thread(thread_id, utime, stime) retlist.append(ntuple) return retlist @wrap_exceptions def get_open_files(self): """Return files opened by process as a list of namedtuples.""" # XXX - C implementation available on FreeBSD >= 8 only # else fallback on lsof parser if hasattr(_psutil_bsd, "get_process_open_files"): rawlist = _psutil_bsd.get_process_open_files(self.pid) return [nt_openfile(path, fd) for path, fd in rawlist] else: lsof = _psposix.LsofParser(self.pid, self._process_name) return lsof.get_process_open_files() @wrap_exceptions def get_connections(self, kind='inet'): """Return etwork connections opened by a process as a list of namedtuples. """ if kind not in conn_tmap: raise ValueError("invalid %r kind argument; choose between %s" % (kind, ', '.join([repr(x) for x in conn_tmap]))) families, types = conn_tmap[kind] rawlist = _psutil_bsd.get_process_connections(self.pid, families, types) ret = [] for item in rawlist: fd, fam, type, laddr, raddr, status = item status = TCP_STATUSES[status] nt = nt_connection(fd, fam, type, laddr, raddr, status) ret.append(nt) return ret @wrap_exceptions def process_wait(self, timeout=None): try: return _psposix.wait_pid(self.pid, timeout) except TimeoutExpired: raise TimeoutExpired(self.pid, self._process_name) @wrap_exceptions def get_process_nice(self): return _psutil_posix.getpriority(self.pid) @wrap_exceptions def set_process_nice(self, value): return _psutil_posix.setpriority(self.pid, value) @wrap_exceptions def get_process_status(self): code = _psutil_bsd.get_process_status(self.pid) if code in PROC_STATUSES: return PROC_STATUSES[code] # XXX is this legit? will we even ever get here? return "?" @wrap_exceptions def get_process_io_counters(self): rc, wc, rb, wb = _psutil_bsd.get_process_io_counters(self.pid) return nt_io(rc, wc, rb, wb) nt_mmap_grouped = namedtuple( 'mmap', 'path rss, private, ref_count, shadow_count') nt_mmap_ext = namedtuple( 'mmap', 'addr, perms path rss, private, ref_count, shadow_count') @wrap_exceptions def get_memory_maps(self): return _psutil_bsd.get_process_memory_maps(self.pid) # FreeBSD < 8 does not support kinfo_getfile() and kinfo_getvmmap() if not hasattr(_psutil_bsd, 'get_process_open_files'): def _not_implemented(self): raise NotImplementedError("supported only starting from FreeBSD 8") get_open_files = _not_implemented get_process_cwd = _not_implemented get_memory_maps = _not_implemented get_num_fds = _not_implemented psutil-1.2.1/psutil/_psutil_bsd.c0000664000175000017500000014412012243206601020770 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 platform-specific module methods for _psutil_bsd */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for struct xsocket */ /* for xinpcb struct */ #include #include #include #include #include /* for struct xtcpcb */ #include /* for TCP connection states */ #include /* for inet_ntop() */ #if __FreeBSD_version < 900000 #include /* system users */ #else #include #endif #include /* get io counters */ #include /* needed for vmtotal struct */ #include /* process open files, shared libs (kinfo_getvmmap) */ #include #include /* net io counters */ #include #include #include /* process open files/connections */ #include #include "_psutil_bsd.h" #include "_psutil_common.h" #include "arch/bsd/process_info.h" // convert a timeval struct to a double #define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0) /* * Utility function which fills a kinfo_proc struct based on process pid */ static int psutil_get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) { int mib[4]; size_t size; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; size = sizeof(struct kinfo_proc); if (sysctl((int*)mib, 4, proc, &size, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return -1; } /* * sysctl stores 0 in the size if we can't find the process information. */ if (size == 0) { NoSuchProcess(); return -1; } return 0; } /* * Return a Python list of all the PIDs running on the system. */ static PyObject* get_pid_list(PyObject* self, PyObject* args) { kinfo_proc *proclist = NULL; kinfo_proc *orig_address = NULL; size_t num_processes; size_t idx; PyObject* retlist = PyList_New(0); PyObject* pid = NULL; if (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++) { pid = Py_BuildValue("i", proclist->ki_pid); if (!pid) goto error; if (PyList_Append(retlist, pid)) goto error; Py_DECREF(pid); proclist++; } free(orig_address); } return retlist; error: Py_XDECREF(pid); Py_DECREF(retlist); if (orig_address != NULL) { free(orig_address); } return NULL; } /* * Return a Python float indicating the system boot time expressed in * seconds since the epoch. */ static PyObject* get_system_boot_time(PyObject* self, PyObject* args) { /* fetch sysctl "kern.boottime" */ static int request[2] = { CTL_KERN, KERN_BOOTTIME }; struct timeval 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* get_process_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.ki_comm); } /* * Return process pathname executable. * Thanks to Robert N. M. Watson: * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT */ static PyObject* get_process_exe(PyObject* self, PyObject* args) { long pid; char pathname[PATH_MAX]; int error; int mib[4]; size_t size; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } 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) { if (psutil_pid_exists(pid) == 0) { return NoSuchProcess(); } else { strcpy(pathname, ""); } } return Py_BuildValue("s", pathname); } /* * Return process cmdline as a Python list of cmdline arguments. */ static PyObject* get_process_cmdline(PyObject* self, PyObject* args) { long pid; PyObject* arglist = NULL; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } // get the commandline, defined in arch/bsd/process_info.c arglist = psutil_get_arg_list(pid); // psutil_get_arg_list() returns NULL only if psutil_get_cmd_args failed with ESRCH // (no process with that PID) if (NULL == arglist) { return PyErr_SetFromErrno(PyExc_OSError); } return Py_BuildValue("N", arglist); } /* * Return process parent pid from kinfo_proc as a Python integer. */ static PyObject* get_process_ppid(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("l", (long)kp.ki_ppid); } /* * Return process status as a Python integer. */ static PyObject* get_process_status(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("i", (int)kp.ki_stat); } /* * Return process real, effective and saved user ids from kinfo_proc * as a Python tuple. */ static PyObject* get_process_uids(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("lll", (long)kp.ki_ruid, (long)kp.ki_uid, (long)kp.ki_svuid); } /* * Return process real, effective and saved group ids from kinfo_proc * as a Python tuple. */ static PyObject* get_process_gids(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("lll", (long)kp.ki_rgid, (long)kp.ki_groups[0], (long)kp.ki_svuid); } /* * Return process real, effective and saved group ids from kinfo_proc * as a Python tuple. */ static PyObject* get_process_tty_nr(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("i", kp.ki_tdev); } /* * Return the number of context switches performed by process as a tuple. */ static PyObject* get_process_num_ctx_switches(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("(ll)", kp.ki_rusage.ru_nvcsw, kp.ki_rusage.ru_nivcsw); } /* * Return number of threads used by process as a Python integer. */ static PyObject* get_process_num_threads(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("l", (long)kp.ki_numthreads); } /* * Retrieves all threads used by process returning a list of tuples * including thread id, user time and system time. * Thanks to Robert N. M. Watson: * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRENT */ static PyObject* get_process_threads(PyObject* self, PyObject* args) { long pid; int mib[4]; struct kinfo_proc *kip = NULL; struct kinfo_proc *kipp = NULL; int error; unsigned int i; size_t size; PyObject* retList = PyList_New(0); PyObject* pyTuple = NULL; if (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]; pyTuple = Py_BuildValue("Idd", kipp->ki_tid, TV2DOUBLE(kipp->ki_rusage.ru_utime), TV2DOUBLE(kipp->ki_rusage.ru_stime) ); if (pyTuple == NULL) goto error; if (PyList_Append(retList, pyTuple)) goto error; Py_DECREF(pyTuple); } free(kip); return retList; error: Py_XDECREF(pyTuple); Py_DECREF(retList); if (kip != NULL) { free(kip); } return NULL; } /* * Return a Python tuple (user_time, kernel_time) */ static PyObject* get_process_cpu_times(PyObject* self, PyObject* args) { long pid; double user_t, sys_t; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } // convert from microseconds to seconds user_t = TV2DOUBLE(kp.ki_rusage.ru_utime); sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime); return Py_BuildValue("(dd)", user_t, sys_t); } /* * Return a Python integer indicating the number of CPUs on the system */ static PyObject* get_num_cpus(PyObject* self, PyObject* args) { int mib[2]; int ncpu; size_t len; mib[0] = CTL_HW; mib[1] = HW_NCPU; len = sizeof(ncpu); if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } return Py_BuildValue("i", ncpu); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject* get_process_create_time(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("d", TV2DOUBLE(kp.ki_start)); } /* * Return a Python float indicating the process create time expressed in * seconds since the epoch. */ static PyObject* get_process_io_counters(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } // there's apparently no way to determine bytes count, hence return -1. return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock, kp.ki_rusage.ru_oublock, -1, -1); } /* * Return extended memory info for a process as a Python tuple. */ static PyObject* get_process_memory_info(PyObject* self, PyObject* args) { long pid; struct kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) { return NULL; } if (psutil_get_kinfo_proc(pid, &kp) == -1) { return NULL; } return Py_BuildValue("(lllll)", ptoa(kp.ki_rssize), // rss (long)kp.ki_size, // vms ptoa(kp.ki_tsize), // text ptoa(kp.ki_dsize), // data ptoa(kp.ki_ssize)); // stack } /* * Return virtual memory usage statistics. */ static PyObject* get_virtual_mem(PyObject* self, PyObject* args) { unsigned int total, active, inactive, wired, cached, free; 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("vm.stats.vm.v_page_count", &total, &size, NULL, 0)) goto error; if (sysctlbyname("vm.stats.vm.v_active_count", &active, &size, NULL, 0)) goto error; if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactive, &size, NULL, 0)) goto error; if (sysctlbyname("vm.stats.vm.v_wire_count", &wired, &size, NULL, 0)) goto error; if (sysctlbyname("vm.stats.vm.v_cache_count", &cached, &size, NULL, 0)) goto error; if (sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0)) goto error; if (sysctlbyname("vfs.bufspace", &buffers, &buffers_size, NULL, 0)) goto error; size = sizeof(vm); if (sysctl(mib, 2, &vm, &size, NULL, 0) != 0) goto error; return Py_BuildValue("KKKKKKKK", (unsigned long long) total * pagesize, (unsigned long long) free * pagesize, (unsigned long long) active * pagesize, (unsigned long long) inactive * pagesize, (unsigned long long) wired * pagesize, (unsigned long long) cached * pagesize, (unsigned long long) buffers, (unsigned long long) (vm.t_vmshr + vm.t_rmshr) * pagesize // shared ); error: PyErr_SetFromErrno(PyExc_OSError); return NULL; } #ifndef _PATH_DEVNULL #define _PATH_DEVNULL "/dev/null" #endif /* * Return swap memory stats (see 'swapinfo' cmdline tool) */ static PyObject* get_swap_mem(PyObject* self, PyObject* args) { kvm_t *kd; struct kvm_swap kvmsw[1]; unsigned int swapin, swapout, nodein, nodeout; size_t size = sizeof(unsigned int); 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; } /* * Return a Python tuple representing user, kernel and idle CPU times */ static PyObject* get_system_cpu_times(PyObject* self, PyObject* args) { long cpu_time[CPUSTATES]; size_t size; size = sizeof(cpu_time); if (sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0) == -1) { PyErr_SetFromErrno(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 ); } /* * XXX * These functions are available on FreeBSD 8 only. * In the upper python layer we do various tricks to avoid crashing * and/or to provide alternatives where possible. */ #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 /* * Return files opened by process as a list of (path, fd) tuples */ static PyObject* get_process_open_files(PyObject* self, PyObject* args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; struct kinfo_proc kipp; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; if (retList == NULL) return NULL; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_get_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_type == KF_TYPE_VNODE) && (kif->kf_vnode_type == KF_VTYPE_VREG)) { tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd); if (tuple == NULL) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(tuple); } } free(freep); return retList; error: Py_XDECREF(tuple); Py_DECREF(retList); if (freep != NULL) free(freep); return NULL; } /* * Return files opened by process as a list of (path, fd) tuples */ static PyObject* get_process_num_fds(PyObject* self, PyObject* args) { long pid; int cnt; struct kinfo_file *freep; struct kinfo_proc kipp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; if (psutil_get_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); } /* * Return process current working directory. */ static PyObject* get_process_cwd(PyObject* self, PyObject* args) { long pid; PyObject *path = NULL; struct kinfo_file *freep = NULL; struct kinfo_file *kif; struct kinfo_proc kipp; int i, cnt; if (! PyArg_ParseTuple(args, "l", &pid)) goto error; if (psutil_get_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) { path = Py_BuildValue("s", kif->kf_path); if (!path) goto error; break; } } /* * For lower pids it seems we can't retrieve any information * (lsof can't do that it either). Since this happens even * as root we return an empty string instead of AccessDenied. */ if (path == NULL) { path = Py_BuildValue("s", ""); } free(freep); return path; error: Py_XDECREF(path); if (freep != NULL) free(freep); return NULL; } /* The tcplist fetching and walking is borrowed from netstat/inet.c. */ static char * psutil_fetch_tcplist(void) { char *buf; size_t len; int error; 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; } // a signaler for connections without an actual status static int PSUTIL_CONN_NONE = 128; /* * Return connections opened by process. */ static PyObject* get_process_connections(PyObject* self, PyObject* args) { long pid; int i, cnt; struct kinfo_file *freep = NULL; struct kinfo_file *kif; struct kinfo_proc kipp; char *tcplist = NULL; struct tcpcb *tcp; PyObject *retList = PyList_New(0); PyObject *tuple = NULL; PyObject *laddr = NULL; PyObject *raddr = NULL; PyObject *af_filter = NULL; PyObject *type_filter = NULL; PyObject* _family = NULL; PyObject* _type = NULL; if (retList == NULL) { return NULL; } if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) { goto error; } if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) { PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence"); goto error; } 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; tuple = NULL; laddr = NULL; raddr = NULL; kif = &freep[i]; if (kif->kf_type == KF_TYPE_SOCKET) { // apply filters _family = PyLong_FromLong((long)kif->kf_sock_domain); inseq = PySequence_Contains(af_filter, _family); Py_DECREF(_family); if (inseq == 0) { continue; } _type = PyLong_FromLong((long)kif->kf_sock_type); inseq = PySequence_Contains(type_filter, _type); Py_DECREF(_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 laddr = Py_BuildValue("(si)", lip, lport); if (!laddr) goto error; if (rport != 0) { raddr = Py_BuildValue("(si)", rip, rport); } else { raddr = Py_BuildValue("()"); } if (!raddr) goto error; tuple = Py_BuildValue("(iiiNNi)", kif->kf_fd, kif->kf_sock_domain, kif->kf_sock_type, laddr, raddr, state); if (!tuple) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(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", (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))), sun->sun_path); tuple = Py_BuildValue("(iiisOi)", kif->kf_fd, kif->kf_sock_domain, kif->kf_sock_type, path, Py_None, PSUTIL_CONN_NONE); if (!tuple) goto error; if (PyList_Append(retList, tuple)) goto error; Py_DECREF(tuple); Py_INCREF(Py_None); } } } free(freep); free(tcplist); return retList; error: Py_XDECREF(tuple); Py_XDECREF(laddr); Py_XDECREF(raddr); Py_DECREF(retList); if (freep != NULL) free(freep); if (tcplist != NULL) free(tcplist); return NULL; } /* * Return a Python list of tuple representing per-cpu times */ static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args) { static int maxcpus; int mib[2]; int ncpu; size_t len; size_t size; int i; PyObject* py_retlist = PyList_New(0); PyObject* py_cputime = NULL; 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; } // remove spaces from string void remove_spaces(char *str) { char *p1 = str; char *p2 = str; do while (*p2 == ' ') p2++; while (*p1++ = *p2++); } /* * Return a list of tuples for every process memory maps. * 'procstat' cmdline utility has been used as an example. */ static PyObject* get_process_memory_maps(PyObject* self, PyObject* args) { long pid; int ptrwidth; int i, cnt; char addr[30]; char perms[4]; const char *path; struct kinfo_proc kp; struct kinfo_vmentry *freep = NULL; struct kinfo_vmentry *kve; ptrwidth = 2*sizeof(void *); PyObject* pytuple = NULL; PyObject* retlist = PyList_New(0); if (retlist == NULL) { return NULL; } if (! PyArg_ParseTuple(args, "l", &pid)) { goto error; } if (psutil_get_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++) { pytuple = NULL; kve = &freep[i]; addr[0] = '\0'; perms[0] = '\0'; sprintf(addr, "%#*jx-%#*jx", ptrwidth, (uintmax_t)kve->kve_start, ptrwidth, (uintmax_t)kve->kve_end); 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; } pytuple = Py_BuildValue("sssiiii", addr, // "start-end" address perms, // "rwx" permissions path, // path kve->kve_resident, // rss kve->kve_private_resident, // private kve->kve_ref_count, // ref count kve->kve_shadow_count // shadow count ); if (!pytuple) goto error; if (PyList_Append(retlist, pytuple)) goto error; Py_DECREF(pytuple); } free(freep); return retlist; error: Py_XDECREF(pytuple); Py_DECREF(retlist); if (freep != NULL) free(freep); return NULL; } #endif /* * Return a list of tuples including device, mount point and fs type * for all partitions mounted on the system. */ static PyObject* get_disk_partitions(PyObject* self, PyObject* args) { int num; int i; long len; uint64_t flags; char opts[200]; struct statfs *fs = NULL; PyObject* py_retlist = PyList_New(0); PyObject* py_tuple = NULL; 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++) { py_tuple = NULL; opts[0] = 0; flags = fs[i].f_flags; // see sys/mount.h if (flags & MNT_RDONLY) strlcat(opts, "ro", sizeof(opts)); else strlcat(opts, "rw", sizeof(opts)); if (flags & MNT_SYNCHRONOUS) strlcat(opts, ",sync", sizeof(opts)); if (flags & MNT_NOEXEC) strlcat(opts, ",noexec", sizeof(opts)); if (flags & MNT_NOSUID) strlcat(opts, ",nosuid", sizeof(opts)); if (flags & MNT_UNION) strlcat(opts, ",union", sizeof(opts)); if (flags & MNT_ASYNC) strlcat(opts, ",async", sizeof(opts)); if (flags & MNT_SUIDDIR) strlcat(opts, ",suiddir", sizeof(opts)); if (flags & MNT_SOFTDEP) strlcat(opts, ",softdep", sizeof(opts)); if (flags & MNT_NOSYMFOLLOW) strlcat(opts, ",nosymfollow", sizeof(opts)); if (flags & MNT_GJOURNAL) strlcat(opts, ",gjournal", sizeof(opts)); if (flags & MNT_MULTILABEL) strlcat(opts, ",multilabel", sizeof(opts)); if (flags & MNT_ACLS) strlcat(opts, ",acls", sizeof(opts)); if (flags & MNT_NOATIME) strlcat(opts, ",noatime", sizeof(opts)); if (flags & MNT_NOCLUSTERR) strlcat(opts, ",noclusterr", sizeof(opts)); if (flags & MNT_NOCLUSTERW) strlcat(opts, ",noclusterw", sizeof(opts)); if (flags & MNT_NFS4ACLS) strlcat(opts, ",nfs4acls", sizeof(opts)); py_tuple = Py_BuildValue("(ssss)", fs[i].f_mntfromname, // device fs[i].f_mntonname, // mount point fs[i].f_fstypename, // fs type opts); // options if (!py_tuple) goto error; if (PyList_Append(py_retlist, py_tuple)) goto error; Py_DECREF(py_tuple); } free(fs); return py_retlist; error: Py_XDECREF(py_tuple); Py_DECREF(py_retlist); if (fs != NULL) free(fs); return NULL; } /* * Return a Python list of named tuples with overall network I/O information */ static PyObject* get_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 a Python dict of tuples for disk I/O information */ static PyObject* get_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)devstat_compute_etime( ¤t.duration[DEVSTAT_READ], NULL), // r time (long long)devstat_compute_etime( ¤t.duration[DEVSTAT_WRITE], NULL) // w time ); if (!py_disk_info) goto error; if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info)) goto error; Py_DECREF(py_disk_info); } if (stats.dinfo->mem_ptr) { free(stats.dinfo->mem_ptr); } free(stats.dinfo); return py_retdict; error: Py_XDECREF(py_disk_info); Py_DECREF(py_retdict); if (stats.dinfo != NULL) free(stats.dinfo); return NULL; } /* * Return currently connected users as a list of tuples. */ static PyObject* get_system_users(PyObject* self, PyObject* args) { PyObject *ret_list = PyList_New(0); PyObject *tuple = NULL; if (ret_list == NULL) return NULL; #if __FreeBSD_version < 900000 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; tuple = Py_BuildValue("(sssf)", ut.ut_name, // username ut.ut_line, // tty ut.ut_host, // hostname (float)ut.ut_time // start time ); if (!tuple) { fclose(fp); goto error; } if (PyList_Append(ret_list, tuple)) { fclose(fp); goto error; } Py_DECREF(tuple); } fclose(fp); #else struct utmpx *utx; while ((utx = getutxent()) != NULL) { if (utx->ut_type != USER_PROCESS) continue; tuple = Py_BuildValue("(sssf)", utx->ut_user, // username utx->ut_line, // tty utx->ut_host, // hostname (float)utx->ut_tv.tv_sec // start time ); if (!tuple) { endutxent(); goto error; } if (PyList_Append(ret_list, tuple)) { endutxent(); goto error; } Py_DECREF(tuple); } endutxent(); #endif return ret_list; error: Py_XDECREF(tuple); Py_DECREF(ret_list); return NULL; } /* * define the psutil C module methods and initialize the module. */ static PyMethodDef PsutilMethods[] = { // --- per-process functions {"get_process_name", get_process_name, METH_VARARGS, "Return process name"}, {"get_process_connections", get_process_connections, METH_VARARGS, "Return connections opened by process"}, {"get_process_exe", get_process_exe, METH_VARARGS, "Return process pathname executable"}, {"get_process_cmdline", get_process_cmdline, METH_VARARGS, "Return process cmdline as a list of cmdline arguments"}, {"get_process_ppid", get_process_ppid, METH_VARARGS, "Return process ppid as an integer"}, {"get_process_uids", get_process_uids, METH_VARARGS, "Return process real effective and saved user ids as a Python tuple"}, {"get_process_gids", get_process_gids, METH_VARARGS, "Return process real effective and saved group ids as a Python tuple"}, {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS, "Return tuple of user/kern time for the given PID"}, {"get_process_create_time", get_process_create_time, METH_VARARGS, "Return a float indicating the process create time expressed in " "seconds since the epoch"}, {"get_process_memory_info", get_process_memory_info, METH_VARARGS, "Return extended memory info for a process as a Python tuple."}, {"get_process_num_threads", get_process_num_threads, METH_VARARGS, "Return number of threads used by process"}, {"get_process_num_ctx_switches", get_process_num_ctx_switches, METH_VARARGS, "Return the number of context switches performed by process"}, {"get_process_threads", get_process_threads, METH_VARARGS, "Return process threads"}, {"get_process_status", get_process_status, METH_VARARGS, "Return process status as an integer"}, {"get_process_io_counters", get_process_io_counters, METH_VARARGS, "Return process IO counters"}, {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS, "Return process tty (terminal) number"}, #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 {"get_process_open_files", get_process_open_files, METH_VARARGS, "Return files opened by process as a list of (path, fd) tuples"}, {"get_process_cwd", get_process_cwd, METH_VARARGS, "Return process current working directory."}, {"get_process_memory_maps", get_process_memory_maps, METH_VARARGS, "Return a list of tuples for every process's memory map"}, {"get_process_num_fds", get_process_num_fds, METH_VARARGS, "Return the number of file descriptors opened by this process"}, #endif // --- system-related functions {"get_pid_list", get_pid_list, METH_VARARGS, "Returns a list of PIDs currently running on the system"}, {"get_num_cpus", get_num_cpus, METH_VARARGS, "Return number of CPUs on the system"}, {"get_virtual_mem", get_virtual_mem, METH_VARARGS, "Return system virtual memory usage statistics"}, {"get_swap_mem", get_swap_mem, METH_VARARGS, "Return swap mem stats"}, {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS, "Return system cpu times as a tuple (user, system, nice, idle, irc)"}, #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS, "Return system per-cpu times as a list of tuples"}, #endif {"get_system_boot_time", get_system_boot_time, METH_VARARGS, "Return the system boot time expressed in seconds since the epoch."}, {"get_disk_partitions", get_disk_partitions, METH_VARARGS, "Return a list of tuples including device, mount point and " "fs type for all partitions mounted on the system."}, {"get_net_io_counters", get_net_io_counters, METH_VARARGS, "Return dict of tuples of networks I/O information."}, {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS, "Return a Python dict of tuples for disk I/O information"}, {"get_system_users", get_system_users, METH_VARARGS, "Return currently connected users as a list of tuples"}, {NULL, NULL, 0, NULL} }; struct module_state { PyObject *error; }; #if PY_MAJOR_VERSION >= 3 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) #else #define GETSTATE(m) (&_state) #endif #if PY_MAJOR_VERSION >= 3 static int psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int psutil_bsd_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "psutil_bsd", NULL, sizeof(struct module_state), PsutilMethods, NULL, psutil_bsd_traverse, psutil_bsd_clear, NULL }; #define INITERROR return NULL PyObject * PyInit__psutil_bsd(void) #else #define INITERROR return void init_psutil_bsd(void) #endif { #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods); #endif // process status constants PyModule_AddIntConstant(module, "SSTOP", SSTOP); PyModule_AddIntConstant(module, "SSLEEP", SSLEEP); PyModule_AddIntConstant(module, "SRUN", SRUN); PyModule_AddIntConstant(module, "SIDL", SIDL); PyModule_AddIntConstant(module, "SWAIT", SWAIT); PyModule_AddIntConstant(module, "SLOCK", SLOCK); PyModule_AddIntConstant(module, "SZOMB", SZOMB); // 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-1.2.1/psutil/arch/0000775000175000017500000000000012244726663017250 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil/arch/mswindows/0000775000175000017500000000000012244726663021302 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil/arch/mswindows/process_handles.h0000664000175000017500000000054412243206601024612 0ustar giampaologiampaolo00000000000000/* * $Id: process_info.h 1060 2011-07-02 18:05:26Z g.rodola $ * * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include PyObject* psutil_get_open_files(long pid, HANDLE processHandle); psutil-1.2.1/psutil/arch/mswindows/process_info.h0000664000175000017500000000137512243206601024132 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_mswindows * module methods. */ #include #include HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess); HANDLE psutil_handle_from_pid(DWORD pid); PVOID psutil_get_peb_address(HANDLE ProcessHandle); HANDLE psutil_handle_from_pid(DWORD pid); int psutil_pid_in_proclist(DWORD pid); int psutil_pid_is_running(DWORD pid); int psutil_handlep_is_running(HANDLE hProcess); PyObject* psutil_get_arg_list(long pid); DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs); psutil-1.2.1/psutil/arch/mswindows/ntextapi.h0000664000175000017500000001714612243206601023300 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. * */ typedef enum _KTHREAD_STATE { Initialized, Ready, Running, Standby, Terminated, Waiting, Transition, DeferredReady, GateWait, MaximumThreadState } KTHREAD_STATE, *PKTHREAD_STATE; typedef enum _KWAIT_REASON { Executive = 0, FreePage = 1, PageIn = 2, PoolAllocation = 3, DelayExecution = 4, Suspended = 5, UserRequest = 6, WrExecutive = 7, WrFreePage = 8, WrPageIn = 9, WrPoolAllocation = 10, WrDelayExecution = 11, WrSuspended = 12, WrUserRequest = 13, WrEventPair = 14, WrQueue = 15, WrLpcReceive = 16, WrLpcReply = 17, WrVirtualMemory = 18, WrPageOut = 19, WrRendezvous = 20, Spare2 = 21, Spare3 = 22, Spare4 = 23, Spare5 = 24, WrCalloutStack = 25, WrKernel = 26, WrResource = 27, WrPushLock = 28, WrMutex = 29, WrQuantumEnd = 30, WrDispatchInt = 31, WrPreempted = 32, WrYieldExecution = 33, WrFastMutex = 34, WrGuardedMutex = 35, WrRundown = 36, MaximumWaitReason = 37 } KWAIT_REASON, *PKWAIT_REASON; typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef struct _SYSTEM_TIMEOFDAY_INFORMATION { LARGE_INTEGER BootTime; LARGE_INTEGER CurrentTime; LARGE_INTEGER TimeZoneBias; ULONG TimeZoneId; ULONG Reserved; ULONGLONG BootTimeBias; ULONGLONG SleepTimeBias; } SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; LONG Priority; LONG BasePriority; ULONG ContextSwitches; ULONG ThreadState; KWAIT_REASON WaitReason; } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; typedef struct _TEB *PTEB; // private typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION { SYSTEM_THREAD_INFORMATION ThreadInfo; PVOID StackBase; PVOID StackLimit; PVOID Win32StartAddress; PTEB TebBase; ULONG_PTR Reserved2; ULONG_PTR Reserved3; ULONG_PTR Reserved4; } SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; LARGE_INTEGER SpareLi1; LARGE_INTEGER SpareLi2; LARGE_INTEGER SpareLi3; LARGE_INTEGER CreateTime; LARGE_INTEGER UserTime; LARGE_INTEGER KernelTime; UNICODE_STRING ImageName; LONG BasePriority; HANDLE UniqueProcessId; HANDLE InheritedFromUniqueProcessId; ULONG HandleCount; ULONG SessionId; ULONG_PTR PageDirectoryBase; SIZE_T PeakVirtualSize; SIZE_T VirtualSize; DWORD PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; SYSTEM_THREAD_INFORMATION Threads[1]; } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; // structures and enums from winternl.h (not available under mingw) typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { LARGE_INTEGER IdleTime; LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER Reserved1[2]; ULONG Reserved2; } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45 } SYSTEM_INFORMATION_CLASS; // ================================================ // get_system_users support () // ================================================ typedef struct _WINSTATION_INFO { BYTE Reserved1[72]; ULONG SessionId; BYTE Reserved2[4]; FILETIME ConnectTime; FILETIME DisconnectTime; FILETIME LastInputTime; FILETIME LoginTime; BYTE Reserved3[1096]; FILETIME CurrentTime; } WINSTATION_INFO, *PWINSTATION_INFO; typedef enum _WINSTATIONINFOCLASS { WinStationInformation = 8 } WINSTATIONINFOCLASS; typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW) (HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG); typedef struct _WINSTATIONINFORMATIONW { BYTE Reserved2[70]; ULONG LogonId; BYTE Reserved3[1140]; } WINSTATIONINFORMATIONW, *PWINSTATIONINFORMATIONW; // start mingw support: // http://www.koders.com/c/fid7C02CAE627C526914CDEB427405B51DF393A5EFA.aspx #ifndef _INC_WTSAPI typedef struct _WTS_CLIENT_ADDRESS { DWORD AddressFamily; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC BYTE Address[20]; // client network address } WTS_CLIENT_ADDRESS, * PWTS_CLIENT_ADDRESS; HANDLE WINAPI WTSOpenServerA( IN LPSTR pServerName ); VOID WINAPI WTSCloseServer( IN HANDLE hServer ); #endif // end mingw support: /* * 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 struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PVOID PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; typedef enum _PROCESSINFOCLASS { 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, ProcessBreakOnTermination, ProcessDebugObjectHandle, ProcessDebugFlags, ProcessHandleTracing, ProcessIoPriority, ProcessExecuteFlags, ProcessResourceManagement, ProcessCookie, ProcessImageInformation, MaxProcessInfoClass } PROCESSINFOCLASS; psutil-1.2.1/psutil/arch/mswindows/process_handles.c0000664000175000017500000002252312243206601024606 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 UNICODE #define UNICODE #endif #include #include #include #include "process_handles.h" #ifndef NT_SUCCESS #define NT_SUCCESS(x) ((x) >= 0) #endif #define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 #define SystemHandleInformation 16 #define ObjectBasicInformation 0 #define ObjectNameInformation 1 #define ObjectTypeInformation 2 typedef LONG NTSTATUS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)( ULONG SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength ); typedef NTSTATUS (NTAPI *_NtDuplicateObject)( HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, ULONG Attributes, ULONG Options ); typedef NTSTATUS (NTAPI *_NtQueryObject)( HANDLE ObjectHandle, ULONG ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength ); typedef struct _SYSTEM_HANDLE { ULONG ProcessId; BYTE ObjectTypeNumber; BYTE Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE, *PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG HandleCount; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef enum _POOL_TYPE { NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, NonPagedPoolCacheAligned, PagedPoolCacheAligned, NonPagedPoolCacheAlignedMustS } POOL_TYPE, *PPOOL_TYPE; typedef struct _OBJECT_TYPE_INFORMATION { UNICODE_STRING Name; ULONG TotalNumberOfObjects; ULONG TotalNumberOfHandles; ULONG TotalPagedPoolUsage; ULONG TotalNonPagedPoolUsage; ULONG TotalNamePoolUsage; ULONG TotalHandleTableUsage; ULONG HighWaterNumberOfObjects; ULONG HighWaterNumberOfHandles; ULONG HighWaterPagedPoolUsage; ULONG HighWaterNonPagedPoolUsage; ULONG HighWaterNamePoolUsage; ULONG HighWaterHandleTableUsage; ULONG InvalidAttributes; GENERIC_MAPPING GenericMapping; ULONG ValidAccess; BOOLEAN SecurityRequired; BOOLEAN MaintainHandleCount; USHORT MaintainTypeList; POOL_TYPE PoolType; ULONG PagedPoolUsage; ULONG NonPagedPoolUsage; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) { return GetProcAddress(GetModuleHandleA(LibraryName), ProcName); } PyObject* psutil_get_open_files(long pid, HANDLE processHandle) { _NtQuerySystemInformation NtQuerySystemInformation = GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation"); _NtDuplicateObject NtDuplicateObject = GetLibraryProcAddress("ntdll.dll", "NtDuplicateObject"); _NtQueryObject NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject"); NTSTATUS status; PSYSTEM_HANDLE_INFORMATION handleInfo; ULONG handleInfoSize = 0x10000; ULONG i; ULONG fileNameLength; PyObject *filesList = Py_BuildValue("[]"); PyObject *arg = NULL; PyObject *fileFromWchar = NULL; if (filesList == NULL) return NULL; handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize); if (handleInfo == NULL) { Py_DECREF(filesList); PyErr_NoMemory(); return NULL; } /* NtQuerySystemInformation won't give us the correct buffer size, so we guess by doubling the buffer size. */ while ((status = NtQuerySystemInformation( SystemHandleInformation, handleInfo, handleInfoSize, NULL )) == STATUS_INFO_LENGTH_MISMATCH) { handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2); } /* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */ if (!NT_SUCCESS(status)) { //printf("NtQuerySystemInformation failed!\n"); Py_DECREF(filesList); free(handleInfo); return NULL; } for (i = 0; i < handleInfo->HandleCount; i++) { SYSTEM_HANDLE handle = handleInfo->Handles[i]; HANDLE dupHandle = NULL; POBJECT_TYPE_INFORMATION objectTypeInfo = NULL; PVOID objectNameInfo; UNICODE_STRING objectName; ULONG returnLength; fileFromWchar = NULL; arg = NULL; /* Check if this handle belongs to the PID the user specified. */ if (handle.ProcessId != pid) continue; /* Skip handles with the following access codes as the next call to NtDuplicateObject() or NtQueryObject() might hang forever. */ if((handle.GrantedAccess == 0x0012019f) || (handle.GrantedAccess == 0x001a019f) || (handle.GrantedAccess == 0x00120189) || (handle.GrantedAccess == 0x00100000)) { continue; } /* Duplicate the handle so we can query it. */ if (!NT_SUCCESS(NtDuplicateObject( processHandle, handle.Handle, GetCurrentProcess(), &dupHandle, 0, 0, 0 ))) { //printf("[%#x] Error!\n", handle.Handle); continue; } /* Query the object type. */ objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000); if (!NT_SUCCESS(NtQueryObject( dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL ))) { //printf("[%#x] Error!\n", handle.Handle); free(objectTypeInfo); CloseHandle(dupHandle); continue; } objectNameInfo = malloc(0x1000); if (!NT_SUCCESS(NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength ))) { /* Reallocate the buffer and try again. */ objectNameInfo = realloc(objectNameInfo, returnLength); if (!NT_SUCCESS(NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, returnLength, NULL ))) { /* We have the type name, so just display that.*/ /* printf( "[%#x] %.*S: (could not get name)\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); */ free(objectTypeInfo); free(objectNameInfo); CloseHandle(dupHandle); continue; } } /* Cast our buffer into an UNICODE_STRING. */ objectName = *(PUNICODE_STRING)objectNameInfo; /* Print the information! */ if (objectName.Length) { /* The object has a name. Make sure it is a file otherwise ignore it */ fileNameLength = objectName.Length / 2; if (wcscmp(objectTypeInfo->Name.Buffer, L"File") == 0) { //printf("%.*S\n", objectName.Length / 2, objectName.Buffer); fileFromWchar = PyUnicode_FromWideChar(objectName.Buffer, fileNameLength); if (fileFromWchar == NULL) goto error_py_fun; #if PY_MAJOR_VERSION >= 3 arg = Py_BuildValue("N", PyUnicode_AsUTF8String(fileFromWchar)); #else arg = Py_BuildValue("N", PyUnicode_FromObject(fileFromWchar)); #endif if (!arg) goto error_py_fun; Py_XDECREF(fileFromWchar); fileFromWchar = NULL; if (PyList_Append(filesList, arg)) goto error_py_fun; Py_XDECREF(arg); } /* printf( "[%#x] %.*S: %.*S\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer, objectName.Length / 2, objectName.Buffer ); */ } else { /* Print something else. */ /* printf( "[%#x] %.*S: (unnamed)\n", handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer ); */ ;; } free(objectTypeInfo); free(objectNameInfo); CloseHandle(dupHandle); } free(handleInfo); CloseHandle(processHandle); return filesList; error_py_fun: Py_XDECREF(arg); Py_XDECREF(fileFromWchar); Py_DECREF(filesList); return NULL; } psutil-1.2.1/psutil/arch/mswindows/security.h0000664000175000017500000000103112243206601023275 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 SetPrivilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege); int SetSeDebug(); int UnsetSeDebug(); HANDLE token_from_handle(HANDLE hProcess); int HasSystemPrivilege(HANDLE hProcess); psutil-1.2.1/psutil/arch/mswindows/security.c0000664000175000017500000001477412243206601023312 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 token_from_handle(HANDLE hProcess) { HANDLE hToken = NULL; if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken) ) { return PyErr_SetFromWindowsErr(0); } return hToken; } /* * http://www.ddj.com/windows/184405986 * * There's a way to determine whether we're running under the Local System * account. However (you guessed it), we have to call more Win32 functions to * determine this. Backing up through the code listing, we need to make another * call to GetTokenInformation, but instead of passing through the TOKEN_USER * constant, we pass through the TOKEN_PRIVILEGES constant. This value returns * an array of privileges that the account has in the environment. Iterating * through the array, we call the function LookupPrivilegeName looking for the * string “SeTcbPrivilege. If the function returns this string, then this * account has Local System privileges */ int HasSystemPrivilege(HANDLE hProcess) { DWORD i; DWORD dwSize = 0; DWORD dwRetval = 0; TCHAR privName[256]; DWORD dwNameSize = 256; //PTOKEN_PRIVILEGES tp = NULL; BYTE *pBuffer = NULL; TOKEN_PRIVILEGES* tp = NULL; HANDLE hToken = token_from_handle(hProcess); if (NULL == hToken) { return -1; } // call GetTokenInformation first to get the buffer size if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) { dwRetval = GetLastError(); // if it failed for a reason other than the buffer, bail out if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) { PyErr_SetFromWindowsErr(dwRetval); return 0; } } // allocate buffer and call GetTokenInformation again //tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize); pBuffer = (BYTE *) malloc(dwSize); if (pBuffer == NULL) { PyErr_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; } } //for free(pBuffer); return 0; } BOOL SetPrivilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) { TOKEN_PRIVILEGES tp; LUID luid; TOKEN_PRIVILEGES tpPrevious; DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES); if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE; // first pass. get current privilege setting tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = 0; AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious ); if (GetLastError() != ERROR_SUCCESS) return FALSE; // second pass. set privilege based on previous setting tpPrevious.PrivilegeCount = 1; tpPrevious.Privileges[0].Luid = luid; if(bEnablePrivilege) { tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED); } else { tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes); } AdjustTokenPrivileges( hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL ); if (GetLastError() != ERROR_SUCCESS) return FALSE; return TRUE; } int SetSeDebug() { HANDLE hToken; if(! OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ){ if (GetLastError() == ERROR_NO_TOKEN){ if (!ImpersonateSelf(SecurityImpersonation)){ CloseHandle(hToken); return 0; } if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ){ RevertToSelf(); CloseHandle(hToken); return 0; } } } // enable SeDebugPrivilege (open any process) if (! SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)){ RevertToSelf(); CloseHandle(hToken); return 0; } RevertToSelf(); CloseHandle(hToken); return 1; } int UnsetSeDebug() { HANDLE hToken; if(! OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ){ if(GetLastError() == ERROR_NO_TOKEN){ if(! ImpersonateSelf(SecurityImpersonation)){ //Log2File("Error setting impersonation! [UnsetSeDebug()]", L_DEBUG); return 0; } if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken) ){ //Log2File("Error Opening Thread Token! [UnsetSeDebug()]", L_DEBUG); return 0; } } } //now disable SeDebug if(!SetPrivilege(hToken, SE_DEBUG_NAME, FALSE)){ //Log2File("Error unsetting SeDebug Privilege [SetPrivilege()]", L_WARN); return 0; } CloseHandle(hToken); return 1; } psutil-1.2.1/psutil/arch/mswindows/process_info.c0000664000175000017500000003032712243206601024124 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_mswindows module methods. */ #include #include #include #include #include "security.h" #include "process_info.h" #include "ntextapi.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 (NULL == proclist) { return -1; } for (i = 0; i < numberOfReturnedPIDs; i++) { if (pid == proclist[i]) { free(proclist); return 1; } } free(proclist); return 0; } // Check exit code from a process handle. Return FALSE on an error also // 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_arg_list(long pid) { int nArgs, i; LPWSTR *szArglist = NULL; HANDLE hProcess = NULL; PVOID pebAddress; PVOID rtlUserProcParamsAddress; UNICODE_STRING commandLine; WCHAR *commandLineContents = NULL; PyObject *arg = NULL; PyObject *arg_from_wchar = NULL; PyObject *argList = NULL; hProcess = 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 { ////printf("Could not read CommandLine!\n"); 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)) { ////printf("Could not read the command line string!\n"); PyErr_SetFromWindowsErr(0); goto error; } /* print the commandline */ ////printf("%.*S\n", commandLine.Length / 2, commandLineContents); // null-terminate the string to prevent wcslen from returning incorrect length // the length specifier is in characters, but commandLine.Length is in bytes commandLineContents[(commandLine.Length/sizeof(WCHAR))] = '\0'; // attemempt tp parse the command line using Win32 API, fall back on string // cmdline version otherwise szArglist = CommandLineToArgvW(commandLineContents, &nArgs); if (NULL == szArglist) { // failed to parse arglist // encode as a UTF8 Python string object from WCHAR string arg_from_wchar = PyUnicode_FromWideChar(commandLineContents, commandLine.Length / 2); if (arg_from_wchar == NULL) goto error; #if PY_MAJOR_VERSION >= 3 argList = Py_BuildValue("N", PyUnicode_AsUTF8String(arg_from_wchar)); #else argList = Py_BuildValue("N", PyUnicode_FromObject(arg_from_wchar)); #endif if (!argList) goto error; } else { // arglist parsed as array of UNICODE_STRING, so convert each to Python // string object and add to arg list argList = Py_BuildValue("[]"); if (argList == NULL) goto error; for(i=0; i= 3 arg = PyUnicode_FromObject(arg_from_wchar); #else arg = PyUnicode_AsUTF8String(arg_from_wchar); #endif if (arg == NULL) goto error; Py_XDECREF(arg_from_wchar); if (PyList_Append(argList, arg)) goto error; Py_XDECREF(arg); } } if (szArglist != NULL) LocalFree(szArglist); free(commandLineContents); CloseHandle(hProcess); return argList; error: Py_XDECREF(arg); Py_XDECREF(arg_from_wchar); Py_XDECREF(argList); if (hProcess != NULL) CloseHandle(hProcess); if (commandLineContents != NULL) free(commandLineContents); if (szArglist != NULL) LocalFree(szArglist); return NULL; } #define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes)) #define PH_NEXT_PROCESS(Process) ( \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \ (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \ NULL \ ) const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; const STATUS_BUFFER_TOO_SMALL = 0xC0000023L; /* * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure * fills the structure with process information. * On success return 1, else 0 with Python exception already set. */ int get_process_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer) { static ULONG initialBufferSize = 0x4000; NTSTATUS status; PVOID buffer; ULONG bufferSize; PSYSTEM_PROCESS_INFORMATION process; // get NtQuerySystemInformation typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG); NTQSI_PROC NtQuerySystemInformation; HINSTANCE hNtDll; hNtDll = LoadLibrary(TEXT("ntdll.dll")); NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress( hNtDll, "NtQuerySystemInformation"); bufferSize = initialBufferSize; buffer = malloc(bufferSize); 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-1.2.1/psutil/arch/osx/0000775000175000017500000000000012244726663020061 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil/arch/osx/process_info.h0000664000175000017500000000121212243206601022677 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 typedef struct kinfo_proc kinfo_proc; int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount); int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp); int psutil_get_argmax(void); int psutil_pid_exists(long pid); int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size); PyObject* psutil_get_arg_list(long pid); psutil-1.2.1/psutil/arch/osx/process_info.c0000664000175000017500000001567612243206601022715 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. */ int psutil_pid_exists(long pid) { int kill_ret; // save some time if it's an invalid PID if (pid < 0) { return 0; } // if kill returns success of permission denied we know it's a valid PID kill_ret = kill(pid , 0); if ( (0 == kill_ret) || (EPERM == errno) ) { return 1; } // otherwise return 0 for PID not found return 0; } /* * Returns a list of all BSD processes on the system. This routine * allocates the list and puts it in *procList and a count of the * number of entries in *procCount. You are responsible for freeing * this list (use "free" from System framework). * On success, the function returns 0. * On error, the function returns a BSD errno value. */ int 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_arg_list(long pid) { int mib[3]; int nargs; int len; char *procargs = NULL; char *arg_ptr; char *arg_end; char *curr_arg; size_t argmax; PyObject *arg = NULL; PyObject *arglist = NULL; //special case for PID 0 (kernel_task) where cmdline cannot be fetched if (pid == 0) { return Py_BuildValue("[]"); } /* read argmax and allocate memory for argument space. */ argmax = 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) { // invalid == 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; arglist = Py_BuildValue("[]"); if (!arglist) goto error; while (arg_ptr < arg_end && nargs > 0) { if (*arg_ptr++ == '\0') { arg = Py_BuildValue("s", curr_arg); if (!arg) goto error; if (PyList_Append(arglist, arg)) goto error; Py_DECREF(arg); // iterate to next arg and decrement # of args curr_arg = arg_ptr; nargs--; } } free(procargs); return arglist; error: Py_XDECREF(arg); Py_XDECREF(arglist); if (procargs != NULL) free(procargs); return NULL; } int 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-1.2.1/psutil/arch/bsd/0000775000175000017500000000000012244726663020020 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil/arch/bsd/process_info.h0000664000175000017500000000114112243206601022637 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 typedef struct kinfo_proc kinfo_proc; int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount); char *psutil_get_cmd_args(long pid, size_t *argsize); char *psutil_get_cmd_path(long pid, size_t *pathsize); int psutil_pid_exists(long pid); PyObject* psutil_get_arg_list(long pid); psutil-1.2.1/psutil/arch/bsd/process_info.c0000664000175000017500000001576612243206601022654 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 "process_info.h" /* * Returns a list of all BSD processes on the system. This routine * allocates the list and puts it in *procList and a count of the * number of entries in *procCount. You are responsible for freeing * this list (use "free" from System framework). * On success, the function returns 0. * On error, the function returns a BSD errno value. */ int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) { int err; struct kinfo_proc * result; int done; static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; // Declaring name as const requires us to cast it when passing it to // sysctl because the prototype doesn't include the const modifier. size_t length; assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); *procCount = 0; /* * We start by calling sysctl with result == NULL and length == 0. * That will succeed, and set length to the appropriate length. * We then allocate a buffer of that size and call sysctl again * with that buffer. If that succeeds, we're done. If that fails * with ENOMEM, we have to throw away our buffer and loop. Note * that the loop causes use to call sysctl with NULL again; this * is necessary because the ENOMEM failure case sets length to * the amount of data returned, not the amount of data that * could have been returned. */ result = NULL; done = 0; do { assert(result == NULL); // Call sysctl with a NULL buffer. length = 0; err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); if (err == -1) err = errno; // Allocate an appropriately sized buffer based on the results // from the previous call. if (err == 0) { result = malloc(length); if (result == NULL) err = ENOMEM; } // Call sysctl again with the new buffer. If we get an ENOMEM // error, toss away our buffer and start again. if (err == 0) { err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1, result, &length, NULL, 0); if (err == -1) err = errno; if (err == 0) { done = 1; } else if (err == ENOMEM) { assert(result != NULL); free(result); result = NULL; err = 0; } } } while (err == 0 && ! done); // Clean up and establish post conditions. if (err != 0 && result != NULL) { free(result); result = NULL; } *procList = result; *procCount = length / sizeof(struct kinfo_proc); assert((err == 0) == (*procList != NULL)); return err; } char *psutil_get_cmd_path(long pid, size_t *pathsize) { int mib[4]; char *path; size_t size = 0; /* * Make a sysctl() call to get the raw argument space of the process. */ mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PATHNAME; mib[3] = pid; // call with a null buffer first to determine if we need a buffer if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) { return NULL; } path = malloc(size); if (path == NULL) { PyErr_NoMemory(); return NULL; } *pathsize = size; if (sysctl(mib, 4, path, &size, NULL, 0) == -1) { free(path); return NULL; /* Insufficient privileges */ } return path; } /* * 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. */ 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_arg_list(long pid) { char *argstr = NULL; int pos = 0; size_t argsize = 0; PyObject *retlist = Py_BuildValue("[]"); PyObject *item = NULL; if (pid < 0) { return retlist; } argstr = 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) { item = Py_BuildValue("s", &argstr[pos]); if (!item) goto error; if (PyList_Append(retlist, item)) goto error; Py_DECREF(item); pos = pos + strlen(&argstr[pos]) + 1; } } free(argstr); return retlist; error: Py_XDECREF(item); Py_DECREF(retlist); if (argstr != NULL) free(argstr); return NULL; } /* * Return 1 if PID exists in the current process list, else 0. */ int psutil_pid_exists(long pid) { int kill_ret; if (pid < 0) { return 0; } // if kill returns success of permission denied we know it's a valid PID kill_ret = kill(pid , 0); if ((0 == kill_ret) || (EPERM == errno)) { return 1; } // otherwise return 0 for PID not found return 0; } /* * Set exception to AccessDenied if pid exists else NoSuchProcess. */ int psutil_raise_ad_or_nsp(pid) { if (psutil_pid_exists(pid) == 0) { NoSuchProcess(); } else { AccessDenied(); } } psutil-1.2.1/psutil.egg-info/0000775000175000017500000000000012244726663020025 5ustar giampaologiampaolo00000000000000psutil-1.2.1/psutil.egg-info/SOURCES.txt0000664000175000017500000000264312244726663021716 0ustar giampaologiampaolo00000000000000CREDITS HISTORY LICENSE MANIFEST.in README TODO setup.py examples/disk_usage.py examples/free.py examples/iotop.py examples/killall.py examples/meminfo.py examples/netstat.py examples/nettop.py examples/pmap.py examples/process_detail.py examples/top.py examples/who.py psutil/__init__.py psutil/_common.py psutil/_compat.py psutil/_error.py psutil/_psbsd.py psutil/_pslinux.py psutil/_psmswindows.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_mswindows.c psutil/_psutil_mswindows.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/error.py psutil.egg-info/PKG-INFO psutil.egg-info/SOURCES.txt psutil.egg-info/dependency_links.txt psutil.egg-info/top_level.txt psutil/arch/bsd/process_info.c psutil/arch/bsd/process_info.h psutil/arch/mswindows/ntextapi.h psutil/arch/mswindows/process_handles.c psutil/arch/mswindows/process_handles.h psutil/arch/mswindows/process_info.c psutil/arch/mswindows/process_info.h psutil/arch/mswindows/security.c psutil/arch/mswindows/security.h psutil/arch/osx/process_info.c psutil/arch/osx/process_info.h test/__init__.py 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-1.2.1/psutil.egg-info/dependency_links.txt0000664000175000017500000000000112244726663024073 0ustar giampaologiampaolo00000000000000 psutil-1.2.1/psutil.egg-info/PKG-INFO0000664000175000017500000002607212244726663021131 0ustar giampaologiampaolo00000000000000Metadata-Version: 1.1 Name: psutil Version: 1.2.1 Summary: A process and system utilities module for Python Home-page: http://code.google.com/p/psutil/ Author: Giampaolo Rodola Author-email: g.rodola gmail com License: License :: OSI Approved :: BSD License Description: =========== Quick links =========== * `Home page `_ * `Download `_ * `Documentation `_ * `Forum `_ * `What's new `_ ======= Summary ======= psutil is a module providing an interface for retrieving information on all running processes and system utilization (CPU, memory, disks, network, users) in a portable way by using Python, implementing many functionalities offered by command line tools such as: **ps, top, df, kill, free, lsof, free, netstat, ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**. It currently supports **Linux**, **Windows**, **OSX**, **FreeBSD**, **Sun Solaris** both **32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using a single code base. ============== Example usages ============== CPU === >>> import psutil >>> psutil.cpu_times() cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.509, irq=0.0, softirq=19.422, 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] [7.0, 8.5] [1.2, 9.0] >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... cpupercent(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) cpupercent(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) cpupercent(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) Memory ====== >>> psutil.virtual_memory() vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336) >>> psutil.swap_memory() swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== >>> psutil.disk_partitions() [partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) iostat(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= >>> psutil.net_io_counters(pernic=True) {'eth0': iostat(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': iostat(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> Other system info ================= >>> psutil.get_users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.get_boot_time() 1365519115.0 >>> >>> psutil.NUM_CPUS 4 >>> psutil.TOTAL_PHYMEM 8374120448L >>> Process management ================== >>> import psutil >>> psutil.get_pid_list() [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071] >>> >>> p = psutil.Process(7055) >>> p.name 'python' >>> p.exe '/usr/bin/python' >>> p.getcwd() '/home/giampaolo' >>> p.cmdline ['/usr/bin/python', 'main.py'] >>> >>> str(p.status) 'running' >>> p.username 'giampaolo' >>> p.create_time 1267551141.5019531 >>> p.terminal '/dev/pts/0' >>> >>> p.uids user(real=1000, effective=1000, saved=1000) >>> p.gids group(real=1000, effective=1000, saved=1000) >>> >>> p.get_cpu_times() cputimes(user=1.02, system=0.31) >>> p.get_cpu_percent(interval=1.0) 12.1 >>> p.get_cpu_affinity() [0, 1, 2, 3] >>> p.set_cpu_affinity([0]) >>> >>> p.get_memory_percent() 0.63423 >>> >>> p.get_memory_info() meminfo(rss=7471104, vms=68513792) >>> p.get_ext_memory_info() meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.get_memory_maps() [mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), mmap(path='[heap]', rss=54653, anonymous=8192, swap=0), mmap(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.get_io_counters() io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.get_open_files() [openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.get_connections() [connection(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), connection(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), connection(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), connection(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.get_num_threads() 4 >>> p.get_num_fds() 8 >>> p.get_threads() [thread(id=5234, user_time=22.5, system_time=9.2891), thread(id=5235, user_time=0.0, system_time=0.0), thread(id=5236, user_time=0.0, system_time=0.0), thread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.get_num_ctx_switches() amount(voluntary=78, involuntary=19) >>> >>> p.get_nice() 0 >>> p.set_nice(10) >>> >>> p.set_ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Windows and Linux only) >>> p.get_ionice() ionice(ioclass=3, value=0) >>> >>> p.set_rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # resource limits (Linux only) >>> p.get_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 >>> Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,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 :: 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.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 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 :: Systems Administration Classifier: Topic :: Utilities psutil-1.2.1/psutil.egg-info/top_level.txt0000664000175000017500000000004312244726663022554 0ustar giampaologiampaolo00000000000000psutil _psutil_linux _psutil_posix psutil-1.2.1/TODO0000664000175000017500000001073712243743627015511 0ustar giampaologiampaolo00000000000000TODO ==== A collection of ideas and notes about stuff to implement in future versions. "#NNN" occurrences refer to bug tracker issues at: https://code.google.com/p/psutil/issues/list HIGHER PRIORITY =============== * #387: system-wide connections (netstat). * OpenBSD support. * #371: CPU temperature (apparently OSX and Linux only; on Linux it requires lm-sensors lib). * #250: net ifaces speed. * Process.name on Windows is slow: http://stackoverflow.com/questions/6587036/ * Windows binary for Python 3.3 64-bit. * #269: expose network ifaces RX/TW queues. LOWER PRIORITY ============== * #355: Android support. * #276: GNU/Hurd support. * NetBSD support? * DranflyBSD support? * AIX support? * examples/pidof.py (same as 'pidof' cli tool) * examples/pstree.py (same as 'pstree' cli tool) * get_threads() should also return thread names in order to implement it * examples/taskmgr-gui.py (using tk). * system-wide # 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. * thread names: * https://code.google.com/p/plcrashreporter/issues/detail?id=65 DEBATABLE ========= * [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. * cpu_percent(): current default interval is 0.1 so that by default it will produce a meaningful value. It represents a trap in case the user iterates over multiple processes though, as it introduces a big slowdown. Should it default to 0.0? * Rename connection ntuple's fields 'local_address', 'remote_address' to 'laddr', 'raddr' (note in accordance with http://bugs.python.org/issue17675) * Process per-cpus percent (XXX Windows only?), see: https://groups.google.com/forum/?fromgroups#!topic/psutil/ErrKTxAbu50 * 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 (XXX figure out which ones exactly) provide CPU times about process children. On those systems Process.get_cpu_times() might return a (user, system, user_children, system_children) ntuple. * 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.get_threads() might grow an extra "id" parameter so that it can be used as such: >>> p = psutil.Process(pid) >>> p.get_threads(id=psutil.get_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. * 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. Side note: tests' call_until() should raise TimeoutExpired instead of RuntimeError. COMPATIBILITY BREAKAGE ====================== H = higher priority ? = debatable Which can be safely removed (long deprecated): * psutil.Process.nice * get_process_list * psutil.*mem* functions * psutil.error.py Which can be safely renamed: * _psmswindows.py -> _pswindows.py * _psutil_mswindows.c -> _psutil_windows.c * _psutil_mswindows.h -> _psutil_windows.h Risky renames: * psutil.get_pid_list() -> psutil.get_pids() * psutil.Process.ppid -> get_ppid() * psutil.Process.status -> get_status() * psutil.Process.uids -> get_uids() * psutil.Process.gids -> get_gids() * psutil.Process.username -> get_username() * psutil.Process.getcwd -> get_cwd() psutil-1.2.1/CREDITS0000664000175000017500000000562412243206601016022 0ustar giampaologiampaolo00000000000000Intro ===== We would like to recognize some of the people who have been instrumental in the development of psutil. I'm sure we are forgetting some people (feel free to email us), but here is a short list. It's modeled after the Linux CREDITS file where the fields are: name (N), e-mail (E), web-address (W), country (C), description (D), (I) issues (issue tracker is at http://code.google.com/p/psutil/issues/list). Really thanks to all of you. Author ====== N: Giampaolo Rodola' C: Italy E: g.rodola@gmail.com W: http://www.linkedin.com/in/grodola Contributors ============ N: Jay Loden C: NJ, USA E: jloden@gmail.com D: original co-author, initial design/bootstrap and continuing bug fixes W: http://www.jayloden.com N: Jeremy Whitlock E: jcscoobyrs@gmail.com I: 125, 150, 174, 206 N: wj32 E: wj32.64@gmail.com D: process username() and get_connections() on Windows I: 114, 115 N: Yan Raber C: Bologna, Italy E: yanraber@gmail.com D: help on Windows development N: Justin Venus E: justin.venus@gmail.com D: Solaris support I: 18 N: Dave Daeschler C: USA E: david.daeschler@gmail.com D: initial design/bootstrap and continuing bug fixes N: cjgohlke E: cjgohlke@gmail.com D: Windows 64 bit support I: 107 N: Jeffery Kline E: jeffery.kline@gmail.com I: 130 N: Grabriel Monnerat E: gabrielmonnerat@gmail.com I: 146 N: Philip Roberts E: philip.roberts@gmail.com I: 168 N: jcscoobyrs E: jcscoobyrs@gmail.com I: 125 N: Sandro Tosi E: sandro.tosi@gmail.com I: 200, 201 N: Andrew Colin E: andrew.colin@gmail.com I: 248 N: Amoser E: amoser@google.com I: 266, 267, 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: 438psutil-1.2.1/MANIFEST.in0000664000175000017500000000032312243206601016527 0ustar giampaologiampaolo00000000000000include CREDITS include HISTORY include LICENSE include MANIFEST.in include README include TODO include setup.py recursive-include psutil *.py *.c *.h recursive-include test *.py recursive-include examples *.py psutil-1.2.1/README0000664000175000017500000001604212243206601015656 0ustar giampaologiampaolo00000000000000=========== Quick links =========== * `Home page `_ * `Download `_ * `Documentation `_ * `Forum `_ * `What's new `_ ======= Summary ======= psutil is a module providing an interface for retrieving information on all running processes and system utilization (CPU, memory, disks, network, users) in a portable way by using Python, implementing many functionalities offered by command line tools such as: **ps, top, df, kill, free, lsof, free, netstat, ifconfig, nice, ionice, iostat, iotop, uptime, pidof, tty, who, taskset, pmap**. It currently supports **Linux**, **Windows**, **OSX**, **FreeBSD**, **Sun Solaris** both **32-bit** and **64-bit** with Python versions from **2.4** to **3.3** by using a single code base. ============== Example usages ============== CPU === >>> import psutil >>> psutil.cpu_times() cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.509, irq=0.0, softirq=19.422, 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] [7.0, 8.5] [1.2, 9.0] >>> >>> for x in range(3): ... psutil.cpu_times_percent(interval=1, percpu=False) ... cpupercent(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) cpupercent(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) cpupercent(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) Memory ====== >>> psutil.virtual_memory() vmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336) >>> psutil.swap_memory() swap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944) >>> Disks ===== >>> psutil.disk_partitions() [partition(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'), partition(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')] >>> >>> psutil.disk_usage('/') usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5) >>> >>> psutil.disk_io_counters(perdisk=False) iostat(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568) >>> Network ======= >>> psutil.net_io_counters(pernic=True) {'eth0': iostat(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0), 'lo': iostat(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)} >>> Other system info ================= >>> psutil.get_users() [user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0), user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)] >>> >>> psutil.get_boot_time() 1365519115.0 >>> >>> psutil.NUM_CPUS 4 >>> psutil.TOTAL_PHYMEM 8374120448L >>> Process management ================== >>> import psutil >>> psutil.get_pid_list() [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071] >>> >>> p = psutil.Process(7055) >>> p.name 'python' >>> p.exe '/usr/bin/python' >>> p.getcwd() '/home/giampaolo' >>> p.cmdline ['/usr/bin/python', 'main.py'] >>> >>> str(p.status) 'running' >>> p.username 'giampaolo' >>> p.create_time 1267551141.5019531 >>> p.terminal '/dev/pts/0' >>> >>> p.uids user(real=1000, effective=1000, saved=1000) >>> p.gids group(real=1000, effective=1000, saved=1000) >>> >>> p.get_cpu_times() cputimes(user=1.02, system=0.31) >>> p.get_cpu_percent(interval=1.0) 12.1 >>> p.get_cpu_affinity() [0, 1, 2, 3] >>> p.set_cpu_affinity([0]) >>> >>> p.get_memory_percent() 0.63423 >>> >>> p.get_memory_info() meminfo(rss=7471104, vms=68513792) >>> p.get_ext_memory_info() meminfo(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0) >>> p.get_memory_maps() [mmap(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0), mmap(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0), mmap(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0), mmap(path='[heap]', rss=54653, anonymous=8192, swap=0), mmap(path='[stack]', rss=1542, anonymous=166, swap=0), ...] >>> >>> p.get_io_counters() io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632) >>> >>> p.get_open_files() [openfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)] >>> >>> p.get_connections() [connection(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'), connection(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'), connection(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'), connection(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')] >>> >>> p.get_num_threads() 4 >>> p.get_num_fds() 8 >>> p.get_threads() [thread(id=5234, user_time=22.5, system_time=9.2891), thread(id=5235, user_time=0.0, system_time=0.0), thread(id=5236, user_time=0.0, system_time=0.0), thread(id=5237, user_time=0.0707, system_time=1.1)] >>> >>> p.get_num_ctx_switches() amount(voluntary=78, involuntary=19) >>> >>> p.get_nice() 0 >>> p.set_nice(10) >>> >>> p.set_ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Windows and Linux only) >>> p.get_ionice() ionice(ioclass=3, value=0) >>> >>> p.set_rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # resource limits (Linux only) >>> p.get_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 >>>