psutil for windows

Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
This commit is contained in:
2018-03-08 07:44:30 -05:00
parent bc370b76fc
commit b2f054253e
45 changed files with 3 additions and 24800 deletions
-2376
View File
File diff suppressed because it is too large Load Diff
-449
View File
@@ -1,449 +0,0 @@
# 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 __init__.py and _ps*.py modules."""
from __future__ import division
import contextlib
import errno
import functools
import os
import socket
import stat
import sys
import warnings
from collections import namedtuple
from socket import AF_INET
from socket import SOCK_DGRAM
from socket import SOCK_STREAM
try:
from socket import AF_INET6
except ImportError:
AF_INET6 = None
try:
from socket import AF_UNIX
except ImportError:
AF_UNIX = None
if sys.version_info >= (3, 4):
import enum
else:
enum = None
__all__ = [
# OS constants
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS',
'WINDOWS',
# connection constants
'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT',
# net constants
'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN',
# process status constants
'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED',
'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED',
'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL',
'STATUS_WAKING', 'STATUS_ZOMBIE',
# named tuples
'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile',
'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart',
'sdiskusage', 'snetio', 'snic', 'snicstats', 'sswap', 'suser',
# utility functions
'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize',
'parse_environ_block', 'path_exists_strict', 'usage_percent',
'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum',
]
# ===================================================================
# --- OS constants
# ===================================================================
POSIX = os.name == "posix"
WINDOWS = os.name == "nt"
LINUX = sys.platform.startswith("linux")
OSX = sys.platform.startswith("darwin")
FREEBSD = sys.platform.startswith("freebsd")
OPENBSD = sys.platform.startswith("openbsd")
NETBSD = sys.platform.startswith("netbsd")
BSD = FREEBSD or OPENBSD or NETBSD
SUNOS = sys.platform.startswith("sunos") or sys.platform.startswith("solaris")
# ===================================================================
# --- API constants
# ===================================================================
# Process.status()
STATUS_RUNNING = "running"
STATUS_SLEEPING = "sleeping"
STATUS_DISK_SLEEP = "disk-sleep"
STATUS_STOPPED = "stopped"
STATUS_TRACING_STOP = "tracing-stop"
STATUS_ZOMBIE = "zombie"
STATUS_DEAD = "dead"
STATUS_WAKE_KILL = "wake-kill"
STATUS_WAKING = "waking"
STATUS_IDLE = "idle" # FreeBSD, OSX
STATUS_LOCKED = "locked" # FreeBSD
STATUS_WAITING = "waiting" # FreeBSD
STATUS_SUSPENDED = "suspended" # NetBSD
# Process.connections() and psutil.net_connections()
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"
# net_if_stats()
if enum is None:
NIC_DUPLEX_FULL = 2
NIC_DUPLEX_HALF = 1
NIC_DUPLEX_UNKNOWN = 0
else:
class NicDuplex(enum.IntEnum):
NIC_DUPLEX_FULL = 2
NIC_DUPLEX_HALF = 1
NIC_DUPLEX_UNKNOWN = 0
globals().update(NicDuplex.__members__)
# sensors_battery()
if enum is None:
POWER_TIME_UNKNOWN = -1
POWER_TIME_UNLIMITED = -2
else:
class BatteryTime(enum.IntEnum):
POWER_TIME_UNKNOWN = -1
POWER_TIME_UNLIMITED = -2
globals().update(BatteryTime.__members__)
# ===================================================================
# --- namedtuples
# ===================================================================
# --- for system functions
# psutil.swap_memory()
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
'sout'])
# psutil.disk_usage()
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
# psutil.disk_io_counters()
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
'read_bytes', 'write_bytes',
'read_time', 'write_time'])
# psutil.disk_partitions()
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
# psutil.net_io_counters()
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
'packets_sent', 'packets_recv',
'errin', 'errout',
'dropin', 'dropout'])
# psutil.users()
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started'])
# psutil.net_connections()
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
'status', 'pid'])
# psutil.net_if_addrs()
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
# psutil.net_if_stats()
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
# psutil.cpu_stats()
scpustats = namedtuple(
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
# psutil.cpu_freq()
scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
# psutil.sensors_temperatures()
shwtemp = namedtuple(
'shwtemp', ['label', 'current', 'high', 'critical'])
# psutil.sensors_battery()
sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
# psutil.sensors_battery()
sfan = namedtuple('sfan', ['label', 'current'])
# --- for Process methods
# psutil.Process.cpu_times()
pcputimes = namedtuple('pcputimes',
['user', 'system', 'children_user', 'children_system'])
# psutil.Process.open_files()
popenfile = namedtuple('popenfile', ['path', 'fd'])
# psutil.Process.threads()
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
# psutil.Process.uids()
puids = namedtuple('puids', ['real', 'effective', 'saved'])
# psutil.Process.gids()
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
# psutil.Process.io_counters()
pio = namedtuple('pio', ['read_count', 'write_count',
'read_bytes', 'write_bytes'])
# psutil.Process.ionice()
pionice = namedtuple('pionice', ['ioclass', 'value'])
# psutil.Process.ctx_switches()
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
# psutil.Process.connections()
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
'status'])
# ===================================================================
# --- Process.connections() 'kind' parameter mapping
# ===================================================================
conn_tmap = {
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
"tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]),
"tcp4": ([AF_INET], [SOCK_STREAM]),
"udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]),
"udp4": ([AF_INET], [SOCK_DGRAM]),
"inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
"inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
"inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
}
if AF_INET6 is not None:
conn_tmap.update({
"tcp6": ([AF_INET6], [SOCK_STREAM]),
"udp6": ([AF_INET6], [SOCK_DGRAM]),
})
if AF_UNIX is not None:
conn_tmap.update({
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
})
del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
# ===================================================================
# --- utils
# ===================================================================
def usage_percent(used, total, _round=None):
"""Calculate percentage usage of 'used' against 'total'."""
try:
ret = (used / total) * 100
except ZeroDivisionError:
ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
if _round is not None:
return round(ret, _round)
else:
return ret
def memoize(fun):
"""A simple memoize decorator for functions supporting (hashable)
positional arguments.
It also provides a cache_clear() function for clearing the cache:
>>> @memoize
... def foo()
... return 1
...
>>> foo()
1
>>> foo.cache_clear()
>>>
"""
@functools.wraps(fun)
def wrapper(*args, **kwargs):
key = (args, frozenset(sorted(kwargs.items())))
try:
return cache[key]
except KeyError:
ret = cache[key] = fun(*args, **kwargs)
return ret
def cache_clear():
"""Clear cache."""
cache.clear()
cache = {}
wrapper.cache_clear = cache_clear
return wrapper
def memoize_when_activated(fun):
"""A memoize decorator which is disabled by default. It can be
activated and deactivated on request.
For efficiency reasons it can be used only against class methods
accepting no arguments.
>>> class Foo:
... @memoize
... def foo()
... print(1)
...
>>> f = Foo()
>>> # deactivated (default)
>>> foo()
1
>>> foo()
1
>>>
>>> # activated
>>> foo.cache_activate()
>>> foo()
1
>>> foo()
>>> foo()
>>>
"""
@functools.wraps(fun)
def wrapper(self):
if not wrapper.cache_activated:
return fun(self)
else:
try:
ret = cache[fun]
except KeyError:
ret = cache[fun] = fun(self)
return ret
def cache_activate():
"""Activate cache."""
wrapper.cache_activated = True
def cache_deactivate():
"""Deactivate and clear cache."""
wrapper.cache_activated = False
cache.clear()
cache = {}
wrapper.cache_activated = False
wrapper.cache_activate = cache_activate
wrapper.cache_deactivate = cache_deactivate
return wrapper
def isfile_strict(path):
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
exceptions, see:
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
"""
try:
st = os.stat(path)
except OSError as err:
if err.errno in (errno.EPERM, errno.EACCES):
raise
return False
else:
return stat.S_ISREG(st.st_mode)
def path_exists_strict(path):
"""Same as os.path.exists() but does not swallow EACCES / EPERM
exceptions, see:
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
"""
try:
os.stat(path)
except OSError as err:
if err.errno in (errno.EPERM, errno.EACCES):
raise
return False
else:
return True
def supports_ipv6():
"""Return True if IPv6 is supported on this platform."""
if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
return False
try:
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
with contextlib.closing(sock):
sock.bind(("::1", 0))
return True
except socket.error:
return False
def parse_environ_block(data):
"""Parse a C environ block of environment variables into a dictionary."""
# The block is usually raw data from the target process. It might contain
# trailing garbage and lines that do not look like assignments.
ret = {}
pos = 0
# localize global variable to speed up access.
WINDOWS_ = WINDOWS
while True:
next_pos = data.find("\0", pos)
# nul byte at the beginning or double nul byte means finish
if next_pos <= pos:
break
# there might not be an equals sign
equal_pos = data.find("=", pos, next_pos)
if equal_pos > pos:
key = data[pos:equal_pos]
value = data[equal_pos + 1:next_pos]
# Windows expects environment variables to be uppercase only
if WINDOWS_:
key = key.upper()
ret[key] = value
pos = next_pos + 1
return ret
def sockfam_to_enum(num):
"""Convert a numeric socket family value to an IntEnum member.
If it's not a known member, return the numeric value itself.
"""
if enum is None:
return num
else: # pragma: no cover
try:
return socket.AddressFamily(num)
except (ValueError, AttributeError):
return num
def socktype_to_enum(num):
"""Convert a numeric socket type value to an IntEnum member.
If it's not a known member, return the numeric value itself.
"""
if enum is None:
return num
else: # pragma: no cover
try:
return socket.AddressType(num)
except (ValueError, AttributeError):
return num
def deprecated_method(replacement):
"""A decorator which can be used to mark a method as deprecated
'replcement' is the method name which will be called instead.
"""
def outer(fun):
msg = "%s() is deprecated; use %s() instead" % (
fun.__name__, replacement)
if fun.__doc__ is None:
fun.__doc__ = msg
@functools.wraps(fun)
def inner(self, *args, **kwargs):
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
return getattr(self, replacement)(*args, **kwargs)
return inner
return outer
-249
View File
@@ -1,249 +0,0 @@
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Module which provides compatibility with older Python versions."""
import collections
import functools
import os
import sys
__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b",
"callable", "lru_cache", "which"]
PY3 = sys.version_info[0] == 3
if PY3:
long = int
xrange = range
unicode = str
basestring = str
def u(s):
return s
def b(s):
return s.encode("latin-1")
else:
long = long
xrange = xrange
unicode = unicode
basestring = basestring
def u(s):
return unicode(s, "unicode_escape")
def b(s):
return s
# removed in 3.0, reintroduced in 3.2
try:
callable = callable
except NameError:
def callable(obj):
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
# --- stdlib additions
# py 3.2 functools.lru_cache
# Taken from: http://code.activestate.com/recipes/578078
# Credit: Raymond Hettinger
try:
from functools import lru_cache
except ImportError:
try:
from threading import RLock
except ImportError:
from dummy_threading import RLock
_CacheInfo = collections.namedtuple(
"CacheInfo", ["hits", "misses", "maxsize", "currsize"])
class _HashedSeq(list):
__slots__ = 'hashvalue'
def __init__(self, tup, hash=hash):
self[:] = tup
self.hashvalue = hash(tup)
def __hash__(self):
return self.hashvalue
def _make_key(args, kwds, typed,
kwd_mark=(object(), ),
fasttypes=set((int, str, frozenset, type(None))),
sorted=sorted, tuple=tuple, type=type, len=len):
key = args
if kwds:
sorted_items = sorted(kwds.items())
key += kwd_mark
for item in sorted_items:
key += item
if typed:
key += tuple(type(v) for v in args)
if kwds:
key += tuple(type(v) for k, v in sorted_items)
elif len(key) == 1 and type(key[0]) in fasttypes:
return key[0]
return _HashedSeq(key)
def lru_cache(maxsize=100, typed=False):
"""Least-recently-used cache decorator, see:
http://docs.python.org/3/library/functools.html#functools.lru_cache
"""
def decorating_function(user_function):
cache = dict()
stats = [0, 0]
HITS, MISSES = 0, 1
make_key = _make_key
cache_get = cache.get
_len = len
lock = RLock()
root = []
root[:] = [root, root, None, None]
nonlocal_root = [root]
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
if maxsize == 0:
def wrapper(*args, **kwds):
result = user_function(*args, **kwds)
stats[MISSES] += 1
return result
elif maxsize is None:
def wrapper(*args, **kwds):
key = make_key(args, kwds, typed)
result = cache_get(key, root)
if result is not root:
stats[HITS] += 1
return result
result = user_function(*args, **kwds)
cache[key] = result
stats[MISSES] += 1
return result
else:
def wrapper(*args, **kwds):
if kwds or typed:
key = make_key(args, kwds, typed)
else:
key = args
lock.acquire()
try:
link = cache_get(key)
if link is not None:
root, = nonlocal_root
link_prev, link_next, key, result = link
link_prev[NEXT] = link_next
link_next[PREV] = link_prev
last = root[PREV]
last[NEXT] = root[PREV] = link
link[PREV] = last
link[NEXT] = root
stats[HITS] += 1
return result
finally:
lock.release()
result = user_function(*args, **kwds)
lock.acquire()
try:
root, = nonlocal_root
if key in cache:
pass
elif _len(cache) >= maxsize:
oldroot = root
oldroot[KEY] = key
oldroot[RESULT] = result
root = nonlocal_root[0] = oldroot[NEXT]
oldkey = root[KEY]
root[KEY] = root[RESULT] = None
del cache[oldkey]
cache[key] = oldroot
else:
last = root[PREV]
link = [last, root, key, result]
last[NEXT] = root[PREV] = cache[key] = link
stats[MISSES] += 1
finally:
lock.release()
return result
def cache_info():
"""Report cache statistics"""
lock.acquire()
try:
return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
len(cache))
finally:
lock.release()
def cache_clear():
"""Clear the cache and cache statistics"""
lock.acquire()
try:
cache.clear()
root = nonlocal_root[0]
root[:] = [root, root, None, None]
stats[:] = [0, 0]
finally:
lock.release()
wrapper.__wrapped__ = user_function
wrapper.cache_info = cache_info
wrapper.cache_clear = cache_clear
return functools.update_wrapper(wrapper, user_function)
return decorating_function
# python 3.3
try:
from shutil import which
except ImportError:
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
"""Given a command, mode, and a PATH string, return the path which
conforms to the given mode on the PATH, or None if there is no such
file.
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
of os.environ.get("PATH"), or can be overridden with a custom search
path.
"""
def _access_check(fn, mode):
return (os.path.exists(fn) and os.access(fn, mode) and
not os.path.isdir(fn))
if os.path.dirname(cmd):
if _access_check(cmd, mode):
return cmd
return None
if path is None:
path = os.environ.get("PATH", os.defpath)
if not path:
return None
path = path.split(os.pathsep)
if sys.platform == "win32":
if os.curdir not in path:
path.insert(0, os.curdir)
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
files = [cmd]
else:
files = [cmd + ext for ext in pathext]
else:
files = [cmd]
seen = set()
for dir in path:
normdir = os.path.normcase(dir)
if normdir not in seen:
seen.add(normdir)
for thefile in files:
name = os.path.join(dir, thefile)
if _access_check(name, mode):
return name
return None
-855
View File
@@ -1,855 +0,0 @@
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""FreeBSD, OpenBSD and NetBSD platforms implementation."""
import contextlib
import errno
import functools
import os
import xml.etree.ElementTree as ET
from collections import namedtuple
from . import _common
from . import _psposix
from . import _psutil_bsd as cext
from . import _psutil_posix as cext_posix
from ._common import conn_tmap
from ._common import FREEBSD
from ._common import memoize
from ._common import memoize_when_activated
from ._common import NETBSD
from ._common import OPENBSD
from ._common import sockfam_to_enum
from ._common import socktype_to_enum
from ._common import usage_percent
from ._compat import which
__extra__all__ = []
# =====================================================================
# --- globals
# =====================================================================
if FREEBSD:
PROC_STATUSES = {
cext.SIDL: _common.STATUS_IDLE,
cext.SRUN: _common.STATUS_RUNNING,
cext.SSLEEP: _common.STATUS_SLEEPING,
cext.SSTOP: _common.STATUS_STOPPED,
cext.SZOMB: _common.STATUS_ZOMBIE,
cext.SWAIT: _common.STATUS_WAITING,
cext.SLOCK: _common.STATUS_LOCKED,
}
elif OPENBSD or NETBSD:
PROC_STATUSES = {
cext.SIDL: _common.STATUS_IDLE,
cext.SSLEEP: _common.STATUS_SLEEPING,
cext.SSTOP: _common.STATUS_STOPPED,
# According to /usr/include/sys/proc.h SZOMB is unused.
# test_zombie_process() shows that SDEAD is the right
# equivalent. Also it appears there's no equivalent of
# psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE.
# cext.SZOMB: _common.STATUS_ZOMBIE,
cext.SDEAD: _common.STATUS_ZOMBIE,
cext.SZOMB: _common.STATUS_ZOMBIE,
# From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt
# OpenBSD has SRUN and SONPROC: SRUN indicates that a process
# is runnable but *not* yet running, i.e. is on a run queue.
# SONPROC indicates that the process is actually executing on
# a CPU, i.e. it is no longer on a run queue.
# As such we'll map SRUN to STATUS_WAKING and SONPROC to
# STATUS_RUNNING
cext.SRUN: _common.STATUS_WAKING,
cext.SONPROC: _common.STATUS_RUNNING,
}
elif NETBSD:
PROC_STATUSES = {
cext.SIDL: _common.STATUS_IDLE,
cext.SACTIVE: _common.STATUS_RUNNING,
cext.SDYING: _common.STATUS_ZOMBIE,
cext.SSTOP: _common.STATUS_STOPPED,
cext.SZOMB: _common.STATUS_ZOMBIE,
cext.SDEAD: _common.STATUS_DEAD,
cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD
}
TCP_STATUSES = {
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
cext.TCPS_CLOSED: _common.CONN_CLOSE,
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
cext.TCPS_LISTEN: _common.CONN_LISTEN,
cext.TCPS_CLOSING: _common.CONN_CLOSING,
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
}
if NETBSD:
PAGESIZE = os.sysconf("SC_PAGESIZE")
else:
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
AF_LINK = cext_posix.AF_LINK
kinfo_proc_map = dict(
ppid=0,
status=1,
real_uid=2,
effective_uid=3,
saved_uid=4,
real_gid=5,
effective_gid=6,
saved_gid=7,
ttynr=8,
create_time=9,
ctx_switches_vol=10,
ctx_switches_unvol=11,
read_io_count=12,
write_io_count=13,
user_time=14,
sys_time=15,
ch_user_time=16,
ch_sys_time=17,
rss=18,
vms=19,
memtext=20,
memdata=21,
memstack=22,
cpunum=23,
name=24,
)
# these get overwritten on "import psutil" from the __init__.py file
NoSuchProcess = None
ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
# =====================================================================
# --- named tuples
# =====================================================================
# psutil.virtual_memory()
svmem = namedtuple(
'svmem', ['total', 'available', 'percent', 'used', 'free',
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
# psutil.cpu_times()
scputimes = namedtuple(
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
# psutil.Process.memory_info()
pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack'])
# psutil.Process.memory_full_info()
pfullmem = pmem
# psutil.Process.cpu_times()
pcputimes = namedtuple('pcputimes',
['user', 'system', 'children_user', 'children_system'])
# psutil.Process.memory_maps(grouped=True)
pmmap_grouped = namedtuple(
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
# psutil.Process.memory_maps(grouped=False)
pmmap_ext = namedtuple(
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
# psutil.disk_io_counters()
if FREEBSD:
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
'read_bytes', 'write_bytes',
'read_time', 'write_time',
'busy_time'])
else:
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
'read_bytes', 'write_bytes'])
# =====================================================================
# --- memory
# =====================================================================
def virtual_memory():
"""System virtual memory as a namedtuple."""
mem = cext.virtual_mem()
total, free, active, inactive, wired, cached, buffers, shared = mem
if NETBSD:
# On NetBSD buffers and shared mem is determined via /proc.
# The C ext set them to 0.
with open('/proc/meminfo', 'rb') as f:
for line in f:
if line.startswith(b'Buffers:'):
buffers = int(line.split()[1]) * 1024
elif line.startswith(b'MemShared:'):
shared = int(line.split()[1]) * 1024
avail = inactive + cached + free
used = active + wired + cached
percent = usage_percent((total - avail), total, _round=1)
return svmem(total, avail, percent, used, free,
active, inactive, buffers, cached, shared, wired)
def swap_memory():
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
total, used, free, sin, sout = cext.swap_mem()
percent = usage_percent(used, total, _round=1)
return _common.sswap(total, used, free, percent, sin, sout)
# =====================================================================
# --- CPU
# =====================================================================
def cpu_times():
"""Return system per-CPU times as a namedtuple"""
user, nice, system, idle, irq = cext.cpu_times()
return scputimes(user, nice, system, idle, irq)
if hasattr(cext, "per_cpu_times"):
def per_cpu_times():
"""Return system CPU times as a namedtuple"""
ret = []
for cpu_t in cext.per_cpu_times():
user, nice, system, idle, irq = cpu_t
item = scputimes(user, nice, system, idle, irq)
ret.append(item)
return ret
else:
# XXX
# Ok, this is very dirty.
# On FreeBSD < 8 we cannot gather per-cpu information, see:
# https://github.com/giampaolo/psutil/issues/226
# If num cpus > 1, on first call we return single cpu times to avoid a
# crash at psutil import time.
# Next calls will fail with NotImplementedError
def per_cpu_times():
"""Return system CPU times as a namedtuple"""
if cpu_count_logical() == 1:
return [cpu_times()]
if per_cpu_times.__called__:
raise NotImplementedError("supported only starting from FreeBSD 8")
per_cpu_times.__called__ = True
return [cpu_times()]
per_cpu_times.__called__ = False
def cpu_count_logical():
"""Return the number of logical CPUs in the system."""
return cext.cpu_count_logical()
if OPENBSD or NETBSD:
def cpu_count_physical():
# OpenBSD and NetBSD do not implement this.
return 1 if cpu_count_logical() == 1 else None
else:
def cpu_count_physical():
"""Return the number of physical CPUs in the system."""
# From the C module we'll get an XML string similar to this:
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
# We may get None in case "sysctl kern.sched.topology_spec"
# is not supported on this BSD version, in which case we'll mimic
# os.cpu_count() and return None.
ret = None
s = cext.cpu_count_phys()
if s is not None:
# get rid of padding chars appended at the end of the string
index = s.rfind("</groups>")
if index != -1:
s = s[:index + 9]
root = ET.fromstring(s)
try:
ret = len(root.findall('group/children/group/cpu')) or None
finally:
# needed otherwise it will memleak
root.clear()
if not ret:
# If logical CPUs are 1 it's obvious we'll have only 1
# physical CPU.
if cpu_count_logical() == 1:
return 1
return ret
def cpu_stats():
"""Return various CPU stats as a named tuple."""
if FREEBSD:
# Note: the C ext is returning some metrics we are not exposing:
# traps.
ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats()
elif NETBSD:
# XXX
# Note about intrs: the C extension returns 0. intrs
# can be determined via /proc/stat; it has the same value as
# soft_intrs thought so the kernel is faking it (?).
#
# Note about syscalls: the C extension always sets it to 0 (?).
#
# Note: the C ext is returning some metrics we are not exposing:
# traps, faults and forks.
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
cext.cpu_stats()
with open('/proc/stat', 'rb') as f:
for line in f:
if line.startswith(b'intr'):
intrs = int(line.split()[1])
elif OPENBSD:
# Note: the C ext is returning some metrics we are not exposing:
# traps, faults and forks.
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
cext.cpu_stats()
return _common.scpustats(ctxsw, intrs, soft_intrs, syscalls)
# =====================================================================
# --- disks
# =====================================================================
def disk_partitions(all=False):
"""Return mounted disk partitions as a list of namedtuples.
'all' argument is ignored, see:
https://github.com/giampaolo/psutil/issues/906
"""
retlist = []
partitions = cext.disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
disk_usage = _psposix.disk_usage
disk_io_counters = cext.disk_io_counters
# =====================================================================
# --- network
# =====================================================================
net_io_counters = cext.net_io_counters
net_if_addrs = cext_posix.net_if_addrs
def net_if_stats():
"""Get NIC stats (isup, duplex, speed, mtu)."""
names = net_io_counters().keys()
ret = {}
for name in names:
mtu = cext_posix.net_if_mtu(name)
isup = cext_posix.net_if_flags(name)
duplex, speed = cext_posix.net_if_duplex_speed(name)
if hasattr(_common, 'NicDuplex'):
duplex = _common.NicDuplex(duplex)
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
def net_connections(kind):
"""System-wide network connections."""
if OPENBSD:
ret = []
for pid in pids():
try:
cons = Process(pid).connections(kind)
except (NoSuchProcess, ZombieProcess):
continue
else:
for conn in cons:
conn = list(conn)
conn.append(pid)
ret.append(_common.sconn(*conn))
return ret
if kind not in _common.conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
ret = set()
if NETBSD:
rawlist = cext.net_connections(-1)
else:
rawlist = cext.net_connections()
for item in rawlist:
fd, fam, type, laddr, raddr, status, pid = item
# TODO: apply filter at C level
if fam in families and type in types:
try:
status = TCP_STATUSES[status]
except KeyError:
# XXX: Not sure why this happens. I saw this occurring
# with IPv6 sockets opened by 'vim'. Those sockets
# have a very short lifetime so maybe the kernel
# can't initialize their status?
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
fam = sockfam_to_enum(fam)
type = socktype_to_enum(type)
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
ret.add(nt)
return list(ret)
# =====================================================================
# --- sensors
# =====================================================================
if FREEBSD:
def sensors_battery():
"""Return battery info."""
percent, minsleft, power_plugged = cext.sensors_battery()
power_plugged = power_plugged == 1
if power_plugged:
secsleft = _common.POWER_TIME_UNLIMITED
elif minsleft == -1:
secsleft = _common.POWER_TIME_UNKNOWN
else:
secsleft = minsleft * 60
return _common.sbattery(percent, secsleft, power_plugged)
# =====================================================================
# --- other system functions
# =====================================================================
def boot_time():
"""The system boot time expressed in seconds since the epoch."""
return cext.boot_time()
def users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = cext.users()
for item in rawlist:
user, tty, hostname, tstamp = item
if tty == '~':
continue # reboot or shutdown
nt = _common.suser(user, tty or None, hostname, tstamp)
retlist.append(nt)
return retlist
# =====================================================================
# --- processes
# =====================================================================
@memoize
def _pid_0_exists():
try:
Process(0).name()
except NoSuchProcess:
return False
except AccessDenied:
return True
else:
return True
def pids():
"""Returns a list of PIDs currently running on the system."""
ret = cext.pids()
if OPENBSD and (0 not in ret) and _pid_0_exists():
# On OpenBSD the kernel does not return PID 0 (neither does
# ps) but it's actually querable (Process(0) will succeed).
ret.insert(0, 0)
return ret
if OPENBSD or NETBSD:
def pid_exists(pid):
"""Return True if pid exists."""
exists = _psposix.pid_exists(pid)
if not exists:
# We do this because _psposix.pid_exists() lies in case of
# zombie processes.
return pid in pids()
else:
return True
else:
pid_exists = _psposix.pid_exists
def wrap_exceptions(fun):
"""Decorator which translates bare OSError exceptions into
NoSuchProcess and AccessDenied.
"""
@functools.wraps(fun)
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except OSError as err:
if self.pid == 0:
if 0 in pids():
raise AccessDenied(self.pid, self._name)
else:
raise
if err.errno == errno.ESRCH:
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
else:
raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
return wrapper
@contextlib.contextmanager
def wrap_exceptions_procfs(inst):
"""Same as above, for routines relying on reading /proc fs."""
try:
yield
except EnvironmentError as err:
# ENOENT (no such file or directory) gets raised on open().
# ESRCH (no such process) can get raised on read() if
# process is gone in meantime.
if err.errno in (errno.ENOENT, errno.ESRCH):
if not pid_exists(inst.pid):
raise NoSuchProcess(inst.pid, inst._name)
else:
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(inst.pid, inst._name)
raise
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
self._ppid = None
@memoize_when_activated
def oneshot(self):
"""Retrieves multiple process info in one shot as a raw tuple."""
ret = cext.proc_oneshot_info(self.pid)
assert len(ret) == len(kinfo_proc_map)
return ret
def oneshot_enter(self):
self.oneshot.cache_activate()
def oneshot_exit(self):
self.oneshot.cache_deactivate()
@wrap_exceptions
def name(self):
name = self.oneshot()[kinfo_proc_map['name']]
return name if name is not None else cext.proc_name(self.pid)
@wrap_exceptions
def exe(self):
if FREEBSD:
return cext.proc_exe(self.pid)
elif NETBSD:
if self.pid == 0:
# /proc/0 dir exists but /proc/0/exe doesn't
return ""
with wrap_exceptions_procfs(self):
return os.readlink("/proc/%s/exe" % self.pid)
else:
# OpenBSD: exe cannot be determined; references:
# https://chromium.googlesource.com/chromium/src/base/+/
# master/base_paths_posix.cc
# We try our best guess by using which against the first
# cmdline arg (may return None).
cmdline = self.cmdline()
if cmdline:
return which(cmdline[0])
else:
return ""
@wrap_exceptions
def cmdline(self):
if OPENBSD and self.pid == 0:
return [] # ...else it crashes
elif NETBSD:
# XXX - most of the times the underlying sysctl() call on Net
# and Open BSD returns a truncated string.
# Also /proc/pid/cmdline behaves the same so it looks
# like this is a kernel bug.
try:
return cext.proc_cmdline(self.pid)
except OSError as err:
if err.errno == errno.EINVAL:
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
else:
raise ZombieProcess(self.pid, self._name, self._ppid)
else:
raise
else:
return cext.proc_cmdline(self.pid)
@wrap_exceptions
def terminal(self):
tty_nr = self.oneshot()[kinfo_proc_map['ttynr']]
tmap = _psposix.get_terminal_map()
try:
return tmap[tty_nr]
except KeyError:
return None
@wrap_exceptions
def ppid(self):
self._ppid = self.oneshot()[kinfo_proc_map['ppid']]
return self._ppid
@wrap_exceptions
def uids(self):
rawtuple = self.oneshot()
return _common.puids(
rawtuple[kinfo_proc_map['real_uid']],
rawtuple[kinfo_proc_map['effective_uid']],
rawtuple[kinfo_proc_map['saved_uid']])
@wrap_exceptions
def gids(self):
rawtuple = self.oneshot()
return _common.pgids(
rawtuple[kinfo_proc_map['real_gid']],
rawtuple[kinfo_proc_map['effective_gid']],
rawtuple[kinfo_proc_map['saved_gid']])
@wrap_exceptions
def cpu_times(self):
rawtuple = self.oneshot()
return _common.pcputimes(
rawtuple[kinfo_proc_map['user_time']],
rawtuple[kinfo_proc_map['sys_time']],
rawtuple[kinfo_proc_map['ch_user_time']],
rawtuple[kinfo_proc_map['ch_sys_time']])
if FREEBSD:
@wrap_exceptions
def cpu_num(self):
return self.oneshot()[kinfo_proc_map['cpunum']]
@wrap_exceptions
def memory_info(self):
rawtuple = self.oneshot()
return pmem(
rawtuple[kinfo_proc_map['rss']],
rawtuple[kinfo_proc_map['vms']],
rawtuple[kinfo_proc_map['memtext']],
rawtuple[kinfo_proc_map['memdata']],
rawtuple[kinfo_proc_map['memstack']])
memory_full_info = memory_info
@wrap_exceptions
def create_time(self):
return self.oneshot()[kinfo_proc_map['create_time']]
@wrap_exceptions
def num_threads(self):
if hasattr(cext, "proc_num_threads"):
# FreeBSD
return cext.proc_num_threads(self.pid)
else:
return len(self.threads())
@wrap_exceptions
def num_ctx_switches(self):
rawtuple = self.oneshot()
return _common.pctxsw(
rawtuple[kinfo_proc_map['ctx_switches_vol']],
rawtuple[kinfo_proc_map['ctx_switches_unvol']])
@wrap_exceptions
def threads(self):
# Note: on OpenSBD this (/dev/mem) requires root access.
rawlist = cext.proc_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = _common.pthread(thread_id, utime, stime)
retlist.append(ntuple)
if OPENBSD:
# On OpenBSD the underlying C function does not raise NSP
# in case the process is gone (and the returned list may
# incomplete).
self.name() # raise NSP if the process disappeared on us
return retlist
@wrap_exceptions
def connections(self, kind='inet'):
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
if NETBSD:
families, types = conn_tmap[kind]
ret = set()
rawlist = cext.net_connections(self.pid)
for item in rawlist:
fd, fam, type, laddr, raddr, status, pid = item
assert pid == self.pid
if fam in families and type in types:
try:
status = TCP_STATUSES[status]
except KeyError:
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
fam = sockfam_to_enum(fam)
type = socktype_to_enum(type)
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.add(nt)
# On NetBSD the underlying C function does not raise NSP
# in case the process is gone (and the returned list may
# incomplete).
self.name() # raise NSP if the process disappeared on us
return list(ret)
families, types = conn_tmap[kind]
rawlist = cext.proc_connections(self.pid, families, types)
ret = []
for item in rawlist:
fd, fam, type, laddr, raddr, status = item
fam = sockfam_to_enum(fam)
type = socktype_to_enum(type)
status = TCP_STATUSES[status]
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.append(nt)
if OPENBSD:
# On OpenBSD the underlying C function does not raise NSP
# in case the process is gone (and the returned list may
# incomplete).
self.name() # raise NSP if the process disappeared on us
return ret
@wrap_exceptions
def wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except _psposix.TimeoutExpired:
raise TimeoutExpired(timeout, self.pid, self._name)
@wrap_exceptions
def nice_get(self):
return cext_posix.getpriority(self.pid)
@wrap_exceptions
def nice_set(self, value):
return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def status(self):
code = self.oneshot()[kinfo_proc_map['status']]
# XXX is '?' legit? (we're not supposed to return it anyway)
return PROC_STATUSES.get(code, '?')
@wrap_exceptions
def io_counters(self):
rawtuple = self.oneshot()
return _common.pio(
rawtuple[kinfo_proc_map['read_io_count']],
rawtuple[kinfo_proc_map['write_io_count']],
-1,
-1)
@wrap_exceptions
def cwd(self):
"""Return process current working directory."""
# sometimes we get an empty string, in which case we turn
# it into None
if OPENBSD and self.pid == 0:
return None # ...else it would raise EINVAL
elif NETBSD:
with wrap_exceptions_procfs(self):
return os.readlink("/proc/%s/cwd" % self.pid)
elif hasattr(cext, 'proc_open_files'):
# FreeBSD < 8 does not support functions based on
# kinfo_getfile() and kinfo_getvmmap()
return cext.proc_cwd(self.pid) or None
else:
raise NotImplementedError(
"supported only starting from FreeBSD 8" if
FREEBSD else "")
nt_mmap_grouped = namedtuple(
'mmap', 'path rss, private, ref_count, shadow_count')
nt_mmap_ext = namedtuple(
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
def _not_implemented(self):
raise NotImplementedError
# FreeBSD < 8 does not support functions based on kinfo_getfile()
# and kinfo_getvmmap()
if hasattr(cext, 'proc_open_files'):
@wrap_exceptions
def open_files(self):
"""Return files opened by process as a list of namedtuples."""
rawlist = cext.proc_open_files(self.pid)
return [_common.popenfile(path, fd) for path, fd in rawlist]
else:
open_files = _not_implemented
# FreeBSD < 8 does not support functions based on kinfo_getfile()
# and kinfo_getvmmap()
if hasattr(cext, 'proc_num_fds'):
@wrap_exceptions
def num_fds(self):
"""Return the number of file descriptors opened by this process."""
ret = cext.proc_num_fds(self.pid)
if NETBSD:
# On NetBSD the underlying C function does not raise NSP
# in case the process is gone.
self.name() # raise NSP if the process disappeared on us
return ret
else:
num_fds = _not_implemented
# --- FreeBSD only APIs
if FREEBSD:
@wrap_exceptions
def cpu_affinity_get(self):
return cext.proc_cpu_affinity_get(self.pid)
@wrap_exceptions
def cpu_affinity_set(self, cpus):
# Pre-emptively check if CPUs are valid because the C
# function has a weird behavior in case of invalid CPUs,
# see: https://github.com/giampaolo/psutil/issues/586
allcpus = tuple(range(len(per_cpu_times())))
for cpu in cpus:
if cpu not in allcpus:
raise ValueError("invalid CPU #%i (choose between %s)"
% (cpu, allcpus))
try:
cext.proc_cpu_affinity_set(self.pid, cpus)
except OSError as err:
# 'man cpuset_setaffinity' about EDEADLK:
# <<the call would leave a thread without a valid CPU to run
# on because the set does not overlap with the thread's
# anonymous mask>>
if err.errno in (errno.EINVAL, errno.EDEADLK):
for cpu in cpus:
if cpu not in allcpus:
raise ValueError(
"invalid CPU #%i (choose between %s)" % (
cpu, allcpus))
raise
@wrap_exceptions
def memory_maps(self):
return cext.proc_memory_maps(self.pid)
-1872
View File
File diff suppressed because it is too large Load Diff
-506
View File
@@ -1,506 +0,0 @@
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""OSX platform implementation."""
import errno
import functools
import os
from collections import namedtuple
from . import _common
from . import _psposix
from . import _psutil_osx as cext
from . import _psutil_posix as cext_posix
from ._common import conn_tmap
from ._common import isfile_strict
from ._common import memoize_when_activated
from ._common import parse_environ_block
from ._common import sockfam_to_enum
from ._common import socktype_to_enum
from ._common import usage_percent
__extra__all__ = []
# =====================================================================
# --- globals
# =====================================================================
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
AF_LINK = cext_posix.AF_LINK
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
TCP_STATUSES = {
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
cext.TCPS_CLOSED: _common.CONN_CLOSE,
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
cext.TCPS_LISTEN: _common.CONN_LISTEN,
cext.TCPS_CLOSING: _common.CONN_CLOSING,
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
}
PROC_STATUSES = {
cext.SIDL: _common.STATUS_IDLE,
cext.SRUN: _common.STATUS_RUNNING,
cext.SSLEEP: _common.STATUS_SLEEPING,
cext.SSTOP: _common.STATUS_STOPPED,
cext.SZOMB: _common.STATUS_ZOMBIE,
}
kinfo_proc_map = dict(
ppid=0,
ruid=1,
euid=2,
suid=3,
rgid=4,
egid=5,
sgid=6,
ttynr=7,
ctime=8,
status=9,
name=10,
)
pidtaskinfo_map = dict(
cpuutime=0,
cpustime=1,
rss=2,
vms=3,
pfaults=4,
pageins=5,
numthreads=6,
volctxsw=7,
)
# these get overwritten on "import psutil" from the __init__.py file
NoSuchProcess = None
ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
# =====================================================================
# --- named tuples
# =====================================================================
# psutil.cpu_times()
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
# psutil.virtual_memory()
svmem = namedtuple(
'svmem', ['total', 'available', 'percent', 'used', 'free',
'active', 'inactive', 'wired'])
# psutil.Process.memory_info()
pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins'])
# psutil.Process.memory_full_info()
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
# psutil.Process.memory_maps(grouped=True)
pmmap_grouped = namedtuple(
'pmmap_grouped',
'path rss private swapped dirtied ref_count shadow_depth')
# psutil.Process.memory_maps(grouped=False)
pmmap_ext = namedtuple(
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
# =====================================================================
# --- memory
# =====================================================================
def virtual_memory():
"""System virtual memory as a namedtuple."""
total, active, inactive, wired, free = cext.virtual_mem()
avail = inactive + free
used = active + inactive + wired
percent = usage_percent((total - avail), total, _round=1)
return svmem(total, avail, percent, used, free,
active, inactive, wired)
def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
total, used, free, sin, sout = cext.swap_mem()
percent = usage_percent(used, total, _round=1)
return _common.sswap(total, used, free, percent, sin, sout)
# =====================================================================
# --- CPU
# =====================================================================
def cpu_times():
"""Return system CPU times as a namedtuple."""
user, nice, system, idle = cext.cpu_times()
return scputimes(user, nice, system, idle)
def per_cpu_times():
"""Return system CPU times as a named tuple"""
ret = []
for cpu_t in cext.per_cpu_times():
user, nice, system, idle = cpu_t
item = scputimes(user, nice, system, idle)
ret.append(item)
return ret
def cpu_count_logical():
"""Return the number of logical CPUs in the system."""
return cext.cpu_count_logical()
def cpu_count_physical():
"""Return the number of physical CPUs in the system."""
return cext.cpu_count_phys()
def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls, traps = \
cext.cpu_stats()
return _common.scpustats(
ctx_switches, interrupts, soft_interrupts, syscalls)
def cpu_freq():
"""Return CPU frequency.
On OSX per-cpu frequency is not supported.
Also, the returned frequency never changes, see:
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
"""
curr, min_, max_ = cext.cpu_freq()
return [_common.scpufreq(curr, min_, max_)]
# =====================================================================
# --- disks
# =====================================================================
disk_usage = _psposix.disk_usage
disk_io_counters = cext.disk_io_counters
def disk_partitions(all=False):
"""Return mounted disk partitions as a list of namedtuples."""
retlist = []
partitions = cext.disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
if device == 'none':
device = ''
if not all:
if not os.path.isabs(device) or not os.path.exists(device):
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
# =====================================================================
# --- network
# =====================================================================
net_io_counters = cext.net_io_counters
net_if_addrs = cext_posix.net_if_addrs
def net_connections(kind='inet'):
"""System-wide network connections."""
# Note: on OSX this will fail with AccessDenied unless
# the process is owned by root.
ret = []
for pid in pids():
try:
cons = Process(pid).connections(kind)
except NoSuchProcess:
continue
else:
if cons:
for c in cons:
c = list(c) + [pid]
ret.append(_common.sconn(*c))
return ret
def net_if_stats():
"""Get NIC stats (isup, duplex, speed, mtu)."""
names = net_io_counters().keys()
ret = {}
for name in names:
mtu = cext_posix.net_if_mtu(name)
isup = cext_posix.net_if_flags(name)
duplex, speed = cext_posix.net_if_duplex_speed(name)
if hasattr(_common, 'NicDuplex'):
duplex = _common.NicDuplex(duplex)
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
# =====================================================================
# --- other system functions
# =====================================================================
def boot_time():
"""The system boot time expressed in seconds since the epoch."""
return cext.boot_time()
def users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = cext.users()
for item in rawlist:
user, tty, hostname, tstamp = item
if tty == '~':
continue # reboot or shutdown
if not tstamp:
continue
nt = _common.suser(user, tty or None, hostname or None, tstamp)
retlist.append(nt)
return retlist
# =====================================================================
# --- processes
# =====================================================================
pids = cext.pids
pid_exists = _psposix.pid_exists
def wrap_exceptions(fun):
"""Decorator which translates bare OSError exceptions into
NoSuchProcess and AccessDenied.
"""
@functools.wraps(fun)
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except OSError as err:
if self.pid == 0:
if 0 in pids():
raise AccessDenied(self.pid, self._name)
else:
raise
if err.errno == errno.ESRCH:
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
else:
raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
return wrapper
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
self._ppid = None
@memoize_when_activated
def _get_kinfo_proc(self):
# Note: should work with all PIDs without permission issues.
ret = cext.proc_kinfo_oneshot(self.pid)
assert len(ret) == len(kinfo_proc_map)
return ret
@memoize_when_activated
def _get_pidtaskinfo(self):
# Note: should work for PIDs owned by user only.
ret = cext.proc_pidtaskinfo_oneshot(self.pid)
assert len(ret) == len(pidtaskinfo_map)
return ret
def oneshot_enter(self):
self._get_kinfo_proc.cache_activate()
self._get_pidtaskinfo.cache_activate()
def oneshot_exit(self):
self._get_kinfo_proc.cache_deactivate()
self._get_pidtaskinfo.cache_deactivate()
@wrap_exceptions
def name(self):
name = self._get_kinfo_proc()[kinfo_proc_map['name']]
return name if name is not None else cext.proc_name(self.pid)
@wrap_exceptions
def exe(self):
return cext.proc_exe(self.pid)
@wrap_exceptions
def cmdline(self):
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
return cext.proc_cmdline(self.pid)
@wrap_exceptions
def environ(self):
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
return parse_environ_block(cext.proc_environ(self.pid))
@wrap_exceptions
def ppid(self):
self._ppid = self._get_kinfo_proc()[kinfo_proc_map['ppid']]
return self._ppid
@wrap_exceptions
def cwd(self):
return cext.proc_cwd(self.pid)
@wrap_exceptions
def uids(self):
rawtuple = self._get_kinfo_proc()
return _common.puids(
rawtuple[kinfo_proc_map['ruid']],
rawtuple[kinfo_proc_map['euid']],
rawtuple[kinfo_proc_map['suid']])
@wrap_exceptions
def gids(self):
rawtuple = self._get_kinfo_proc()
return _common.puids(
rawtuple[kinfo_proc_map['rgid']],
rawtuple[kinfo_proc_map['egid']],
rawtuple[kinfo_proc_map['sgid']])
@wrap_exceptions
def terminal(self):
tty_nr = self._get_kinfo_proc()[kinfo_proc_map['ttynr']]
tmap = _psposix.get_terminal_map()
try:
return tmap[tty_nr]
except KeyError:
return None
@wrap_exceptions
def memory_info(self):
rawtuple = self._get_pidtaskinfo()
return pmem(
rawtuple[pidtaskinfo_map['rss']],
rawtuple[pidtaskinfo_map['vms']],
rawtuple[pidtaskinfo_map['pfaults']],
rawtuple[pidtaskinfo_map['pageins']],
)
@wrap_exceptions
def memory_full_info(self):
basic_mem = self.memory_info()
uss = cext.proc_memory_uss(self.pid)
return pfullmem(*basic_mem + (uss, ))
@wrap_exceptions
def cpu_times(self):
rawtuple = self._get_pidtaskinfo()
return _common.pcputimes(
rawtuple[pidtaskinfo_map['cpuutime']],
rawtuple[pidtaskinfo_map['cpustime']],
# children user / system times are not retrievable (set to 0)
0, 0)
@wrap_exceptions
def create_time(self):
return self._get_kinfo_proc()[kinfo_proc_map['ctime']]
@wrap_exceptions
def num_ctx_switches(self):
# Unvoluntary value seems not to be available;
# getrusage() numbers seems to confirm this theory.
# We set it to 0.
vol = self._get_pidtaskinfo()[pidtaskinfo_map['volctxsw']]
return _common.pctxsw(vol, 0)
@wrap_exceptions
def num_threads(self):
return self._get_pidtaskinfo()[pidtaskinfo_map['numthreads']]
@wrap_exceptions
def open_files(self):
if self.pid == 0:
return []
files = []
rawlist = cext.proc_open_files(self.pid)
for path, fd in rawlist:
if isfile_strict(path):
ntuple = _common.popenfile(path, fd)
files.append(ntuple)
return files
@wrap_exceptions
def connections(self, kind='inet'):
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
rawlist = cext.proc_connections(self.pid, families, types)
ret = []
for item in rawlist:
fd, fam, type, laddr, raddr, status = item
status = TCP_STATUSES[status]
fam = sockfam_to_enum(fam)
type = socktype_to_enum(type)
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.append(nt)
return ret
@wrap_exceptions
def num_fds(self):
if self.pid == 0:
return 0
return cext.proc_num_fds(self.pid)
@wrap_exceptions
def wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except _psposix.TimeoutExpired:
raise TimeoutExpired(timeout, self.pid, self._name)
@wrap_exceptions
def nice_get(self):
return cext_posix.getpriority(self.pid)
@wrap_exceptions
def nice_set(self, value):
return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def status(self):
code = self._get_kinfo_proc()[kinfo_proc_map['status']]
# XXX is '?' legit? (we're not supposed to return it anyway)
return PROC_STATUSES.get(code, '?')
@wrap_exceptions
def threads(self):
rawlist = cext.proc_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = _common.pthread(thread_id, utime, stime)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def memory_maps(self):
return cext.proc_memory_maps(self.pid)
-184
View File
@@ -1,184 +0,0 @@
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Routines common to all posix systems."""
import errno
import glob
import os
import sys
import time
from ._common import memoize
from ._common import sdiskusage
from ._common import usage_percent
from ._compat import PY3
from ._compat import unicode
__all__ = ['TimeoutExpired', 'pid_exists', 'wait_pid', 'disk_usage',
'get_terminal_map']
class TimeoutExpired(Exception):
pass
def pid_exists(pid):
"""Check whether pid exists in the current process table."""
if pid == 0:
# According to "man 2 kill" PID 0 has a special meaning:
# it refers to <<every process in the process group of the
# calling process>> so we don't want to go any further.
# If we get here it means this UNIX platform *does* have
# a process with id 0.
return True
try:
os.kill(pid, 0)
except OSError as err:
if err.errno == errno.ESRCH:
# ESRCH == No such process
return False
elif err.errno == errno.EPERM:
# EPERM clearly means there's a process to deny access to
return True
else:
# According to "man 2 kill" possible error values are
# (EINVAL, EPERM, ESRCH) therefore we should never get
# here. If we do let's be explicit in considering this
# an error.
raise err
else:
return True
def wait_pid(pid, timeout=None):
"""Wait for process with pid 'pid' to terminate and return its
exit status code as an integer.
If pid is not a children of os.getpid() (current process) just
waits until the process disappears and return None.
If pid does not exist at all return None immediately.
Raise TimeoutExpired on timeout expired.
"""
def check_timeout(delay):
if timeout is not None:
if timer() >= stop_at:
raise TimeoutExpired()
time.sleep(delay)
return min(delay * 2, 0.04)
timer = getattr(time, 'monotonic', time.time)
if timeout is not None:
def waitcall():
return os.waitpid(pid, os.WNOHANG)
stop_at = timer() + timeout
else:
def waitcall():
return os.waitpid(pid, 0)
delay = 0.0001
while True:
try:
retpid, status = waitcall()
except OSError as err:
if err.errno == errno.EINTR:
delay = check_timeout(delay)
continue
elif err.errno == errno.ECHILD:
# This has two meanings:
# - pid is not a child of os.getpid() in which case
# we keep polling until it's gone
# - pid never existed in the first place
# In both cases we'll eventually return None as we
# can't determine its exit status code.
while True:
if pid_exists(pid):
delay = check_timeout(delay)
else:
return
else:
raise
else:
if retpid == 0:
# WNOHANG was used, pid is still running
delay = check_timeout(delay)
continue
# process exited due to a signal; return the integer of
# that signal
if os.WIFSIGNALED(status):
return -os.WTERMSIG(status)
# process exited using exit(2) system call; return the
# integer exit(2) system call has been called with
elif os.WIFEXITED(status):
return os.WEXITSTATUS(status)
else:
# should never happen
raise ValueError("unknown process exit status %r" % status)
def disk_usage(path):
"""Return disk usage associated with path.
Note: UNIX usually reserves 5% disk space which is not accessible
by user. In this function "total" and "used" values reflect the
total and used disk space whereas "free" and "percent" represent
the "free" and "used percent" user disk space.
"""
try:
st = os.statvfs(path)
except UnicodeEncodeError:
if not PY3 and isinstance(path, unicode):
# this is a bug with os.statvfs() and unicode on
# Python 2, see:
# - https://github.com/giampaolo/psutil/issues/416
# - http://bugs.python.org/issue18695
try:
path = path.encode(sys.getfilesystemencoding())
except UnicodeEncodeError:
pass
st = os.statvfs(path)
else:
raise
# Total space which is only available to root (unless changed
# at system level).
total = (st.f_blocks * st.f_frsize)
# Remaining free space usable by root.
avail_to_root = (st.f_bfree * st.f_frsize)
# Remaining free space usable by user.
avail_to_user = (st.f_bavail * st.f_frsize)
# Total space being used in general.
used = (total - avail_to_root)
# Total space which is available to user (same as 'total' but
# for the user).
total_user = used + avail_to_user
# User usage percent compared to the total amount of space
# the user can use. This number would be higher if compared
# to root's because the user has less space (usually -5%).
usage_percent_user = usage_percent(used, total_user, _round=1)
# NB: the percentage is -5% than what shown by df due to
# reserved blocks that we are currently not considering:
# https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462
return sdiskusage(
total=total, used=used, free=avail_to_user, percent=usage_percent_user)
@memoize
def get_terminal_map():
"""Get a map of device-id -> path as a dict.
Used by Process.terminal()
"""
ret = {}
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
for name in ls:
assert name not in ret, name
try:
ret[os.stat(name).st_rdev] = name
except OSError as err:
if err.errno != errno.ENOENT:
raise
return ret
-702
View File
@@ -1,702 +0,0 @@
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Sun OS Solaris platform implementation."""
import errno
import os
import socket
import subprocess
import sys
from collections import namedtuple
from . import _common
from . import _psposix
from . import _psutil_posix as cext_posix
from . import _psutil_sunos as cext
from ._common import isfile_strict
from ._common import memoize_when_activated
from ._common import sockfam_to_enum
from ._common import socktype_to_enum
from ._common import usage_percent
from ._compat import b
from ._compat import PY3
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
# =====================================================================
# --- globals
# =====================================================================
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
AF_LINK = cext_posix.AF_LINK
IS_64_BIT = sys.maxsize > 2**32
CONN_IDLE = "IDLE"
CONN_BOUND = "BOUND"
PROC_STATUSES = {
cext.SSLEEP: _common.STATUS_SLEEPING,
cext.SRUN: _common.STATUS_RUNNING,
cext.SZOMB: _common.STATUS_ZOMBIE,
cext.SSTOP: _common.STATUS_STOPPED,
cext.SIDL: _common.STATUS_IDLE,
cext.SONPROC: _common.STATUS_RUNNING, # same as run
cext.SWAIT: _common.STATUS_WAITING,
}
TCP_STATUSES = {
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
cext.TCPS_CLOSED: _common.CONN_CLOSE,
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
cext.TCPS_LISTEN: _common.CONN_LISTEN,
cext.TCPS_CLOSING: _common.CONN_CLOSING,
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
cext.TCPS_IDLE: CONN_IDLE, # sunos specific
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
}
# these get overwritten on "import psutil" from the __init__.py file
NoSuchProcess = None
ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
# =====================================================================
# --- named tuples
# =====================================================================
# psutil.cpu_times()
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
# psutil.cpu_times(percpu=True)
pcputimes = namedtuple('pcputimes',
['user', 'system', 'children_user', 'children_system'])
# psutil.virtual_memory()
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
# psutil.Process.memory_info()
pmem = namedtuple('pmem', ['rss', 'vms'])
pfullmem = pmem
# psutil.Process.memory_maps(grouped=True)
pmmap_grouped = namedtuple('pmmap_grouped',
['path', 'rss', 'anonymous', 'locked'])
# psutil.Process.memory_maps(grouped=False)
pmmap_ext = namedtuple(
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
# =====================================================================
# --- utils
# =====================================================================
def get_procfs_path():
"""Return updated psutil.PROCFS_PATH constant."""
return sys.modules['psutil'].PROCFS_PATH
# =====================================================================
# --- memory
# =====================================================================
def virtual_memory():
"""Report virtual memory metrics."""
# we could have done this with kstat, but IMHO this is good enough
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
# note: there's no difference on Solaris
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
used = total - free
percent = usage_percent(used, total, _round=1)
return svmem(total, avail, percent, used, free)
def swap_memory():
"""Report swap memory metrics."""
sin, sout = cext.swap_mem()
# XXX
# we are supposed to get total/free by doing so:
# http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/
# usr/src/cmd/swap/swap.c
# ...nevertheless I can't manage to obtain the same numbers as 'swap'
# cmdline utility, so let's parse its output (sigh!)
p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
os.environ['PATH'], 'swap', '-l'],
stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
if PY3:
stdout = stdout.decode(sys.stdout.encoding)
if p.returncode != 0:
raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode)
lines = stdout.strip().split('\n')[1:]
if not lines:
raise RuntimeError('no swap device(s) configured')
total = free = 0
for line in lines:
line = line.split()
t, f = line[-2:]
total += int(int(t) * 512)
free += int(int(f) * 512)
used = total - free
percent = usage_percent(used, total, _round=1)
return _common.sswap(total, used, free, percent,
sin * PAGE_SIZE, sout * PAGE_SIZE)
# =====================================================================
# --- CPU
# =====================================================================
def cpu_times():
"""Return system-wide CPU times as a named tuple"""
ret = cext.per_cpu_times()
return scputimes(*[sum(x) for x in zip(*ret)])
def per_cpu_times():
"""Return system per-CPU times as a list of named tuples"""
ret = cext.per_cpu_times()
return [scputimes(*x) for x in ret]
def cpu_count_logical():
"""Return the number of logical CPUs in the system."""
try:
return os.sysconf("SC_NPROCESSORS_ONLN")
except ValueError:
# mimic os.cpu_count() behavior
return None
def cpu_count_physical():
"""Return the number of physical CPUs in the system."""
return cext.cpu_count_phys()
def cpu_stats():
"""Return various CPU stats as a named tuple."""
ctx_switches, interrupts, syscalls, traps = cext.cpu_stats()
soft_interrupts = 0
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
syscalls)
# =====================================================================
# --- disks
# =====================================================================
disk_io_counters = cext.disk_io_counters
disk_usage = _psposix.disk_usage
def disk_partitions(all=False):
"""Return system disk partitions."""
# TODO - the filtering logic should be better checked so that
# it tries to reflect 'df' as much as possible
retlist = []
partitions = cext.disk_partitions()
for partition in partitions:
device, mountpoint, fstype, opts = partition
if device == 'none':
device = ''
if not all:
# Differently from, say, Linux, we don't have a list of
# common fs types so the best we can do, AFAIK, is to
# filter by filesystem having a total size > 0.
if not disk_usage(mountpoint).total:
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
retlist.append(ntuple)
return retlist
# =====================================================================
# --- network
# =====================================================================
net_io_counters = cext.net_io_counters
net_if_addrs = cext_posix.net_if_addrs
def net_connections(kind, _pid=-1):
"""Return socket connections. If pid == -1 return system-wide
connections (as opposed to connections opened by one process only).
Only INET sockets are returned (UNIX are not).
"""
cmap = _common.conn_tmap.copy()
if _pid == -1:
cmap.pop('unix', 0)
if kind not in cmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in cmap])))
families, types = _common.conn_tmap[kind]
rawlist = cext.net_connections(_pid)
ret = set()
for item in rawlist:
fd, fam, type_, laddr, raddr, status, pid = item
if fam not in families:
continue
if type_ not in types:
continue
status = TCP_STATUSES[status]
fam = sockfam_to_enum(fam)
type_ = socktype_to_enum(type_)
if _pid == -1:
nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid)
else:
nt = _common.pconn(fd, fam, type_, laddr, raddr, status)
ret.add(nt)
return list(ret)
def net_if_stats():
"""Get NIC stats (isup, duplex, speed, mtu)."""
ret = cext.net_if_stats()
for name, items in ret.items():
isup, duplex, speed, mtu = items
if hasattr(_common, 'NicDuplex'):
duplex = _common.NicDuplex(duplex)
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
# =====================================================================
# --- other system functions
# =====================================================================
def boot_time():
"""The system boot time expressed in seconds since the epoch."""
return cext.boot_time()
def users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = cext.users()
localhost = (':0.0', ':0')
for item in rawlist:
user, tty, hostname, tstamp, user_process = item
# note: the underlying C function includes entries about
# system boot, run level and others. We might want
# to use them in the future.
if not user_process:
continue
if hostname in localhost:
hostname = 'localhost'
nt = _common.suser(user, tty, hostname, tstamp)
retlist.append(nt)
return retlist
# =====================================================================
# --- processes
# =====================================================================
def pids():
"""Returns a list of PIDs currently running on the system."""
return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()]
def pid_exists(pid):
"""Check for the existence of a unix pid."""
return _psposix.pid_exists(pid)
def wrap_exceptions(fun):
"""Call callable into a try/except clause and translate ENOENT,
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
"""
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except EnvironmentError as err:
if self.pid == 0:
if 0 in pids():
raise AccessDenied(self.pid, self._name)
else:
raise
# ENOENT (no such file or directory) gets raised on open().
# ESRCH (no such process) can get raised on read() if
# process is gone in meantime.
if err.errno in (errno.ENOENT, errno.ESRCH):
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._name)
else:
raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
return wrapper
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
def __init__(self, pid):
self.pid = pid
self._name = None
self._ppid = None
self._procfs_path = get_procfs_path()
def oneshot_enter(self):
self._proc_name_and_args.cache_activate()
self._proc_basic_info.cache_activate()
self._proc_cred.cache_activate()
def oneshot_exit(self):
self._proc_name_and_args.cache_deactivate()
self._proc_basic_info.cache_deactivate()
self._proc_cred.cache_deactivate()
@memoize_when_activated
def _proc_name_and_args(self):
return cext.proc_name_and_args(self.pid, self._procfs_path)
@memoize_when_activated
def _proc_basic_info(self):
return cext.proc_basic_info(self.pid, self._procfs_path)
@memoize_when_activated
def _proc_cred(self):
return cext.proc_cred(self.pid, self._procfs_path)
@wrap_exceptions
def name(self):
# note: max len == 15
return self._proc_name_and_args()[0]
@wrap_exceptions
def exe(self):
try:
return os.readlink(
"%s/%s/path/a.out" % (self._procfs_path, self.pid))
except OSError:
pass # continue and guess the exe name from the cmdline
# Will be guessed later from cmdline but we want to explicitly
# invoke cmdline here in order to get an AccessDenied
# exception if the user has not enough privileges.
self.cmdline()
return ""
@wrap_exceptions
def cmdline(self):
return self._proc_name_and_args()[1].split(' ')
@wrap_exceptions
def create_time(self):
return self._proc_basic_info()[3]
@wrap_exceptions
def num_threads(self):
return self._proc_basic_info()[5]
@wrap_exceptions
def nice_get(self):
# For some reason getpriority(3) return ESRCH (no such process)
# for certain low-pid processes, no matter what (even as root).
# The process actually exists though, as it has a name,
# creation time, etc.
# The best thing we can do here appears to be raising AD.
# Note: tested on Solaris 11; on Open Solaris 5 everything is
# fine.
try:
return cext_posix.getpriority(self.pid)
except EnvironmentError as err:
# 48 is 'operation not supported' but errno does not expose
# it. It occurs for low system pids.
if err.errno in (errno.ENOENT, errno.ESRCH, 48):
if pid_exists(self.pid):
raise AccessDenied(self.pid, self._name)
raise
@wrap_exceptions
def nice_set(self, value):
if self.pid in (2, 3):
# Special case PIDs: internally setpriority(3) return ESRCH
# (no such process), no matter what.
# The process actually exists though, as it has a name,
# creation time, etc.
raise AccessDenied(self.pid, self._name)
return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def ppid(self):
self._ppid = self._proc_basic_info()[0]
return self._ppid
@wrap_exceptions
def uids(self):
real, effective, saved, _, _, _ = self._proc_cred()
return _common.puids(real, effective, saved)
@wrap_exceptions
def gids(self):
_, _, _, real, effective, saved = self._proc_cred()
return _common.puids(real, effective, saved)
@wrap_exceptions
def cpu_times(self):
try:
times = cext.proc_cpu_times(self.pid, self._procfs_path)
except OSError as err:
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
# We may get here if we attempt to query a 64bit process
# with a 32bit python.
# Error originates from read() and also tools like "cat"
# fail in the same way (!).
# Since there simply is no way to determine CPU times we
# return 0.0 as a fallback. See:
# https://github.com/giampaolo/psutil/issues/857
times = (0.0, 0.0, 0.0, 0.0)
else:
raise
return _common.pcputimes(*times)
@wrap_exceptions
def cpu_num(self):
return cext.proc_cpu_num(self.pid, self._procfs_path)
@wrap_exceptions
def terminal(self):
procfs_path = self._procfs_path
hit_enoent = False
tty = wrap_exceptions(
self._proc_basic_info()[0])
if tty != cext.PRNODEV:
for x in (0, 1, 2, 255):
try:
return os.readlink(
'%s/%d/path/%d' % (procfs_path, self.pid, x))
except OSError as err:
if err.errno == errno.ENOENT:
hit_enoent = True
continue
raise
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('%s/%s' % (procfs_path, self.pid))
@wrap_exceptions
def cwd(self):
# /proc/PID/path/cwd may not be resolved by readlink() even if
# it exists (ls shows it). If that's the case and the process
# is still alive return None (we can return None also on BSD).
# Reference: http://goo.gl/55XgO
procfs_path = self._procfs_path
try:
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
except OSError as err:
if err.errno == errno.ENOENT:
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
return None
raise
@wrap_exceptions
def memory_info(self):
ret = self._proc_basic_info()
rss, vms = ret[1] * 1024, ret[2] * 1024
return pmem(rss, vms)
memory_full_info = memory_info
@wrap_exceptions
def status(self):
code = self._proc_basic_info()[6]
# XXX is '?' legit? (we're not supposed to return it anyway)
return PROC_STATUSES.get(code, '?')
@wrap_exceptions
def threads(self):
procfs_path = self._procfs_path
ret = []
tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid))
hit_enoent = False
for tid in tids:
tid = int(tid)
try:
utime, stime = cext.query_process_thread(
self.pid, tid, procfs_path)
except EnvironmentError as err:
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
# We may get here if we attempt to query a 64bit process
# with a 32bit python.
# Error originates from read() and also tools like "cat"
# fail in the same way (!).
# Since there simply is no way to determine CPU times we
# return 0.0 as a fallback. See:
# https://github.com/giampaolo/psutil/issues/857
continue
# ENOENT == thread gone in meantime
if err.errno == errno.ENOENT:
hit_enoent = True
continue
raise
else:
nt = _common.pthread(tid, utime, stime)
ret.append(nt)
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('%s/%s' % (procfs_path, self.pid))
return ret
@wrap_exceptions
def open_files(self):
retlist = []
hit_enoent = False
procfs_path = self._procfs_path
pathdir = '%s/%d/path' % (procfs_path, self.pid)
for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)):
path = os.path.join(pathdir, fd)
if os.path.islink(path):
try:
file = os.readlink(path)
except OSError as err:
# ENOENT == file which is gone in the meantime
if err.errno == errno.ENOENT:
hit_enoent = True
continue
raise
else:
if isfile_strict(file):
retlist.append(_common.popenfile(file, int(fd)))
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('%s/%s' % (procfs_path, self.pid))
return retlist
def _get_unix_sockets(self, pid):
"""Get UNIX sockets used by process by parsing 'pfiles' output."""
# TODO: rewrite this in C (...but the damn netstat source code
# does not include this part! Argh!!)
cmd = "pfiles %s" % pid
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if PY3:
stdout, stderr = [x.decode(sys.stdout.encoding)
for x in (stdout, stderr)]
if p.returncode != 0:
if 'permission denied' in stderr.lower():
raise AccessDenied(self.pid, self._name)
if 'no such process' in stderr.lower():
raise NoSuchProcess(self.pid, self._name)
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
lines = stdout.split('\n')[2:]
for i, line in enumerate(lines):
line = line.lstrip()
if line.startswith('sockname: AF_UNIX'):
path = line.split(' ', 2)[2]
type = lines[i - 2].strip()
if type == 'SOCK_STREAM':
type = socket.SOCK_STREAM
elif type == 'SOCK_DGRAM':
type = socket.SOCK_DGRAM
else:
type = -1
yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE)
@wrap_exceptions
def connections(self, kind='inet'):
ret = net_connections(kind, _pid=self.pid)
# The underlying C implementation retrieves all OS connections
# and filters them by PID. At this point we can't tell whether
# an empty list means there were no connections for process or
# process is no longer active so we force NSP in case the PID
# is no longer there.
if not ret:
# will raise NSP if process is gone
os.stat('%s/%s' % (self._procfs_path, self.pid))
# UNIX sockets
if kind in ('all', 'unix'):
ret.extend([_common.pconn(*conn) for conn in
self._get_unix_sockets(self.pid)])
return ret
nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked')
nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked')
@wrap_exceptions
def memory_maps(self):
def toaddr(start, end):
return '%s-%s' % (hex(start)[2:].strip('L'),
hex(end)[2:].strip('L'))
procfs_path = self._procfs_path
retlist = []
try:
rawlist = cext.proc_memory_maps(self.pid, procfs_path)
except OSError as err:
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
# We may get here if we attempt to query a 64bit process
# with a 32bit python.
# Error originates from read() and also tools like "cat"
# fail in the same way (!).
# Since there simply is no way to determine CPU times we
# return 0.0 as a fallback. See:
# https://github.com/giampaolo/psutil/issues/857
return []
else:
raise
hit_enoent = False
for item in rawlist:
addr, addrsize, perm, name, rss, anon, locked = item
addr = toaddr(addr, addrsize)
if not name.startswith('['):
try:
name = os.readlink(
'%s/%s/path/%s' % (procfs_path, self.pid, name))
except OSError as err:
if err.errno == errno.ENOENT:
# sometimes the link may not be resolved by
# readlink() even if it exists (ls shows it).
# If that's the case we just return the
# unresolved link path.
# This seems an incosistency with /proc similar
# to: http://goo.gl/55XgO
name = '%s/%s/path/%s' % (procfs_path, self.pid, name)
hit_enoent = True
else:
raise
retlist.append((addr, perm, name, rss, anon, locked))
if hit_enoent:
# raise NSP if the process disappeared on us
os.stat('%s/%s' % (procfs_path, self.pid))
return retlist
@wrap_exceptions
def num_fds(self):
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
@wrap_exceptions
def num_ctx_switches(self):
return _common.pctxsw(
*cext.proc_num_ctx_switches(self.pid, self._procfs_path))
@wrap_exceptions
def wait(self, timeout=None):
try:
return _psposix.wait_pid(self.pid, timeout)
except _psposix.TimeoutExpired:
raise TimeoutExpired(timeout, self.pid, self._name)
-1047
View File
File diff suppressed because it is too large Load Diff
-126
View File
@@ -1,126 +0,0 @@
/*
* 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.
*/
#ifdef PSUTIL_POSIX
#include <sys/types.h>
#include <signal.h>
#endif
#include <Python.h>
/*
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
*/
PyObject *
NoSuchProcess(void) {
PyObject *exc;
char *msg = strerror(ESRCH);
exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
PyErr_SetObject(PyExc_OSError, exc);
Py_XDECREF(exc);
return NULL;
}
/*
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
*/
PyObject *
AccessDenied(void) {
PyObject *exc;
char *msg = strerror(EACCES);
exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
PyErr_SetObject(PyExc_OSError, exc);
Py_XDECREF(exc);
return NULL;
}
#ifdef PSUTIL_POSIX
/*
* Check if PID exists. Return values:
* 1: exists
* 0: does not exist
* -1: error (Python exception is set)
*/
int
psutil_pid_exists(long pid) {
int ret;
// No negative PID exists, plus -1 is an alias for sending signal
// too all processes except system ones. Not what we want.
if (pid < 0)
return 0;
// As per "man 2 kill" PID 0 is an alias for sending the signal to
// every process in the process group of the calling process.
// Not what we want. Some platforms have PID 0, some do not.
// We decide that at runtime.
if (pid == 0) {
#if defined(PSUTIL_LINUX) || defined(PSUTIL_FREEBSD)
return 0;
#else
return 1;
#endif
}
#if defined(PSUTIL_OSX)
ret = kill((pid_t)pid , 0);
#else
ret = kill(pid , 0);
#endif
if (ret == 0)
return 1;
else {
if (errno == ESRCH) {
// ESRCH == No such process
return 0;
}
else if (errno == EPERM) {
// EPERM clearly indicates there's a process to deny
// access to.
return 1;
}
else {
// According to "man 2 kill" possible error values are
// (EINVAL, EPERM, ESRCH) therefore we should never get
// here. If we do let's be explicit in considering this
// an error.
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
}
}
/*
* Utility used for those syscalls which do not return a meaningful
* error that we can translate into an exception which makes sense.
* As such, we'll have to guess.
* On UNIX, if errno is set, we return that one (OSError).
* Else, if PID does not exist we assume the syscall failed because
* of that so we raise NoSuchProcess.
* If none of this is true we giveup and raise RuntimeError(msg).
* This will always set a Python exception and return NULL.
*/
int
psutil_raise_for_pid(long pid, char *msg) {
// Set exception to AccessDenied if pid exists else NoSuchProcess.
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return 0;
}
if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
else
PyErr_SetString(PyExc_RuntimeError, msg);
return 0;
}
#endif
-15
View File
@@ -1,15 +0,0 @@
/*
* 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 <Python.h>
PyObject* AccessDenied(void);
PyObject* NoSuchProcess(void);
#ifdef PSUTIL_POSIX
int psutil_pid_exists(long pid);
void psutil_raise_for_pid(long pid, char *msg);
#endif
-688
View File
@@ -1,688 +0,0 @@
/*
* 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 <Python.h>
#include <errno.h>
#include <stdlib.h>
#include <mntent.h>
#include <features.h>
#include <utmp.h>
#include <sched.h>
#include <linux/version.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <linux/if.h>
// see: https://github.com/giampaolo/psutil/issues/659
#ifdef PSUTIL_ETHTOOL_MISSING_TYPES
#include <linux/types.h>
typedef __u64 u64;
typedef __u32 u32;
typedef __u16 u16;
typedef __u8 u8;
#endif
/* Avoid redefinition of struct sysinfo with musl libc */
#define _LINUX_SYSINFO_H
#include <linux/ethtool.h>
/* The minimum number of CPUs allocated in a cpu_set_t */
static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
// Linux >= 2.6.13
#define PSUTIL_HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set)
// Linux >= 2.6.36 (supposedly) and glibc >= 13
#define PSUTIL_HAVE_PRLIMIT \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \
(__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \
defined(__NR_prlimit64)
#if PSUTIL_HAVE_PRLIMIT
#define _FILE_OFFSET_BITS 64
#include <time.h>
#include <sys/resource.h>
#endif
// May happen on old RedHat versions, see:
// https://github.com/giampaolo/psutil/issues/607
#ifndef DUPLEX_UNKNOWN
#define DUPLEX_UNKNOWN 0xff
#endif
#if PSUTIL_HAVE_IOPRIO
enum {
IOPRIO_WHO_PROCESS = 1,
};
static inline int
ioprio_get(int which, int who) {
return syscall(__NR_ioprio_get, which, who);
}
static inline int
ioprio_set(int which, int who, int ioprio) {
return syscall(__NR_ioprio_set, which, who, ioprio);
}
#define IOPRIO_CLASS_SHIFT 13
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
/*
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
*/
static PyObject *
psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
long pid;
int ioprio, ioclass, iodata;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
if (ioprio == -1)
return PyErr_SetFromErrno(PyExc_OSError);
ioclass = IOPRIO_PRIO_CLASS(ioprio);
iodata = IOPRIO_PRIO_DATA(ioprio);
return Py_BuildValue("ii", ioclass, iodata);
}
/*
* A wrapper around ioprio_set(); sets process I/O priority.
* ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
*/
static PyObject *
psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
long pid;
int ioprio, ioclass, iodata;
int retval;
if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata))
return NULL;
ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
if (retval == -1)
return PyErr_SetFromErrno(PyExc_OSError);
Py_RETURN_NONE;
}
#endif
#if PSUTIL_HAVE_PRLIMIT
/*
* A wrapper around prlimit(2); sets process resource limits.
* This can be used for both get and set, in which case extra
* 'soft' and 'hard' args must be provided.
*/
static PyObject *
psutil_linux_prlimit(PyObject *self, PyObject *args) {
long pid;
int ret, resource;
struct rlimit old, new;
struct rlimit *newp = NULL;
PyObject *py_soft = NULL;
PyObject *py_hard = NULL;
if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &py_soft, &py_hard))
return NULL;
// get
if (py_soft == NULL && py_hard == NULL) {
ret = prlimit(pid, resource, NULL, &old);
if (ret == -1)
return PyErr_SetFromErrno(PyExc_OSError);
#if defined(PSUTIL_HAVE_LONG_LONG)
if (sizeof(old.rlim_cur) > sizeof(long)) {
return Py_BuildValue("LL",
(PY_LONG_LONG)old.rlim_cur,
(PY_LONG_LONG)old.rlim_max);
}
#endif
return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max);
}
// set
else {
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
new.rlim_cur = PyLong_AsLongLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLongLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#else
new.rlim_cur = PyLong_AsLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
new.rlim_max = PyLong_AsLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#endif
newp = &new;
ret = prlimit(pid, resource, newp, &old);
if (ret == -1)
return PyErr_SetFromErrno(PyExc_OSError);
Py_RETURN_NONE;
}
}
#endif
/*
* Return disk mounted partitions as a list of tuples including device,
* mount point and filesystem type
*/
static PyObject *
psutil_disk_partitions(PyObject *self, PyObject *args) {
FILE *file = NULL;
struct mntent *entry;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
if (py_retlist == NULL)
return NULL;
// MOUNTED constant comes from mntent.h and it's == '/etc/mtab'
Py_BEGIN_ALLOW_THREADS
file = setmntent(MOUNTED, "r");
Py_END_ALLOW_THREADS
if ((file == 0) || (file == NULL)) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, MOUNTED);
goto error;
}
while ((entry = getmntent(file))) {
if (entry == NULL) {
PyErr_Format(PyExc_RuntimeError, "getmntent() syscall failed");
goto error;
}
py_tuple = Py_BuildValue("(ssss)",
entry->mnt_fsname, // device
entry->mnt_dir, // mount point
entry->mnt_type, // fs type
entry->mnt_opts); // options
if (! py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
endmntent(file);
return py_retlist;
error:
if (file != NULL)
endmntent(file);
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
return NULL;
}
/*
* A wrapper around sysinfo(), return system memory usage statistics.
*/
static PyObject *
psutil_linux_sysinfo(PyObject *self, PyObject *args) {
struct sysinfo info;
if (sysinfo(&info) != 0)
return PyErr_SetFromErrno(PyExc_OSError);
// note: boot time might also be determined from here
return Py_BuildValue(
"(kkkkkkI)",
info.totalram, // total
info.freeram, // free
info.bufferram, // buffer
info.sharedram, // shared
info.totalswap, // swap tot
info.freeswap, // swap free
info.mem_unit // multiplier
);
}
/*
* Return process CPU affinity as a Python list
* The dual implementation exists because of:
* https://github.com/giampaolo/psutil/issues/536
*/
#ifdef CPU_ALLOC
static PyObject *
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
int cpu, ncpus, count, cpucount_s;
long pid;
size_t setsize;
cpu_set_t *mask = NULL;
PyObject *py_list = NULL;
if (!PyArg_ParseTuple(args, "l", &pid))
return NULL;
ncpus = NCPUS_START;
while (1) {
setsize = CPU_ALLOC_SIZE(ncpus);
mask = CPU_ALLOC(ncpus);
if (mask == NULL)
return PyErr_NoMemory();
if (sched_getaffinity(pid, setsize, mask) == 0)
break;
CPU_FREE(mask);
if (errno != EINVAL)
return PyErr_SetFromErrno(PyExc_OSError);
if (ncpus > INT_MAX / 2) {
PyErr_SetString(PyExc_OverflowError, "could not allocate "
"a large enough CPU set");
return NULL;
}
ncpus = ncpus * 2;
}
py_list = PyList_New(0);
if (py_list == NULL)
goto error;
cpucount_s = CPU_COUNT_S(setsize, mask);
for (cpu = 0, count = cpucount_s; count; cpu++) {
if (CPU_ISSET_S(cpu, setsize, mask)) {
#if PY_MAJOR_VERSION >= 3
PyObject *cpu_num = PyLong_FromLong(cpu);
#else
PyObject *cpu_num = PyInt_FromLong(cpu);
#endif
if (cpu_num == NULL)
goto error;
if (PyList_Append(py_list, cpu_num)) {
Py_DECREF(cpu_num);
goto error;
}
Py_DECREF(cpu_num);
--count;
}
}
CPU_FREE(mask);
return py_list;
error:
if (mask)
CPU_FREE(mask);
Py_XDECREF(py_list);
return NULL;
}
#else
/*
* Alternative implementation in case CPU_ALLOC is not defined.
*/
static PyObject *
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
cpu_set_t cpuset;
unsigned int len = sizeof(cpu_set_t);
long pid;
int i;
PyObject* py_retlist = NULL;
PyObject *py_cpu_num = NULL;
if (!PyArg_ParseTuple(args, "l", &pid))
return NULL;
CPU_ZERO(&cpuset);
if (sched_getaffinity(pid, len, &cpuset) < 0)
return PyErr_SetFromErrno(PyExc_OSError);
py_retlist = PyList_New(0);
if (py_retlist == NULL)
goto error;
for (i = 0; i < CPU_SETSIZE; ++i) {
if (CPU_ISSET(i, &cpuset)) {
py_cpu_num = Py_BuildValue("i", i);
if (py_cpu_num == NULL)
goto error;
if (PyList_Append(py_retlist, py_cpu_num))
goto error;
Py_DECREF(py_cpu_num);
}
}
return py_retlist;
error:
Py_XDECREF(py_cpu_num);
Py_XDECREF(py_retlist);
return NULL;
}
#endif
/*
* Set process CPU affinity; expects a bitmask
*/
static PyObject *
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
cpu_set_t cpu_set;
size_t len;
long pid;
int i, seq_len;
PyObject *py_cpu_set;
PyObject *py_cpu_seq = NULL;
if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
return NULL;
if (!PySequence_Check(py_cpu_set)) {
PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s",
Py_TYPE(py_cpu_set)->tp_name);
goto error;
}
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
if (!py_cpu_seq)
goto error;
seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
CPU_ZERO(&cpu_set);
for (i = 0; i < seq_len; i++) {
PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i);
#if PY_MAJOR_VERSION >= 3
long value = PyLong_AsLong(item);
#else
long value = PyInt_AsLong(item);
#endif
if ((value == -1) || PyErr_Occurred()) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, "invalid CPU value");
goto error;
}
CPU_SET(value, &cpu_set);
}
len = sizeof(cpu_set);
if (sched_setaffinity(pid, len, &cpu_set)) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
Py_DECREF(py_cpu_seq);
Py_RETURN_NONE;
error:
if (py_cpu_seq != NULL)
Py_DECREF(py_cpu_seq);
return NULL;
}
/*
* Return currently connected users as a list of tuples.
*/
static PyObject *
psutil_users(PyObject *self, PyObject *args) {
struct utmp *ut;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_user_proc = NULL;
if (py_retlist == NULL)
return NULL;
setutent();
while (NULL != (ut = getutent())) {
py_tuple = NULL;
py_user_proc = NULL;
if (ut->ut_type == USER_PROCESS)
py_user_proc = Py_True;
else
py_user_proc = Py_False;
py_tuple = Py_BuildValue(
"(sssfO)",
ut->ut_user, // username
ut->ut_line, // tty
ut->ut_host, // hostname
(float)ut->ut_tv.tv_sec, // tstamp
py_user_proc // (bool) user process
);
if (! py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
endutent();
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_user_proc);
Py_DECREF(py_retlist);
endutent();
return NULL;
}
/*
* Return stats about a particular network
* interface. References:
* https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py
* http://www.i-scream.org/libstatgrab/
*/
static PyObject*
psutil_net_if_duplex_speed(PyObject* self, PyObject* args) {
char *nic_name;
int sock = 0;
int ret;
int duplex;
int speed;
struct ifreq ifr;
struct ethtool_cmd ethcmd;
PyObject *py_retlist = NULL;
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
goto error;
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
// duplex and speed
memset(&ethcmd, 0, sizeof ethcmd);
ethcmd.cmd = ETHTOOL_GSET;
ifr.ifr_data = (void *)&ethcmd;
ret = ioctl(sock, SIOCETHTOOL, &ifr);
if (ret != -1) {
duplex = ethcmd.duplex;
speed = ethcmd.speed;
}
else {
if ((errno == EOPNOTSUPP) || (errno == EINVAL)) {
// EOPNOTSUPP may occur in case of wi-fi cards.
// For EINVAL see:
// https://github.com/giampaolo/psutil/issues/797
// #issuecomment-202999532
duplex = DUPLEX_UNKNOWN;
speed = 0;
}
else {
goto error;
}
}
close(sock);
py_retlist = Py_BuildValue("[ii]", duplex, speed);
if (!py_retlist)
goto error;
return py_retlist;
error:
if (sock != -1)
close(sock);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
/*
* Define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] = {
// --- per-process functions
#if PSUTIL_HAVE_IOPRIO
{"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS,
"Get process I/O priority"},
{"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS,
"Set process I/O priority"},
#endif
{"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
"Return process CPU affinity as a Python long (the bitmask)."},
{"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
"Set process CPU affinity; expects a bitmask."},
// --- system related functions
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
"Return disk mounted partitions as a list of tuples including "
"device, mount point and filesystem type"},
{"users", psutil_users, METH_VARARGS,
"Return currently connected users as a list of tuples"},
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
"Return duplex and speed info about a NIC"},
// --- linux specific
{"linux_sysinfo", psutil_linux_sysinfo, METH_VARARGS,
"A wrapper around sysinfo(), return system memory usage statistics"},
#if PSUTIL_HAVE_PRLIMIT
{"linux_prlimit", psutil_linux_prlimit, METH_VARARGS,
"Get or set process resource limits."},
#endif
{NULL, NULL, 0, NULL}
};
struct module_state {
PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_linux_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef
moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_linux",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_linux_traverse,
psutil_linux_clear,
NULL
};
#define INITERROR return NULL
PyMODINIT_FUNC PyInit__psutil_linux(void)
#else
#define INITERROR return
void init_psutil_linux(void)
#endif
{
PyObject *v;
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
#endif
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
#if PSUTIL_HAVE_PRLIMIT
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA);
PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE);
PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS);
PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE);
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
#if defined(HAVE_LONG_LONG)
if (sizeof(RLIM_INFINITY) > sizeof(long)) {
v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
} else
#endif
{
v = PyLong_FromLong((long) RLIM_INFINITY);
}
if (v) {
PyModule_AddObject(module, "RLIM_INFINITY", v);
}
#ifdef RLIMIT_MSGQUEUE
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
#endif
#ifdef RLIMIT_NICE
PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE);
#endif
#ifdef RLIMIT_RTPRIO
PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO);
#endif
#ifdef RLIMIT_RTTIME
PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME);
#endif
#ifdef RLIMIT_SIGPENDING
PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING);
#endif
#endif
PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF);
PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
if (module == NULL)
INITERROR;
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
-1910
View File
File diff suppressed because it is too large Load Diff
-619
View File
@@ -1,619 +0,0 @@
/*
* 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 <Python.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#ifdef PSUTIL_SUNOS10
#include "arch/solaris/v10/ifaddrs.h"
#else
#include <ifaddrs.h>
#endif
#if defined(PSUTIL_LINUX)
#include <netdb.h>
#include <linux/if_packet.h>
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
#include <netdb.h>
#include <netinet/in.h>
#include <net/if_dl.h>
#include <sys/sockio.h>
#include <net/if_media.h>
#include <net/if.h>
#elif defined(PSUTIL_SUNOS)
#include <netdb.h>
#include <sys/sockio.h>
#endif
/*
* Given a PID return process priority as a Python integer.
*/
static PyObject *
psutil_posix_getpriority(PyObject *self, PyObject *args) {
long pid;
int priority;
errno = 0;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
#ifdef PSUTIL_OSX
priority = getpriority(PRIO_PROCESS, (id_t)pid);
#else
priority = getpriority(PRIO_PROCESS, pid);
#endif
if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
return Py_BuildValue("i", priority);
}
/*
* Given a PID and a value change process priority.
*/
static PyObject *
psutil_posix_setpriority(PyObject *self, PyObject *args) {
long pid;
int priority;
int retval;
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
return NULL;
#ifdef PSUTIL_OSX
retval = setpriority(PRIO_PROCESS, (id_t)pid, priority);
#else
retval = setpriority(PRIO_PROCESS, pid, priority);
#endif
if (retval == -1)
return PyErr_SetFromErrno(PyExc_OSError);
Py_RETURN_NONE;
}
/*
* Translate a sockaddr struct into a Python string.
* Return None if address family is not AF_INET* or AF_PACKET.
*/
static PyObject *
psutil_convert_ipaddr(struct sockaddr *addr, int family) {
char buf[NI_MAXHOST];
int err;
int addrlen;
size_t n;
size_t len;
const char *data;
char *ptr;
if (addr == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
else if (family == AF_INET || family == AF_INET6) {
if (family == AF_INET)
addrlen = sizeof(struct sockaddr_in);
else
addrlen = sizeof(struct sockaddr_in6);
err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
NI_NUMERICHOST);
if (err != 0) {
// XXX we get here on FreeBSD when processing 'lo' / AF_INET6
// broadcast. Not sure what to do other than returning None.
// ifconfig does not show anything BTW.
//PyErr_Format(PyExc_RuntimeError, gai_strerror(err));
//return NULL;
Py_INCREF(Py_None);
return Py_None;
}
else {
return Py_BuildValue("s", buf);
}
}
#ifdef PSUTIL_LINUX
else if (family == AF_PACKET) {
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
len = lladdr->sll_halen;
data = (const char *)lladdr->sll_addr;
}
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
else if (addr->sa_family == AF_LINK) {
// Note: prior to Python 3.4 socket module does not expose
// AF_LINK so we'll do.
struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr;
len = dladdr->sdl_alen;
data = LLADDR(dladdr);
}
#endif
else {
// unknown family
Py_INCREF(Py_None);
return Py_None;
}
// AF_PACKET or AF_LINK
if (len > 0) {
ptr = buf;
for (n = 0; n < len; ++n) {
sprintf(ptr, "%02x:", data[n] & 0xff);
ptr += 3;
}
*--ptr = '\0';
return Py_BuildValue("s", buf);
}
else {
Py_INCREF(Py_None);
return Py_None;
}
}
/*
* Return NICs information a-la ifconfig as a list of tuples.
* TODO: on Solaris we won't get any MAC address.
*/
static PyObject*
psutil_net_if_addrs(PyObject* self, PyObject* args) {
struct ifaddrs *ifaddr, *ifa;
int family;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_address = NULL;
PyObject *py_netmask = NULL;
PyObject *py_broadcast = NULL;
PyObject *py_ptp = NULL;
if (py_retlist == NULL)
return NULL;
if (getifaddrs(&ifaddr) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
family = ifa->ifa_addr->sa_family;
py_address = psutil_convert_ipaddr(ifa->ifa_addr, family);
// If the primary address can't be determined just skip it.
// I've never seen this happen on Linux but I did on FreeBSD.
if (py_address == Py_None)
continue;
if (py_address == NULL)
goto error;
py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
if (py_netmask == NULL)
goto error;
if (ifa->ifa_flags & IFF_BROADCAST) {
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
Py_INCREF(Py_None);
py_ptp = Py_None;
}
else if (ifa->ifa_flags & IFF_POINTOPOINT) {
py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family);
Py_INCREF(Py_None);
py_broadcast = Py_None;
}
else {
Py_INCREF(Py_None);
Py_INCREF(Py_None);
py_broadcast = Py_None;
py_ptp = Py_None;
}
if ((py_broadcast == NULL) || (py_ptp == NULL))
goto error;
py_tuple = Py_BuildValue(
"(siOOOO)",
ifa->ifa_name,
family,
py_address,
py_netmask,
py_broadcast,
py_ptp
);
if (! py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
Py_DECREF(py_address);
Py_DECREF(py_netmask);
Py_DECREF(py_broadcast);
Py_DECREF(py_ptp);
}
freeifaddrs(ifaddr);
return py_retlist;
error:
if (ifaddr != NULL)
freeifaddrs(ifaddr);
Py_DECREF(py_retlist);
Py_XDECREF(py_tuple);
Py_XDECREF(py_address);
Py_XDECREF(py_netmask);
Py_XDECREF(py_broadcast);
Py_XDECREF(py_ptp);
return NULL;
}
/*
* Return NIC MTU. References:
* http://www.i-scream.org/libstatgrab/
*/
static PyObject *
psutil_net_if_mtu(PyObject *self, PyObject *args) {
char *nic_name;
int sock = 0;
int ret;
#ifdef PSUTIL_SUNOS10
struct lifreq lifr;
#else
struct ifreq ifr;
#endif
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
goto error;
#ifdef PSUTIL_SUNOS10
strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name));
ret = ioctl(sock, SIOCGIFMTU, &lifr);
#else
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
ret = ioctl(sock, SIOCGIFMTU, &ifr);
#endif
if (ret == -1)
goto error;
close(sock);
#ifdef PSUTIL_SUNOS10
return Py_BuildValue("i", lifr.lifr_mtu);
#else
return Py_BuildValue("i", ifr.ifr_mtu);
#endif
error:
if (sock != 0)
close(sock);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
/*
* Inspect NIC flags, returns a bool indicating whether the NIC is
* running. References:
* http://www.i-scream.org/libstatgrab/
*/
static PyObject *
psutil_net_if_flags(PyObject *self, PyObject *args) {
char *nic_name;
int sock = 0;
int ret;
struct ifreq ifr;
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
goto error;
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
if (ret == -1)
goto error;
close(sock);
if ((ifr.ifr_flags & IFF_UP) != 0)
return Py_BuildValue("O", Py_True);
else
return Py_BuildValue("O", Py_False);
error:
if (sock != 0)
close(sock);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
/*
* net_if_stats() OSX/BSD implementation.
*/
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
int psutil_get_nic_speed(int ifm_active) {
// Determine NIC speed. Taken from:
// http://www.i-scream.org/libstatgrab/
// Assuming only ETHER devices
switch(IFM_TYPE(ifm_active)) {
case IFM_ETHER:
switch(IFM_SUBTYPE(ifm_active)) {
#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \
|| (IFM_10G_LR != IFM_HPNA_1))
// HomePNA 1.0 (1Mb/s)
case(IFM_HPNA_1):
return 1;
#endif
// 10 Mbit
case(IFM_10_T): // 10BaseT - RJ45
case(IFM_10_2): // 10Base2 - Thinnet
case(IFM_10_5): // 10Base5 - AUI
case(IFM_10_STP): // 10BaseT over shielded TP
case(IFM_10_FL): // 10baseFL - Fiber
return 10;
// 100 Mbit
case(IFM_100_TX): // 100BaseTX - RJ45
case(IFM_100_FX): // 100BaseFX - Fiber
case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3
case(IFM_100_VG): // 100VG-AnyLAN
case(IFM_100_T2): // 100BaseT2
return 100;
// 1000 Mbit
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
#if defined(IFM_1000_TX) && !defined(PSUTIL_OPENBSD)
// FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h
case(IFM_1000_TX):
#endif
#ifdef IFM_1000_FX
case(IFM_1000_FX):
#endif
#ifdef IFM_1000_T
case(IFM_1000_T):
#endif
return 1000;
#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \
|| defined(IFM_10G_T)
#ifdef IFM_10G_SR
case(IFM_10G_SR):
#endif
#ifdef IFM_10G_LR
case(IFM_10G_LR):
#endif
#ifdef IFM_10G_CX4
case(IFM_10G_CX4):
#endif
#ifdef IFM_10G_TWINAX
case(IFM_10G_TWINAX):
#endif
#ifdef IFM_10G_TWINAX_LONG
case(IFM_10G_TWINAX_LONG):
#endif
#ifdef IFM_10G_T
case(IFM_10G_T):
#endif
return 10000;
#endif
#if defined(IFM_2500_SX)
#ifdef IFM_2500_SX
case(IFM_2500_SX):
#endif
return 2500;
#endif // any 2.5GBit stuff...
// We don't know what it is
default:
return 0;
}
break;
#ifdef IFM_TOKEN
case IFM_TOKEN:
switch(IFM_SUBTYPE(ifm_active)) {
case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9
case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45
return 4;
case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9
case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45
return 16;
#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100)
#ifdef IFM_TOK_STP100
case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9
#endif
#ifdef IFM_TOK_UTP100
case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45
#endif
return 100;
#endif
// We don't know what it is
default:
return 0;
}
break;
#endif
#ifdef IFM_FDDI
case IFM_FDDI:
switch(IFM_SUBTYPE(ifm_active)) {
// We don't know what it is
default:
return 0;
}
break;
#endif
case IFM_IEEE80211:
switch(IFM_SUBTYPE(ifm_active)) {
case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps
case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps
return 1;
case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps
case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps
return 2;
case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps
return 5;
case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps
return 11;
case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps
return 22;
// We don't know what it is
default:
return 0;
}
break;
default:
return 0;
}
}
/*
* Return stats about a particular network interface.
* References:
* http://www.i-scream.org/libstatgrab/
*/
static PyObject *
psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
char *nic_name;
int sock = 0;
int ret;
int duplex;
int speed;
struct ifreq ifr;
struct ifmediareq ifmed;
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1)
goto error;
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
// speed / duplex
memset(&ifmed, 0, sizeof(struct ifmediareq));
strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name));
ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed);
if (ret == -1) {
speed = 0;
duplex = 0;
}
else {
speed = psutil_get_nic_speed(ifmed.ifm_active);
if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active)
duplex = 2;
else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active)
duplex = 1;
else
duplex = 0;
}
close(sock);
return Py_BuildValue("[ii]", duplex, speed);
error:
if (sock != 0)
close(sock);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
#endif // net_if_stats() OSX/BSD implementation
/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
PsutilMethods[] = {
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
"Return process priority"},
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
"Set process priority"},
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
"Retrieve NICs information"},
{"net_if_mtu", psutil_net_if_mtu, METH_VARARGS,
"Retrieve NIC MTU"},
{"net_if_flags", psutil_net_if_flags, METH_VARARGS,
"Retrieve NIC flags"},
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
"Return NIC stats."},
#endif
{NULL, NULL, 0, NULL}
};
struct module_state {
PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
#endif
#if PY_MAJOR_VERSION >= 3
static int
psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int
psutil_posix_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"psutil_posix",
NULL,
sizeof(struct module_state),
PsutilMethods,
NULL,
psutil_posix_traverse,
psutil_posix_clear,
NULL
};
#define INITERROR return NULL
PyMODINIT_FUNC PyInit__psutil_posix(void)
#else
#define INITERROR return
void init_psutil_posix(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
#endif
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS)
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
#endif
if (module == NULL)
INITERROR;
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
-5
View File
@@ -1,5 +0,0 @@
/*
* 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.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-965
View File
@@ -1,965 +0,0 @@
# 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 contextlib
import errno
import functools
import os
import sys
from collections import namedtuple
from . import _common
try:
from . import _psutil_windows as cext
except ImportError as err:
if str(err).lower().startswith("dll load failed") and \
sys.getwindowsversion()[0] < 6:
# We may get here if:
# 1) we are on an old Windows version
# 2) psutil was installed via pip + wheel
# See: https://github.com/giampaolo/psutil/issues/811
# It must be noted that psutil can still (kind of) work
# on outdated systems if compiled / installed from sources,
# but if we get here it means this this was a wheel (or exe).
msg = "this Windows version is too old (< Windows Vista); "
msg += "psutil 3.4.2 is the latest version which supports Windows "
msg += "2000, XP and 2003 server"
raise RuntimeError(msg)
else:
raise
from ._common import conn_tmap
from ._common import isfile_strict
from ._common import parse_environ_block
from ._common import sockfam_to_enum
from ._common import socktype_to_enum
from ._common import usage_percent
from ._common import memoize_when_activated
from ._compat import long
from ._compat import lru_cache
from ._compat import PY3
from ._compat import xrange
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
from ._psutil_windows import HIGH_PRIORITY_CLASS
from ._psutil_windows import IDLE_PRIORITY_CLASS
from ._psutil_windows import NORMAL_PRIORITY_CLASS
from ._psutil_windows import REALTIME_PRIORITY_CLASS
if sys.version_info >= (3, 4):
import enum
else:
enum = None
# process priority constants, import from __init__.py:
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
__extra__all__ = [
"win_service_iter", "win_service_get",
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
"CONN_DELETE_TCB",
"AF_LINK",
]
# =====================================================================
# --- globals
# =====================================================================
CONN_DELETE_TCB = "DELETE_TCB"
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES,
cext.ERROR_ACCESS_DENIED])
if enum is None:
AF_LINK = -1
else:
AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1})
AF_LINK = AddressFamily.AF_LINK
TCP_STATUSES = {
cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED,
cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT,
cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV,
cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1,
cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2,
cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT,
cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE,
cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK,
cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN,
cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING,
cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB,
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
}
if enum is not None:
class Priority(enum.IntEnum):
ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS
IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS
globals().update(Priority.__members__)
pinfo_map = dict(
num_handles=0,
ctx_switches=1,
user_time=2,
kernel_time=3,
create_time=4,
num_threads=5,
io_rcount=6,
io_wcount=7,
io_rbytes=8,
io_wbytes=9,
io_count_others=10,
io_bytes_others=11,
num_page_faults=12,
peak_wset=13,
wset=14,
peak_paged_pool=15,
paged_pool=16,
peak_non_paged_pool=17,
non_paged_pool=18,
pagefile=19,
peak_pagefile=20,
mem_private=21,
)
# these get overwritten on "import psutil" from the __init__.py file
NoSuchProcess = None
AccessDenied = None
TimeoutExpired = None
# =====================================================================
# --- named tuples
# =====================================================================
# psutil.cpu_times()
scputimes = namedtuple('scputimes',
['user', 'system', 'idle', 'interrupt', 'dpc'])
# psutil.virtual_memory()
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
# psutil.Process.memory_info()
pmem = namedtuple(
'pmem', ['rss', 'vms',
'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool',
'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool',
'pagefile', 'peak_pagefile', 'private'])
# psutil.Process.memory_full_info()
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
# psutil.Process.memory_maps(grouped=True)
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
# psutil.Process.memory_maps(grouped=False)
pmmap_ext = namedtuple(
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
# psutil.Process.io_counters()
pio = namedtuple('pio', ['read_count', 'write_count',
'read_bytes', 'write_bytes',
'other_count', 'other_bytes'])
# =====================================================================
# --- utils
# =====================================================================
@lru_cache(maxsize=512)
def convert_dos_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 = cext.win32_QueryDosDevice(rawdrive)
return os.path.join(driveletter, s[len(rawdrive):])
def py2_strencode(s, encoding=sys.getfilesystemencoding()):
"""Encode a string in the given encoding. Falls back on returning
the string as is if it can't be encoded.
"""
if PY3 or isinstance(s, str):
return s
else:
try:
return s.encode(encoding)
except UnicodeEncodeError:
# Filesystem codec failed, return the plain unicode
# string (this should never happen).
return s
# =====================================================================
# --- memory
# =====================================================================
def virtual_memory():
"""System virtual memory as a namedtuple."""
mem = cext.virtual_mem()
totphys, availphys, totpagef, availpagef, totvirt, freevirt = mem
#
total = totphys
avail = availphys
free = availphys
used = total - avail
percent = usage_percent((total - avail), total, _round=1)
return svmem(total, avail, percent, used, free)
def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
mem = cext.virtual_mem()
total = mem[2]
free = mem[3]
used = total - free
percent = usage_percent(used, total, _round=1)
return _common.sswap(total, used, free, percent, 0, 0)
# =====================================================================
# --- disk
# =====================================================================
disk_io_counters = cext.disk_io_counters
def disk_usage(path):
"""Return disk usage associated with path."""
try:
total, free = cext.disk_usage(path)
except WindowsError:
if not os.path.exists(path):
msg = "No such file or directory: '%s'" % path
raise OSError(errno.ENOENT, msg)
raise
used = total - free
percent = usage_percent(used, total, _round=1)
return _common.sdiskusage(total, used, free, percent)
def disk_partitions(all):
"""Return disk partitions."""
rawlist = cext.disk_partitions(all)
return [_common.sdiskpart(*x) for x in rawlist]
# =====================================================================
# --- CPU
# =====================================================================
def cpu_times():
"""Return system CPU times as a named tuple."""
user, system, idle = cext.cpu_times()
# Internally, GetSystemTimes() is used, and it doesn't return
# interrupt and dpc times. cext.per_cpu_times() does, so we
# rely on it to get those only.
percpu_summed = scputimes(*[sum(n) for n in zip(*cext.per_cpu_times())])
return scputimes(user, system, idle,
percpu_summed.interrupt, percpu_summed.dpc)
def per_cpu_times():
"""Return system per-CPU times as a list of named tuples."""
ret = []
for user, system, idle, interrupt, dpc in cext.per_cpu_times():
item = scputimes(user, system, idle, interrupt, dpc)
ret.append(item)
return ret
def cpu_count_logical():
"""Return the number of logical CPUs in the system."""
return cext.cpu_count_logical()
def cpu_count_physical():
"""Return the number of physical CPUs in the system."""
return cext.cpu_count_phys()
def cpu_stats():
"""Return CPU statistics."""
ctx_switches, interrupts, dpcs, syscalls = cext.cpu_stats()
soft_interrupts = 0
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
syscalls)
def cpu_freq():
"""Return CPU frequency.
On Windows per-cpu frequency is not supported.
"""
curr, max_ = cext.cpu_freq()
min_ = 0.0
return [_common.scpufreq(float(curr), min_, float(max_))]
# =====================================================================
# --- network
# =====================================================================
def net_connections(kind, _pid=-1):
"""Return socket connections. If pid == -1 return system-wide
connections (as opposed to connections opened by one process only).
"""
if kind not in conn_tmap:
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
rawlist = cext.net_connections(_pid, families, types)
ret = set()
for item in rawlist:
fd, fam, type, laddr, raddr, status, pid = item
status = TCP_STATUSES[status]
fam = sockfam_to_enum(fam)
type = socktype_to_enum(type)
if _pid == -1:
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
else:
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.add(nt)
return list(ret)
def net_if_stats():
"""Get NIC stats (isup, duplex, speed, mtu)."""
ret = cext.net_if_stats()
for name, items in ret.items():
name = py2_strencode(name)
isup, duplex, speed, mtu = items
if hasattr(_common, 'NicDuplex'):
duplex = _common.NicDuplex(duplex)
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
def net_io_counters():
"""Return network I/O statistics for every network interface
installed on the system as a dict of raw tuples.
"""
ret = cext.net_io_counters()
return dict([(py2_strencode(k), v) for k, v in ret.items()])
def net_if_addrs():
"""Return the addresses associated to each NIC."""
ret = []
for items in cext.net_if_addrs():
items = list(items)
items[0] = py2_strencode(items[0])
ret.append(items)
return ret
# =====================================================================
# --- sensors
# =====================================================================
def sensors_battery():
"""Return battery information."""
# For constants meaning see:
# https://msdn.microsoft.com/en-us/library/windows/desktop/
# aa373232(v=vs.85).aspx
acline_status, flags, percent, secsleft = cext.sensors_battery()
power_plugged = acline_status == 1
no_battery = bool(flags & 128)
charging = bool(flags & 8)
if no_battery:
return None
if power_plugged or charging:
secsleft = _common.POWER_TIME_UNLIMITED
elif secsleft == -1:
secsleft = _common.POWER_TIME_UNKNOWN
return _common.sbattery(percent, secsleft, power_plugged)
# =====================================================================
# --- other system functions
# =====================================================================
def boot_time():
"""The system boot time expressed in seconds since the epoch."""
return cext.boot_time()
def users():
"""Return currently connected users as a list of namedtuples."""
retlist = []
rawlist = cext.users()
for item in rawlist:
user, hostname, tstamp = item
user = py2_strencode(user)
nt = _common.suser(user, None, hostname, tstamp)
retlist.append(nt)
return retlist
# =====================================================================
# --- Windows services
# =====================================================================
def win_service_iter():
"""Return a list of WindowsService instances."""
for name, display_name in cext.winservice_enumerate():
yield WindowsService(name, display_name)
def win_service_get(name):
"""Open a Windows service and return it as a WindowsService instance."""
service = WindowsService(name, None)
service._display_name = service._query_config()['display_name']
return service
class WindowsService(object):
"""Represents an installed Windows service."""
def __init__(self, name, display_name):
self._name = name
self._display_name = display_name
def __str__(self):
details = "(name=%r, display_name=%r)" % (
self._name, self._display_name)
return "%s%s" % (self.__class__.__name__, details)
def __repr__(self):
return "<%s at %s>" % (self.__str__(), id(self))
def __eq__(self, other):
# Test for equality with another WindosService object based
# on name.
if not isinstance(other, WindowsService):
return NotImplemented
return self._name == other._name
def __ne__(self, other):
return not self == other
def _query_config(self):
with self._wrap_exceptions():
display_name, binpath, username, start_type = \
cext.winservice_query_config(self._name)
# XXX - update _self.display_name?
return dict(
display_name=display_name,
binpath=binpath,
username=username,
start_type=start_type)
def _query_status(self):
with self._wrap_exceptions():
status, pid = cext.winservice_query_status(self._name)
if pid == 0:
pid = None
return dict(status=status, pid=pid)
@contextlib.contextmanager
def _wrap_exceptions(self):
"""Ctx manager which translates bare OSError and WindowsError
exceptions into NoSuchProcess and AccessDenied.
"""
try:
yield
except WindowsError as err:
NO_SUCH_SERVICE_SET = (cext.ERROR_INVALID_NAME,
cext.ERROR_SERVICE_DOES_NOT_EXIST)
if err.errno in ACCESS_DENIED_SET:
raise AccessDenied(
pid=None, name=self._name,
msg="service %r is not querable (not enough privileges)" %
self._name)
elif err.errno in NO_SUCH_SERVICE_SET or \
err.winerror in NO_SUCH_SERVICE_SET:
raise NoSuchProcess(
pid=None, name=self._name,
msg="service %r does not exist)" % self._name)
else:
raise
# config query
def name(self):
"""The service name. This string is how a service is referenced
and can be passed to win_service_get() to get a new
WindowsService instance.
"""
return self._name
def display_name(self):
"""The service display name. The value is cached when this class
is instantiated.
"""
return self._display_name
def binpath(self):
"""The fully qualified path to the service binary/exe file as
a string, including command line arguments.
"""
return self._query_config()['binpath']
def username(self):
"""The name of the user that owns this service."""
return self._query_config()['username']
def start_type(self):
"""A string which can either be "automatic", "manual" or
"disabled".
"""
return self._query_config()['start_type']
# status query
def pid(self):
"""The process PID, if any, else None. This can be passed
to Process class to control the service's process.
"""
return self._query_status()['pid']
def status(self):
"""Service status as a string."""
return self._query_status()['status']
def description(self):
"""Service long description."""
return cext.winservice_query_descr(self.name())
# utils
def as_dict(self):
"""Utility method retrieving all the information above as a
dictionary.
"""
d = self._query_config()
d.update(self._query_status())
d['name'] = self.name()
d['display_name'] = self.display_name()
d['description'] = self.description()
return d
# actions
# XXX: the necessary C bindings for start() and stop() are
# implemented but for now I prefer not to expose them.
# I may change my mind in the future. Reasons:
# - they require Administrator privileges
# - can't implement a timeout for stop() (unless by using a thread,
# which sucks)
# - would require adding ServiceAlreadyStarted and
# ServiceAlreadyStopped exceptions, adding two new APIs.
# - we might also want to have modify(), which would basically mean
# rewriting win32serviceutil.ChangeServiceConfig, which involves a
# lot of stuff (and API constants which would pollute the API), see:
# http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/
# win32/lib/win32serviceutil.py.html#0175
# - psutil is typically about "read only" monitoring stuff;
# win_service_* APIs should only be used to retrieve a service and
# check whether it's running
# def start(self, timeout=None):
# with self._wrap_exceptions():
# cext.winservice_start(self.name())
# if timeout:
# giveup_at = time.time() + timeout
# while True:
# if self.status() == "running":
# return
# else:
# if time.time() > giveup_at:
# raise TimeoutExpired(timeout)
# else:
# time.sleep(.1)
# def stop(self):
# # Note: timeout is not implemented because it's just not
# # possible, see:
# # http://stackoverflow.com/questions/11973228/
# with self._wrap_exceptions():
# return cext.winservice_stop(self.name())
# =====================================================================
# --- processes
# =====================================================================
pids = cext.pids
pid_exists = cext.pid_exists
ppid_map = cext.ppid_map # used internally by Process.children()
def wrap_exceptions(fun):
"""Decorator which translates bare OSError and WindowsError
exceptions into NoSuchProcess and AccessDenied.
"""
@functools.wraps(fun)
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
raise AccessDenied(self.pid, self._name)
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._name)
raise
return wrapper
class Process(object):
"""Wrapper class around underlying C implementation."""
__slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
self._ppid = None
# --- oneshot() stuff
def oneshot_enter(self):
self.oneshot_info.cache_activate()
def oneshot_exit(self):
self.oneshot_info.cache_deactivate()
@memoize_when_activated
def oneshot_info(self):
"""Return multiple information about this process as a
raw tuple.
"""
ret = cext.proc_info(self.pid)
assert len(ret) == len(pinfo_map)
return ret
@wrap_exceptions
def name(self):
"""Return process name, which on Windows is always the final
part of the executable.
"""
# This is how PIDs 0 and 4 are always represented in taskmgr
# and process-hacker.
if self.pid == 0:
return "System Idle Process"
elif self.pid == 4:
return "System"
else:
try:
# Note: this will fail with AD for most PIDs owned
# by another user but it's faster.
return py2_strencode(os.path.basename(self.exe()))
except AccessDenied:
return py2_strencode(cext.proc_name(self.pid))
@wrap_exceptions
def exe(self):
# Note: os.path.exists(path) may return False even if the file
# is there, see:
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
# see https://github.com/giampaolo/psutil/issues/414
# see https://github.com/giampaolo/psutil/issues/528
if self.pid in (0, 4):
raise AccessDenied(self.pid, self._name)
return py2_strencode(convert_dos_path(cext.proc_exe(self.pid)))
@wrap_exceptions
def cmdline(self):
ret = cext.proc_cmdline(self.pid)
if PY3:
return ret
else:
return [py2_strencode(s) for s in ret]
@wrap_exceptions
def environ(self):
return parse_environ_block(cext.proc_environ(self.pid))
def ppid(self):
try:
return ppid_map()[self.pid]
except KeyError:
raise NoSuchProcess(self.pid, self._name)
def _get_raw_meminfo(self):
try:
return cext.proc_memory_info(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
# TODO: the C ext can probably be refactored in order
# to get this from cext.proc_info()
info = self.oneshot_info()
return (
info[pinfo_map['num_page_faults']],
info[pinfo_map['peak_wset']],
info[pinfo_map['wset']],
info[pinfo_map['peak_paged_pool']],
info[pinfo_map['paged_pool']],
info[pinfo_map['peak_non_paged_pool']],
info[pinfo_map['non_paged_pool']],
info[pinfo_map['pagefile']],
info[pinfo_map['peak_pagefile']],
info[pinfo_map['mem_private']],
)
raise
@wrap_exceptions
def memory_info(self):
# on Windows RSS == WorkingSetSize and VSM == PagefileUsage.
# Underlying C function returns fields of PROCESS_MEMORY_COUNTERS
# struct.
t = self._get_raw_meminfo()
rss = t[2] # wset
vms = t[7] # pagefile
return pmem(*(rss, vms, ) + t)
@wrap_exceptions
def memory_full_info(self):
basic_mem = self.memory_info()
uss = cext.proc_memory_uss(self.pid)
return pfullmem(*basic_mem + (uss, ))
def memory_maps(self):
try:
raw = cext.proc_memory_maps(self.pid)
except OSError as err:
# XXX - can't use wrap_exceptions decorator as we're
# returning a generator; probably needs refactoring.
if err.errno in ACCESS_DENIED_SET:
raise AccessDenied(self.pid, self._name)
if err.errno == errno.ESRCH:
raise NoSuchProcess(self.pid, self._name)
raise
else:
for addr, perm, path, rss in raw:
path = convert_dos_path(path)
addr = hex(addr)
yield (addr, perm, path, rss)
@wrap_exceptions
def kill(self):
return cext.proc_kill(self.pid)
@wrap_exceptions
def send_signal(self, sig):
os.kill(self.pid, sig)
@wrap_exceptions
def wait(self, timeout=None):
if timeout is None:
cext_timeout = cext.INFINITE
else:
# WaitForSingleObject() expects time in milliseconds
cext_timeout = int(timeout * 1000)
ret = cext.proc_wait(self.pid, cext_timeout)
if ret == WAIT_TIMEOUT:
raise TimeoutExpired(timeout, self.pid, self._name)
return ret
@wrap_exceptions
def username(self):
if self.pid in (0, 4):
return 'NT AUTHORITY\\SYSTEM'
return cext.proc_username(self.pid)
@wrap_exceptions
def create_time(self):
# special case for kernel process PIDs; return system boot time
if self.pid in (0, 4):
return boot_time()
try:
return cext.proc_create_time(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
return self.oneshot_info()[pinfo_map['create_time']]
raise
@wrap_exceptions
def num_threads(self):
return self.oneshot_info()[pinfo_map['num_threads']]
@wrap_exceptions
def threads(self):
rawlist = cext.proc_threads(self.pid)
retlist = []
for thread_id, utime, stime in rawlist:
ntuple = _common.pthread(thread_id, utime, stime)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def cpu_times(self):
try:
user, system = cext.proc_cpu_times(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
info = self.oneshot_info()
user = info[pinfo_map['user_time']]
system = info[pinfo_map['kernel_time']]
else:
raise
# Children user/system times are not retrievable (set to 0).
return _common.pcputimes(user, system, 0, 0)
@wrap_exceptions
def suspend(self):
return cext.proc_suspend(self.pid)
@wrap_exceptions
def resume(self):
return cext.proc_resume(self.pid)
@wrap_exceptions
def cwd(self):
if self.pid in (0, 4):
raise AccessDenied(self.pid, self._name)
# return a normalized pathname since the native C function appends
# "\\" at the and of the path
path = cext.proc_cwd(self.pid)
return py2_strencode(os.path.normpath(path))
@wrap_exceptions
def open_files(self):
if self.pid in (0, 4):
return []
ret = set()
# Filenames come in in native format like:
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
# Convert the first part in the corresponding drive letter
# (e.g. "C:\") by using Windows's QueryDosDevice()
raw_file_names = cext.proc_open_files(self.pid)
for _file in raw_file_names:
_file = convert_dos_path(_file)
if isfile_strict(_file):
if not PY3:
_file = py2_strencode(_file)
ntuple = _common.popenfile(_file, -1)
ret.add(ntuple)
return list(ret)
@wrap_exceptions
def connections(self, kind='inet'):
return net_connections(kind, _pid=self.pid)
@wrap_exceptions
def nice_get(self):
value = cext.proc_priority_get(self.pid)
if enum is not None:
value = Priority(value)
return value
@wrap_exceptions
def nice_set(self, value):
return cext.proc_priority_set(self.pid, value)
# available on Windows >= Vista
if hasattr(cext, "proc_io_priority_get"):
@wrap_exceptions
def ionice_get(self):
return cext.proc_io_priority_get(self.pid)
@wrap_exceptions
def ionice_set(self, value, _):
if _:
raise TypeError("set_proc_ionice() on Windows takes only "
"1 argument (2 given)")
if value not in (2, 1, 0):
raise ValueError("value must be 2 (normal), 1 (low) or 0 "
"(very low); got %r" % value)
return cext.proc_io_priority_set(self.pid, value)
@wrap_exceptions
def io_counters(self):
try:
ret = cext.proc_io_counters(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
info = self.oneshot_info()
ret = (
info[pinfo_map['io_rcount']],
info[pinfo_map['io_wcount']],
info[pinfo_map['io_rbytes']],
info[pinfo_map['io_wbytes']],
info[pinfo_map['io_count_others']],
info[pinfo_map['io_bytes_others']],
)
else:
raise
return pio(*ret)
@wrap_exceptions
def status(self):
suspended = cext.proc_is_suspended(self.pid)
if suspended:
return _common.STATUS_STOPPED
else:
return _common.STATUS_RUNNING
@wrap_exceptions
def cpu_affinity_get(self):
def from_bitmask(x):
return [i for i in xrange(64) if (1 << i) & x]
bitmask = cext.proc_cpu_affinity_get(self.pid)
return from_bitmask(bitmask)
@wrap_exceptions
def cpu_affinity_set(self, value):
def to_bitmask(l):
if not l:
raise ValueError("invalid argument %r" % l)
out = 0
for b in l:
out |= 2 ** b
return out
# SetProcessAffinityMask() states that ERROR_INVALID_PARAMETER
# is returned for an invalid CPU but this seems not to be true,
# therefore we check CPUs validy beforehand.
allcpus = list(range(len(per_cpu_times())))
for cpu in value:
if cpu not in allcpus:
if not isinstance(cpu, (int, long)):
raise TypeError(
"invalid CPU %r; an integer is required" % cpu)
else:
raise ValueError("invalid CPU %r" % cpu)
bitmask = to_bitmask(value)
cext.proc_cpu_affinity_set(self.pid, bitmask)
@wrap_exceptions
def num_handles(self):
try:
return cext.proc_num_handles(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
return self.oneshot_info()[pinfo_map['num_handles']]
raise
@wrap_exceptions
def num_ctx_switches(self):
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
# only voluntary ctx switches are supported
return _common.pctxsw(ctx_switches, 0)
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <Python.h>
typedef struct kinfo_proc kinfo_proc;
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc);
//
PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
PyObject* psutil_get_cmdline(long pid);
PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
#if defined(PSUTIL_FREEBSD)
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
#endif
-631
View File
@@ -1,631 +0,0 @@
/*
* 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 <Python.h>
#include <sys/user.h>
#include <sys/file.h>
#include <sys/socketvar.h> // for struct xsocket
#include <sys/un.h>
#include <sys/unpcb.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <netinet/in.h> // for xinpcb struct
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h> // for struct xtcpcb
#include <netinet/tcp_fsm.h> // for TCP connection states
#include <arpa/inet.h> // for inet_ntop()
#include <net/if_media.h>
#include <libutil.h>
#include "../../_psutil_common.h"
#define HASHSIZE 1009
// a signaler for connections without an actual status
static int PSUTIL_CONN_NONE = 128;
static struct xfile *psutil_xfiles;
static int psutil_nxfiles;
// The tcplist fetching and walking is borrowed from netstat/inet.c.
static char *
psutil_fetch_tcplist(void) {
char *buf;
size_t len;
for (;;) {
if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
buf = malloc(len);
if (buf == NULL) {
PyErr_NoMemory();
return NULL;
}
if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) {
free(buf);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return buf;
}
}
static int
psutil_sockaddr_port(int family, struct sockaddr_storage *ss) {
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
if (family == AF_INET) {
sin = (struct sockaddr_in *)ss;
return (sin->sin_port);
}
else {
sin6 = (struct sockaddr_in6 *)ss;
return (sin6->sin6_port);
}
}
static void *
psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) {
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
if (family == AF_INET) {
sin = (struct sockaddr_in *)ss;
return (&sin->sin_addr);
}
else {
sin6 = (struct sockaddr_in6 *)ss;
return (&sin6->sin6_addr);
}
}
static socklen_t
psutil_sockaddr_addrlen(int family) {
if (family == AF_INET)
return (sizeof(struct in_addr));
else
return (sizeof(struct in6_addr));
}
static int
psutil_sockaddr_matches(int family, int port, void *pcb_addr,
struct sockaddr_storage *ss) {
if (psutil_sockaddr_port(family, ss) != port)
return (0);
return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr,
psutil_sockaddr_addrlen(family)) == 0);
}
static struct tcpcb *
psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
struct tcpcb *tp;
struct inpcb *inp;
struct xinpgen *xig, *oxig;
struct xsocket *so;
oxig = xig = (struct xinpgen *)buf;
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
xig->xig_len > sizeof(struct xinpgen);
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
tp = &((struct xtcpcb *)xig)->xt_tp;
inp = &((struct xtcpcb *)xig)->xt_inp;
so = &((struct xtcpcb *)xig)->xt_socket;
if (so->so_type != kif->kf_sock_type ||
so->xso_family != kif->kf_sock_domain ||
so->xso_protocol != kif->kf_sock_protocol)
continue;
if (kif->kf_sock_domain == AF_INET) {
if (!psutil_sockaddr_matches(
AF_INET, inp->inp_lport, &inp->inp_laddr,
&kif->kf_sa_local))
continue;
if (!psutil_sockaddr_matches(
AF_INET, inp->inp_fport, &inp->inp_faddr,
&kif->kf_sa_peer))
continue;
} else {
if (!psutil_sockaddr_matches(
AF_INET6, inp->inp_lport, &inp->in6p_laddr,
&kif->kf_sa_local))
continue;
if (!psutil_sockaddr_matches(
AF_INET6, inp->inp_fport, &inp->in6p_faddr,
&kif->kf_sa_peer))
continue;
}
return (tp);
}
return NULL;
}
int
psutil_populate_xfiles() {
size_t len;
if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) {
PyErr_NoMemory();
return 0;
}
while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) {
if (errno != ENOMEM) {
PyErr_SetFromErrno(0);
return 0;
}
len *= 2;
if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) {
PyErr_NoMemory();
return 0;
}
}
if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) {
PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch");
return 0;
}
psutil_nxfiles = len / sizeof *psutil_xfiles;
return 1;
}
int
psutil_get_pid_from_sock(int sock_hash) {
struct xfile *xf;
int hash, n;
for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) {
if (xf->xf_data == NULL)
continue;
hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
if (sock_hash == hash)
return xf->xf_pid;
}
return -1;
}
// Reference:
// https://gitorious.org/freebsd/freebsd/source/
// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c
int psutil_gather_inet(int proto, PyObject *py_retlist) {
struct xinpgen *xig, *exig;
struct xinpcb *xip;
struct xtcpcb *xtp;
struct inpcb *inp;
struct xsocket *so;
const char *varname = NULL;
size_t len, bufsize;
void *buf;
int hash;
int retry;
int type;
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
switch (proto) {
case IPPROTO_TCP:
varname = "net.inet.tcp.pcblist";
type = SOCK_STREAM;
break;
case IPPROTO_UDP:
varname = "net.inet.udp.pcblist";
type = SOCK_DGRAM;
break;
}
buf = NULL;
bufsize = 8192;
retry = 5;
do {
for (;;) {
buf = realloc(buf, bufsize);
if (buf == NULL)
continue; // XXX
len = bufsize;
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
break;
if (errno != ENOMEM) {
PyErr_SetFromErrno(0);
goto error;
}
bufsize *= 2;
}
xig = (struct xinpgen *)buf;
exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig);
if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) {
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
goto error;
}
} while (xig->xig_gen != exig->xig_gen && retry--);
for (;;) {
int lport, rport, pid, status, family;
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
if (xig >= exig)
break;
switch (proto) {
case IPPROTO_TCP:
xtp = (struct xtcpcb *)xig;
if (xtp->xt_len != sizeof *xtp) {
PyErr_Format(PyExc_RuntimeError,
"struct xtcpcb size mismatch");
goto error;
}
inp = &xtp->xt_inp;
so = &xtp->xt_socket;
status = xtp->xt_tp.t_state;
break;
case IPPROTO_UDP:
xip = (struct xinpcb *)xig;
if (xip->xi_len != sizeof *xip) {
PyErr_Format(PyExc_RuntimeError,
"struct xinpcb size mismatch");
goto error;
}
inp = &xip->xi_inp;
so = &xip->xi_socket;
status = PSUTIL_CONN_NONE;
break;
default:
PyErr_Format(PyExc_RuntimeError, "invalid proto");
goto error;
}
char lip[200], rip[200];
hash = (int)((uintptr_t)so->xso_so % HASHSIZE);
pid = psutil_get_pid_from_sock(hash);
if (pid < 0)
continue;
lport = ntohs(inp->inp_lport);
rport = ntohs(inp->inp_fport);
if (inp->inp_vflag & INP_IPV4) {
family = AF_INET;
inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip));
inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip));
}
else if (inp->inp_vflag & INP_IPV6) {
family = AF_INET6;
inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip));
inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip));
}
// construct python tuple/list
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
if (rport != 0)
py_raddr = Py_BuildValue("(si)", rip, rport);
else
py_raddr = Py_BuildValue("()");
if (!py_raddr)
goto error;
py_tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr,
py_raddr, status, pid);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
free(buf);
return 1;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
free(buf);
return 0;
}
int psutil_gather_unix(int proto, PyObject *py_retlist) {
struct xunpgen *xug, *exug;
struct xunpcb *xup;
const char *varname = NULL;
const char *protoname = NULL;
size_t len;
size_t bufsize;
void *buf;
int hash;
int retry;
int pid;
struct sockaddr_un *sun;
char path[PATH_MAX];
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
switch (proto) {
case SOCK_STREAM:
varname = "net.local.stream.pcblist";
protoname = "stream";
break;
case SOCK_DGRAM:
varname = "net.local.dgram.pcblist";
protoname = "dgram";
break;
}
buf = NULL;
bufsize = 8192;
retry = 5;
do {
for (;;) {
buf = realloc(buf, bufsize);
if (buf == NULL) {
PyErr_NoMemory();
goto error;
}
len = bufsize;
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
break;
if (errno != ENOMEM) {
PyErr_SetFromErrno(0);
goto error;
}
bufsize *= 2;
}
xug = (struct xunpgen *)buf;
exug = (struct xunpgen *)(void *)
((char *)buf + len - sizeof *exug);
if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) {
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
goto error;
}
} while (xug->xug_gen != exug->xug_gen && retry--);
for (;;) {
xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
if (xug >= exug)
break;
xup = (struct xunpcb *)xug;
if (xup->xu_len != sizeof *xup)
goto error;
hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE);
pid = psutil_get_pid_from_sock(hash);
if (pid < 0)
continue;
sun = (struct sockaddr_un *)&xup->xu_addr;
snprintf(path, sizeof(path), "%.*s",
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
sun->sun_path);
py_tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path,
Py_None, PSUTIL_CONN_NONE, pid);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
Py_INCREF(Py_None);
}
free(buf);
return 1;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
free(buf);
return 0;
}
PyObject*
psutil_net_connections(PyObject* self, PyObject* args) {
// Return system-wide open connections.
PyObject *py_retlist = PyList_New(0);
if (py_retlist == NULL)
return NULL;
if (psutil_populate_xfiles() != 1)
goto error;
if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0)
goto error;
if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0)
goto error;
if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0)
goto error;
if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0)
goto error;
free(psutil_xfiles);
return py_retlist;
error:
Py_DECREF(py_retlist);
free(psutil_xfiles);
return NULL;
}
PyObject *
psutil_proc_connections(PyObject *self, PyObject *args) {
// Return connections opened by process.
long pid;
int i, cnt;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
char *tcplist = NULL;
struct tcpcb *tcp;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
PyObject *py_af_filter = NULL;
PyObject *py_type_filter = NULL;
PyObject *py_family = NULL;
PyObject *py_type = NULL;
if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
goto error;
}
tcplist = psutil_fetch_tcplist();
if (tcplist == NULL) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
for (i = 0; i < cnt; i++) {
int lport, rport, state;
char lip[200], rip[200];
char path[PATH_MAX];
int inseq;
py_tuple = NULL;
py_laddr = NULL;
py_raddr = NULL;
kif = &freep[i];
if (kif->kf_type == KF_TYPE_SOCKET) {
// apply filters
py_family = PyLong_FromLong((long)kif->kf_sock_domain);
inseq = PySequence_Contains(py_af_filter, py_family);
Py_DECREF(py_family);
if (inseq == 0)
continue;
py_type = PyLong_FromLong((long)kif->kf_sock_type);
inseq = PySequence_Contains(py_type_filter, py_type);
Py_DECREF(py_type);
if (inseq == 0)
continue;
// IPv4 / IPv6 socket
if ((kif->kf_sock_domain == AF_INET) ||
(kif->kf_sock_domain == AF_INET6)) {
// fill status
state = PSUTIL_CONN_NONE;
if (kif->kf_sock_type == SOCK_STREAM) {
tcp = psutil_search_tcplist(tcplist, kif);
if (tcp != NULL)
state = (int)tcp->t_state;
}
// build addr and port
inet_ntop(
kif->kf_sock_domain,
psutil_sockaddr_addr(kif->kf_sock_domain,
&kif->kf_sa_local),
lip,
sizeof(lip));
inet_ntop(
kif->kf_sock_domain,
psutil_sockaddr_addr(kif->kf_sock_domain,
&kif->kf_sa_peer),
rip,
sizeof(rip));
lport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
&kif->kf_sa_local));
rport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
&kif->kf_sa_peer));
// construct python tuple/list
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
if (rport != 0)
py_raddr = Py_BuildValue("(si)", rip, rport);
else
py_raddr = Py_BuildValue("()");
if (!py_raddr)
goto error;
py_tuple = Py_BuildValue(
"(iiiNNi)",
kif->kf_fd,
kif->kf_sock_domain,
kif->kf_sock_type,
py_laddr,
py_raddr,
state
);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
// UNIX socket
else if (kif->kf_sock_domain == AF_UNIX) {
struct sockaddr_un *sun;
sun = (struct sockaddr_un *)&kif->kf_sa_local;
snprintf(
path, sizeof(path), "%.*s",
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
sun->sun_path);
py_tuple = Py_BuildValue(
"(iiisOi)",
kif->kf_fd,
kif->kf_sock_domain,
kif->kf_sock_type,
path,
Py_None,
PSUTIL_CONN_NONE
);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
Py_INCREF(Py_None);
}
}
}
free(freep);
free(tcplist);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
Py_DECREF(py_retlist);
if (freep != NULL)
free(freep);
if (tcplist != NULL)
free(tcplist);
return NULL;
}
-11
View File
@@ -1,11 +0,0 @@
/*
* 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 <Python.h>
PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
PyObject* psutil_net_connections(PyObject* self, PyObject* args);
-664
View File
@@ -1,664 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Platform-specific module methods for NetBSD.
*/
#if defined(PSUTIL_NETBSD)
#define _KMEMUSER
#endif
#include <Python.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/swap.h> // for swap_mem
#include <signal.h>
#include <kvm.h>
// connection stuff
#include <netdb.h> // for NI_MAXHOST
#include <sys/socket.h>
#include <sys/sched.h> // for CPUSTATES & CP_*
#define _KERNEL // for DTYPE_*
#include <sys/file.h>
#undef _KERNEL
#include <sys/disk.h> // struct diskstats
#include <netinet/in.h>
#include <arpa/inet.h>
#include "netbsd_socks.h"
#include "netbsd.h"
#include "../../_psutil_common.h"
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
// ============================================================================
// Utility functions
// ============================================================================
int
psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) {
// Fills a kinfo_proc struct based on process pid.
int ret;
int mib[6];
size_t size = sizeof(kinfo_proc);
mib[0] = CTL_KERN;
mib[1] = KERN_PROC2;
mib[2] = KERN_PROC_PID;
mib[3] = pid;
mib[4] = size;
mib[5] = 1;
ret = sysctl((int*)mib, 6, proc, &size, NULL, 0);
if (ret == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
// sysctl stores 0 in the size if we can't find the process information.
if (size == 0) {
NoSuchProcess();
return -1;
}
return 0;
}
struct kinfo_file *
kinfo_getfile(pid_t pid, int* cnt) {
// Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an
// int as arg and returns an array with cnt struct kinfo_file.
int mib[6];
size_t len;
struct kinfo_file* kf;
mib[0] = CTL_KERN;
mib[1] = KERN_FILE2;
mib[2] = KERN_FILE_BYPID;
mib[3] = (int) pid;
mib[4] = sizeof(struct kinfo_file);
mib[5] = 0;
// get the size of what would be returned
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if ((kf = malloc(len)) == NULL) {
PyErr_NoMemory();
return NULL;
}
mib[5] = (int)(len / sizeof(struct kinfo_file));
if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
*cnt = (int)(len / sizeof(struct kinfo_file));
return kf;
}
// XXX: This is no longer used as per
// https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820
// Current implementation uses /proc instead.
// Left here just in case.
PyObject *
psutil_proc_exe(PyObject *self, PyObject *args) {
#if __NetBSD_Version__ >= 799000000
pid_t pid;
char pathname[MAXPATHLEN];
int error;
int mib[4];
int ret;
size_t size;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (pid == 0) {
// else returns ENOENT
return Py_BuildValue("s", "");
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = pid;
mib[3] = KERN_PROC_PATHNAME;
size = sizeof(pathname);
error = sysctl(mib, 4, NULL, &size, NULL, 0);
if (error == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
error = sysctl(mib, 4, pathname, &size, NULL, 0);
if (error == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if (size == 0 || strlen(pathname) == 0) {
ret = psutil_pid_exists(pid);
if (ret == -1)
return NULL;
else if (ret == 0)
return NoSuchProcess();
else
strcpy(pathname, "");
}
#if PY_MAJOR_VERSION >= 3
return PyUnicode_DecodeFSDefault(pathname);
#else
return Py_BuildValue("s", pathname);
#endif
#else
return Py_BuildValue("s", "");
#endif
}
PyObject *
psutil_proc_num_threads(PyObject *self, PyObject *args) {
// Return number of threads used by process as a Python integer.
long pid;
kinfo_proc kp;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
return Py_BuildValue("l", (long)kp.p_nlwps);
}
PyObject *
psutil_proc_threads(PyObject *self, PyObject *args) {
pid_t pid;
int mib[5];
int i, nlwps;
ssize_t st;
size_t size;
struct kinfo_lwp *kl = NULL;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
mib[0] = CTL_KERN;
mib[1] = KERN_LWP;
mib[2] = pid;
mib[3] = sizeof(struct kinfo_lwp);
mib[4] = 0;
st = sysctl(mib, 5, NULL, &size, NULL, 0);
if (st == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if (size == 0) {
NoSuchProcess();
goto error;
}
mib[4] = size / sizeof(size_t);
kl = malloc(size);
if (kl == NULL) {
PyErr_NoMemory();
goto error;
}
st = sysctl(mib, 5, kl, &size, NULL, 0);
if (st == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if (size == 0) {
NoSuchProcess();
goto error;
}
nlwps = (int)(size / sizeof(struct kinfo_lwp));
for (i = 0; i < nlwps; i++) {
py_tuple = Py_BuildValue("idd",
(&kl[i])->l_lid,
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime),
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime));
if (py_tuple == NULL)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
free(kl);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (kl != NULL)
free(kl);
return NULL;
}
// ============================================================================
// APIS
// ============================================================================
int
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
// Returns a list of all BSD processes on the system. This routine
// allocates the list and puts it in *procList and a count of the
// number of entries in *procCount. You are responsible for freeing
// this list (use "free" from System framework).
// On success, the function returns 0.
// On error, the function returns a BSD errno value.
kinfo_proc *result;
int done;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC, 0 };
// Declaring name as const requires us to cast it when passing it to
// sysctl because the prototype doesn't include the const modifier.
size_t length;
char errbuf[_POSIX2_LINE_MAX];
kinfo_proc *x;
int cnt;
kvm_t *kd;
assert( procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (kd == NULL) {
PyErr_Format(
PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf);
return errno;
}
result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt);
if (result == NULL) {
PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() syscall failed");
kvm_close(kd);
return errno;
}
*procCount = (size_t)cnt;
size_t mlen = cnt * sizeof(kinfo_proc);
if ((*procList = malloc(mlen)) == NULL) {
PyErr_NoMemory();
kvm_close(kd);
return errno;
}
memcpy(*procList, result, mlen);
assert(*procList != NULL);
kvm_close(kd);
return 0;
}
char *
psutil_get_cmd_args(pid_t pid, size_t *argsize) {
int mib[4];
ssize_t st;
size_t argmax;
size_t size;
char *procargs = NULL;
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
st = sysctl(mib, 2, &argmax, &size, NULL, 0);
if (st == -1) {
warn("failed to get kern.argmax");
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
procargs = (char *)malloc(argmax);
if (procargs == NULL) {
PyErr_NoMemory();
return NULL;
}
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_ARGS;
mib[2] = pid;
mib[3] = KERN_PROC_ARGV;
st = sysctl(mib, 4, procargs, &argmax, NULL, 0);
if (st == -1) {
warn("failed to get kern.procargs");
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
*argsize = argmax;
return procargs;
}
// Return the command line as a python list object.
// XXX - most of the times sysctl() returns a truncated string.
// Also /proc/pid/cmdline behaves the same so it looks like this
// is a kernel bug.
PyObject *
psutil_get_cmdline(pid_t pid) {
char *argstr = NULL;
int pos = 0;
size_t argsize = 0;
PyObject *py_arg = NULL;
PyObject *py_retlist = PyList_New(0);
if (py_retlist == NULL)
return NULL;
if (pid == 0)
return py_retlist;
argstr = psutil_get_cmd_args(pid, &argsize);
if (argstr == NULL)
goto error;
// args are returned as a flattened string with \0 separators between
// arguments add each string to the list then step forward to the next
// separator
if (argsize > 0) {
while (pos < argsize) {
#if PY_MAJOR_VERSION >= 3
py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]);
#else
py_arg = Py_BuildValue("s", &argstr[pos]);
#endif
if (!py_arg)
goto error;
if (PyList_Append(py_retlist, py_arg))
goto error;
Py_DECREF(py_arg);
pos = pos + strlen(&argstr[pos]) + 1;
}
}
free(argstr);
return py_retlist;
error:
Py_XDECREF(py_arg);
Py_DECREF(py_retlist);
if (argstr != NULL)
free(argstr);
return NULL;
}
/*
* Virtual memory stats, taken from:
* https://github.com/satterly/zabbix-stats/blob/master/src/libs/zbxsysinfo/
* netbsd/memory.c
*/
PyObject *
psutil_virtual_mem(PyObject *self, PyObject *args) {
size_t size;
struct uvmexp_sysctl uv;
int mib[] = {CTL_VM, VM_UVMEXP2};
long pagesize = getpagesize();
size = sizeof(uv);
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return Py_BuildValue("KKKKKKKK",
(unsigned long long) uv.npages << uv.pageshift, // total
(unsigned long long) uv.free << uv.pageshift, // free
(unsigned long long) uv.active << uv.pageshift, // active
(unsigned long long) uv.inactive << uv.pageshift, // inactive
(unsigned long long) uv.wired << uv.pageshift, // wired
(unsigned long long) uv.filepages + uv.execpages * pagesize, // cached
// These are determined from /proc/meminfo in Python.
(unsigned long long) 0, // buffers
(unsigned long long) 0 // shared
);
}
PyObject *
psutil_swap_mem(PyObject *self, PyObject *args) {
uint64_t swap_total, swap_free;
struct swapent *swdev;
int nswap, i;
nswap = swapctl(SWAP_NSWAP, 0, 0);
if (nswap == 0) {
// This means there's no swap partition.
return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
}
swdev = calloc(nswap, sizeof(*swdev));
if (swdev == NULL) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if (swapctl(SWAP_STATS, swdev, nswap) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
// Total things up.
swap_total = swap_free = 0;
for (i = 0; i < nswap; i++) {
if (swdev[i].se_flags & SWF_ENABLE) {
swap_total += swdev[i].se_nblks * DEV_BSIZE;
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse) * DEV_BSIZE;
}
}
free(swdev);
// Get swap in/out
unsigned int total;
size_t size = sizeof(total);
struct uvmexp_sysctl uv;
int mib[] = {CTL_VM, VM_UVMEXP2};
long pagesize = getpagesize();
size = sizeof(uv);
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
return Py_BuildValue("(LLLll)",
swap_total,
(swap_total - swap_free),
swap_free,
(long) uv.pgswapin * pagesize, // swap in
(long) uv.pgswapout * pagesize); // swap out
error:
free(swdev);
}
PyObject *
psutil_proc_num_fds(PyObject *self, PyObject *args) {
long pid;
int cnt;
struct kinfo_file *freep;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
return NULL;
}
free(freep);
return Py_BuildValue("i", cnt);
}
PyObject *
psutil_per_cpu_times(PyObject *self, PyObject *args) {
// XXX: why static?
static int maxcpus;
int mib[3];
int ncpu;
size_t len;
size_t size;
int i;
PyObject *py_cputime = NULL;
PyObject *py_retlist = PyList_New(0);
if (py_retlist == NULL)
return NULL;
// retrieve the number of cpus
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
uint64_t cpu_time[CPUSTATES];
for (i = 0; i < ncpu; i++) {
// per-cpu info
mib[0] = CTL_KERN;
mib[1] = KERN_CP_TIME;
mib[2] = i;
size = sizeof(cpu_time);
if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) {
warn("failed to get kern.cptime2");
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
py_cputime = Py_BuildValue(
"(ddddd)",
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC);
if (!py_cputime)
goto error;
if (PyList_Append(py_retlist, py_cputime))
goto error;
Py_DECREF(py_cputime);
}
return py_retlist;
error:
Py_XDECREF(py_cputime);
Py_DECREF(py_retlist);
return NULL;
}
PyObject *
psutil_disk_io_counters(PyObject *self, PyObject *args) {
int i, dk_ndrive, mib[3];
size_t len;
struct io_sysctl *stats;
PyObject *py_disk_info = NULL;
PyObject *py_retdict = PyDict_New();
if (py_retdict == NULL)
return NULL;
mib[0] = CTL_HW;
mib[1] = HW_IOSTATS;
mib[2] = sizeof(struct io_sysctl);
len = 0;
if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) {
warn("can't get HW_IOSTATS");
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
dk_ndrive = (int)(len / sizeof(struct io_sysctl));
stats = malloc(len);
if (stats == NULL) {
PyErr_NoMemory();
goto error;
}
if (sysctl(mib, 3, stats, &len, NULL, 0) < 0 ) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
for (i = 0; i < dk_ndrive; i++) {
py_disk_info = Py_BuildValue(
"(KKKK)",
stats[i].rxfer,
stats[i].wxfer,
stats[i].rbytes,
stats[i].wbytes
);
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info))
goto error;
Py_DECREF(py_disk_info);
}
free(stats);
return py_retdict;
error:
Py_XDECREF(py_disk_info);
Py_DECREF(py_retdict);
if (stats != NULL)
free(stats);
return NULL;
}
PyObject *
psutil_cpu_stats(PyObject *self, PyObject *args) {
size_t size;
struct uvmexp_sysctl uv;
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
size = sizeof(uv);
if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return Py_BuildValue(
"IIIIIII",
uv.swtch, // ctx switches
uv.intrs, // interrupts - XXX always 0, will be determined via /proc
uv.softs, // soft interrupts
uv.syscalls, // syscalls - XXX always 0
uv.traps, // traps
uv.faults, // faults
uv.forks // forks
);
}
-28
View File
@@ -1,28 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <Python.h>
typedef struct kinfo_proc2 kinfo_proc;
int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc);
struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt);
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
char *psutil_get_cmd_args(pid_t pid, size_t *argsize);
//
PyObject *psutil_get_cmdline(pid_t pid);
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
-443
View File
@@ -1,443 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola'.
* Copyright (c) 2015, Ryo ONODERA.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <Python.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/cdefs.h>
#include <arpa/inet.h>
#include <sys/queue.h>
#include <sys/un.h>
#include <sys/file.h>
// a signaler for connections without an actual status
int PSUTIL_CONN_NONE = 128;
// address family filter
enum af_filter {
INET,
INET4,
INET6,
TCP,
TCP4,
TCP6,
UDP,
UDP4,
UDP6,
UNIX,
ALL,
};
// kinfo_file results
struct kif {
SLIST_ENTRY(kif) kifs;
struct kinfo_file *kif;
};
// kinfo_file results list
SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead);
// kinfo_pcb results
struct kpcb {
SLIST_ENTRY(kpcb) kpcbs;
struct kinfo_pcb *kpcb;
};
// kinfo_pcb results list
SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead);
static void psutil_kiflist_init(void);
static void psutil_kiflist_clear(void);
static void psutil_kpcblist_init(void);
static void psutil_kpcblist_clear(void);
static int psutil_get_files(void);
static int psutil_get_sockets(const char *name);
static int psutil_get_info(int aff);
// Initialize kinfo_file results list.
static void
psutil_kiflist_init(void) {
SLIST_INIT(&kihead);
return;
}
// Clear kinfo_file results list.
static void
psutil_kiflist_clear(void) {
while (!SLIST_EMPTY(&kihead)) {
SLIST_REMOVE_HEAD(&kihead, kifs);
}
return;
}
// Initialize kinof_pcb result list.
static void
psutil_kpcblist_init(void) {
SLIST_INIT(&kpcbhead);
return;
}
// Clear kinof_pcb result list.
static void
psutil_kpcblist_clear(void) {
while (!SLIST_EMPTY(&kpcbhead)) {
SLIST_REMOVE_HEAD(&kpcbhead, kpcbs);
}
return;
}
// Get all open files including socket.
static int
psutil_get_files(void) {
size_t len;
int mib[6];
char *buf;
off_t offset;
int j;
mib[0] = CTL_KERN;
mib[1] = KERN_FILE2;
mib[2] = KERN_FILE_BYFILE;
mib[3] = 0;
mib[4] = sizeof(struct kinfo_file);
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
offset = len % sizeof(off_t);
mib[5] = len / sizeof(struct kinfo_file);
if ((buf = malloc(len + offset)) == NULL) {
PyErr_NoMemory();
return -1;
}
if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) {
free(buf);
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
len /= sizeof(struct kinfo_file);
struct kinfo_file *ki = (struct kinfo_file *)(buf + offset);
for (j = 0; j < len; j++) {
struct kif *kif = malloc(sizeof(struct kif));
kif->kif = &ki[j];
SLIST_INSERT_HEAD(&kihead, kif, kifs);
}
/*
// debug
struct kif *k;
SLIST_FOREACH(k, &kihead, kifs) {
printf("%d\n", k->kif->ki_pid);
}
*/
return 0;
}
// Get open sockets.
static int
psutil_get_sockets(const char *name) {
size_t namelen;
int mib[8];
int ret, j;
struct kinfo_pcb *pcb;
size_t len;
memset(mib, 0, sizeof(mib));
if (sysctlnametomib(name, mib, &namelen) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if ((pcb = malloc(len)) == NULL) {
PyErr_NoMemory();
return -1;
}
memset(pcb, 0, len);
mib[6] = sizeof(*pcb);
mib[7] = len / sizeof(*pcb);
if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) {
free(pcb);
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
len /= sizeof(struct kinfo_pcb);
struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb;
for (j = 0; j < len; j++) {
struct kpcb *kpcb = malloc(sizeof(struct kpcb));
kpcb->kpcb = &kp[j];
SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs);
}
/*
// debug
struct kif *k;
struct kpcb *k;
SLIST_FOREACH(k, &kpcbhead, kpcbs) {
printf("ki_type: %d\n", k->kpcb->ki_type);
printf("ki_family: %d\n", k->kpcb->ki_family);
}
*/
return 0;
}
// Collect open file and connections.
static int
psutil_get_info(int aff) {
switch (aff) {
case INET:
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
return -1;
break;
case INET4:
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
return -1;
break;
case INET6:
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
return -1;
break;
case TCP:
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
return -1;
break;
case TCP4:
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
return -1;
break;
case TCP6:
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
return -1;
break;
case UDP:
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
return -1;
break;
case UDP4:
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
return -1;
break;
case UDP6:
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
return -1;
break;
case UNIX:
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
return -1;
break;
case ALL:
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
return -1;
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
return -1;
break;
}
return 0;
}
/*
* Return system-wide connections (unless a pid != -1 is passed).
*/
PyObject *
psutil_net_connections(PyObject *self, PyObject *args) {
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
pid_t pid;
if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
psutil_kiflist_init();
psutil_kpcblist_init();
if (psutil_get_files() != 0)
goto error;
if (psutil_get_info(ALL) != 0)
goto error;
struct kif *k;
SLIST_FOREACH(k, &kihead, kifs) {
struct kpcb *kp;
if ((pid != -1) && (k->kif->ki_pid != pid))
continue;
SLIST_FOREACH(kp, &kpcbhead, kpcbs) {
if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr)
continue;
char laddr[PATH_MAX];
char raddr[PATH_MAX];
int32_t lport;
int32_t rport;
int32_t status;
// IPv4 or IPv6
if ((kp->kpcb->ki_family == AF_INET) ||
(kp->kpcb->ki_family == AF_INET6)) {
if (kp->kpcb->ki_family == AF_INET) {
// IPv4
struct sockaddr_in *sin_src =
(struct sockaddr_in *)&kp->kpcb->ki_src;
struct sockaddr_in *sin_dst =
(struct sockaddr_in *)&kp->kpcb->ki_dst;
// source addr and port
inet_ntop(AF_INET, &sin_src->sin_addr, laddr,
sizeof(laddr));
lport = ntohs(sin_src->sin_port);
// remote addr and port
inet_ntop(AF_INET, &sin_dst->sin_addr, raddr,
sizeof(raddr));
rport = ntohs(sin_dst->sin_port);
}
else {
// IPv6
struct sockaddr_in6 *sin6_src =
(struct sockaddr_in6 *)&kp->kpcb->ki_src;
struct sockaddr_in6 *sin6_dst =
(struct sockaddr_in6 *)&kp->kpcb->ki_dst;
// local addr and port
inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr,
sizeof(laddr));
lport = ntohs(sin6_src->sin6_port);
// remote addr and port
inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr,
sizeof(raddr));
rport = ntohs(sin6_dst->sin6_port);
}
// status
if (kp->kpcb->ki_type == SOCK_STREAM)
status = kp->kpcb->ki_tstate;
else
status = PSUTIL_CONN_NONE;
// build addr tuple
py_laddr = Py_BuildValue("(si)", laddr, lport);
if (! py_laddr)
goto error;
if (rport != 0)
py_raddr = Py_BuildValue("(si)", raddr, rport);
else
py_raddr = Py_BuildValue("()");
if (! py_raddr)
goto error;
}
else if (kp->kpcb->ki_family == AF_UNIX) {
// UNIX sockets
struct sockaddr_un *sun_src =
(struct sockaddr_un *)&kp->kpcb->ki_src;
struct sockaddr_un *sun_dst =
(struct sockaddr_un *)&kp->kpcb->ki_dst;
strcpy(laddr, sun_src->sun_path);
strcpy(raddr, sun_dst->sun_path);
status = PSUTIL_CONN_NONE;
// TODO: handle unicode
py_laddr = Py_BuildValue("s", laddr);
if (! py_laddr)
goto error;
// TODO: handle unicode
py_raddr = Py_BuildValue("s", raddr);
if (! py_raddr)
goto error;
}
// append tuple to list
py_tuple = Py_BuildValue(
"(iiiNNii)",
k->kif->ki_fd,
kp->kpcb->ki_family,
kp->kpcb->ki_type,
py_laddr,
py_raddr,
status,
k->kif->ki_pid);
if (! py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
}
psutil_kiflist_clear();
psutil_kpcblist_clear();
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
return 0;
}
-10
View File
@@ -1,10 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola'.
* Copyright (c) 2015, Ryo ONODERA.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
PyObject *psutil_proc_connections(PyObject *, PyObject *);
PyObject *psutil_net_connections(PyObject *, PyObject *);
-788
View File
@@ -1,788 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Platform-specific module methods for OpenBSD.
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/mount.h> // for VFS_*
#include <sys/swap.h> // for swap_mem
#include <sys/vmmeter.h> // for vmtotal struct
#include <signal.h>
#include <kvm.h>
// connection stuff
#include <netdb.h> // for NI_MAXHOST
#include <sys/socket.h>
#include <sys/sched.h> // for CPUSTATES & CP_*
#define _KERNEL // for DTYPE_*
#include <sys/file.h>
#undef _KERNEL
#include <sys/disk.h> // struct diskstats
#include <arpa/inet.h> // for inet_ntoa()
#include <err.h> // for warn() & err()
#include "../../_psutil_common.h"
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
// #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
// a signaler for connections without an actual status
int PSUTIL_CONN_NONE = 128;
// ============================================================================
// Utility functions
// ============================================================================
int
psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
// Fills a kinfo_proc struct based on process pid.
int ret;
int mib[6];
size_t size = sizeof(struct kinfo_proc);
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = pid;
mib[4] = size;
mib[5] = 1;
ret = sysctl((int*)mib, 6, proc, &size, NULL, 0);
if (ret == -1) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
// sysctl stores 0 in the size if we can't find the process information.
if (size == 0) {
NoSuchProcess();
return -1;
}
return 0;
}
struct kinfo_file *
kinfo_getfile(long pid, int* cnt) {
// Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an
// int as arg and returns an array with cnt struct kinfo_file.
int mib[6];
size_t len;
struct kinfo_file* kf;
mib[0] = CTL_KERN;
mib[1] = KERN_FILE;
mib[2] = KERN_FILE_BYPID;
mib[3] = (int) pid;
mib[4] = sizeof(struct kinfo_file);
mib[5] = 0;
/* get the size of what would be returned */
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if ((kf = malloc(len)) == NULL) {
PyErr_NoMemory();
return NULL;
}
mib[5] = (int)(len / sizeof(struct kinfo_file));
if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
*cnt = (int)(len / sizeof(struct kinfo_file));
return kf;
}
// ============================================================================
// APIS
// ============================================================================
int
psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
// Returns a list of all BSD processes on the system. This routine
// allocates the list and puts it in *procList and a count of the
// number of entries in *procCount. You are responsible for freeing
// this list (use "free" from System framework).
// On success, the function returns 0.
// On error, the function returns a BSD errno value.
struct kinfo_proc *result;
// Declaring name as const requires us to cast it when passing it to
// sysctl because the prototype doesn't include the const modifier.
char errbuf[_POSIX2_LINE_MAX];
int cnt;
kvm_t *kd;
assert(procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (kd == NULL) {
return errno;
}
result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt);
if (result == NULL) {
kvm_close(kd);
err(1, NULL);
return errno;
}
*procCount = (size_t)cnt;
size_t mlen = cnt * sizeof(struct kinfo_proc);
if ((*procList = malloc(mlen)) == NULL) {
kvm_close(kd);
err(1, NULL);
return errno;
}
memcpy(*procList, result, mlen);
assert(*procList != NULL);
kvm_close(kd);
return 0;
}
char **
_psutil_get_argv(long pid) {
static char **argv;
int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
size_t argv_size = 128;
/* Loop and reallocate until we have enough space to fit argv. */
for (;; argv_size *= 2) {
if ((argv = realloc(argv, argv_size)) == NULL)
err(1, NULL);
if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0)
return argv;
if (errno == ESRCH) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if (errno != ENOMEM)
err(1, NULL);
}
}
// returns the command line as a python list object
PyObject *
psutil_get_cmdline(long pid) {
static char **argv;
char **p;
PyObject *py_arg = NULL;
PyObject *py_retlist = Py_BuildValue("[]");
if (!py_retlist)
return NULL;
if (pid < 0)
return py_retlist;
if ((argv = _psutil_get_argv(pid)) == NULL)
goto error;
for (p = argv; *p != NULL; p++) {
#if PY_MAJOR_VERSION >= 3
py_arg = PyUnicode_DecodeFSDefault(*p);
#else
py_arg = Py_BuildValue("s", *p);
#endif
if (!py_arg)
goto error;
if (PyList_Append(py_retlist, py_arg))
goto error;
Py_DECREF(py_arg);
}
return py_retlist;
error:
Py_XDECREF(py_arg);
Py_DECREF(py_retlist);
return NULL;
}
PyObject *
psutil_proc_threads(PyObject *self, PyObject *args) {
// OpenBSD reference:
// https://github.com/janmojzis/pstree/blob/master/proc_kvm.c
// Note: this requires root access, else it will fail trying
// to access /dev/kmem.
long pid;
kvm_t *kd = NULL;
int nentries, i;
char errbuf[4096];
struct kinfo_proc *kp;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
if (! kd) {
if (strstr(errbuf, "Permission denied") != NULL)
AccessDenied();
else
PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() syscall failed");
goto error;
}
kp = kvm_getprocs(
kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid,
sizeof(*kp), &nentries);
if (! kp) {
if (strstr(errbuf, "Permission denied") != NULL)
AccessDenied();
else
PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() syscall failed");
goto error;
}
for (i = 0; i < nentries; i++) {
if (kp[i].p_tid < 0)
continue;
if (kp[i].p_pid == pid) {
py_tuple = Py_BuildValue(
"Idd",
kp[i].p_tid,
PSUTIL_KPT2DOUBLE(kp[i].p_uutime),
PSUTIL_KPT2DOUBLE(kp[i].p_ustime));
if (py_tuple == NULL)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
}
kvm_close(kd);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (kd != NULL)
kvm_close(kd);
return NULL;
}
PyObject *
psutil_virtual_mem(PyObject *self, PyObject *args) {
int64_t total_physmem;
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
int physmem_mib[] = {CTL_HW, HW_PHYSMEM64};
int vmmeter_mib[] = {CTL_VM, VM_METER};
size_t size;
struct uvmexp uvmexp;
struct bcachestats bcstats;
struct vmtotal vmdata;
long pagesize = getpagesize();
size = sizeof(total_physmem);
if (sysctl(physmem_mib, 2, &total_physmem, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
size = sizeof(uvmexp);
if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
size = sizeof(bcstats);
if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
size = sizeof(vmdata);
if (sysctl(vmmeter_mib, 2, &vmdata, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return Py_BuildValue("KKKKKKKK",
// Note: many programs calculate total memory as
// "uvmexp.npages * pagesize" but this is incorrect and does not
// match "sysctl | grep hw.physmem".
(unsigned long long) total_physmem,
(unsigned long long) uvmexp.free * pagesize,
(unsigned long long) uvmexp.active * pagesize,
(unsigned long long) uvmexp.inactive * pagesize,
(unsigned long long) uvmexp.wired * pagesize,
// this is how "top" determines it
(unsigned long long) bcstats.numbufpages * pagesize, // cached
(unsigned long long) 0, // buffers
(unsigned long long) vmdata.t_vmshr + vmdata.t_rmshr // shared
);
}
PyObject *
psutil_swap_mem(PyObject *self, PyObject *args) {
uint64_t swap_total, swap_free;
struct swapent *swdev;
int nswap, i;
if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) {
PyErr_NoMemory();
return NULL;
}
if (swapctl(SWAP_STATS, swdev, nswap) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
// Total things up.
swap_total = swap_free = 0;
for (i = 0; i < nswap; i++) {
if (swdev[i].se_flags & SWF_ENABLE) {
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse);
swap_total += swdev[i].se_nblks;
}
}
free(swdev);
return Py_BuildValue("(LLLII)",
swap_total * DEV_BSIZE,
(swap_total - swap_free) * DEV_BSIZE,
swap_free * DEV_BSIZE,
// swap in / swap out is not supported as the
// swapent struct does not provide any info
// about it.
0, 0);
error:
free(swdev);
return NULL;
}
PyObject *
psutil_proc_num_fds(PyObject *self, PyObject *args) {
long pid;
int cnt;
struct kinfo_file *freep;
struct kinfo_proc kipp;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (psutil_kinfo_proc(pid, &kipp) == -1)
return NULL;
errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
return NULL;
}
free(freep);
return Py_BuildValue("i", cnt);
}
PyObject *
psutil_proc_cwd(PyObject *self, PyObject *args) {
// Reference:
// http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n179
long pid;
struct kinfo_proc kp;
char path[MAXPATHLEN];
size_t pathlen = sizeof path;
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
int name[] = { CTL_KERN, KERN_PROC_CWD, pid };
if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
#if PY_MAJOR_VERSION >= 3
return PyUnicode_DecodeFSDefault(path);
#else
return Py_BuildValue("s", path);
#endif
}
// see sys/kern/kern_sysctl.c lines 1100 and
// usr.bin/fstat/fstat.c print_inet_details()
static char *
psutil_convert_ipv4(int family, uint32_t addr[4]) {
struct in_addr a;
memcpy(&a, addr, sizeof(a));
return inet_ntoa(a);
}
static char *
psutil_inet6_addrstr(struct in6_addr *p)
{
struct sockaddr_in6 sin6;
static char hbuf[NI_MAXHOST];
const int niflags = NI_NUMERICHOST;
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_addr = *p;
if (IN6_IS_ADDR_LINKLOCAL(p) &&
*(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
sin6.sin6_scope_id =
ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
}
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
hbuf, sizeof(hbuf), NULL, 0, niflags))
return "invalid";
return hbuf;
}
PyObject *
psutil_proc_connections(PyObject *self, PyObject *args) {
long pid;
int i, cnt;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
char *tcplist = NULL;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
PyObject *py_af_filter = NULL;
PyObject *py_type_filter = NULL;
PyObject *py_family = NULL;
PyObject *_type = NULL;
if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
errno = 0;
freep = kinfo_getfile(pid, &cnt);
if (freep == NULL) {
psutil_raise_for_pid(pid, "kinfo_getfile() failed");
goto error;
}
for (i = 0; i < cnt; i++) {
int state;
int lport;
int rport;
char addrbuf[NI_MAXHOST + 2];
int inseq;
struct in6_addr laddr6;
py_tuple = NULL;
py_laddr = NULL;
py_raddr = NULL;
kif = &freep[i];
if (kif->f_type == DTYPE_SOCKET) {
// apply filters
py_family = PyLong_FromLong((long)kif->so_family);
inseq = PySequence_Contains(py_af_filter, py_family);
Py_DECREF(py_family);
if (inseq == 0)
continue;
_type = PyLong_FromLong((long)kif->so_type);
inseq = PySequence_Contains(py_type_filter, _type);
Py_DECREF(_type);
if (inseq == 0)
continue;
// IPv4 / IPv6 socket
if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) {
// fill status
if (kif->so_type == SOCK_STREAM)
state = kif->t_state;
else
state = PSUTIL_CONN_NONE;
// ports
lport = ntohs(kif->inp_lport);
rport = ntohs(kif->inp_fport);
// local address, IPv4
if (kif->so_family == AF_INET) {
py_laddr = Py_BuildValue(
"(si)",
psutil_convert_ipv4(kif->so_family, kif->inp_laddru),
lport);
if (!py_laddr)
goto error;
}
else {
// local address, IPv6
memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6));
snprintf(addrbuf, sizeof(addrbuf), "%s",
psutil_inet6_addrstr(&laddr6));
py_laddr = Py_BuildValue("(si)", addrbuf, lport);
if (!py_laddr)
goto error;
}
if (rport != 0) {
// remote address, IPv4
if (kif->so_family == AF_INET) {
py_raddr = Py_BuildValue(
"(si)",
psutil_convert_ipv4(
kif->so_family, kif->inp_faddru),
rport);
}
else {
// remote address, IPv6
memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6));
snprintf(addrbuf, sizeof(addrbuf), "%s",
psutil_inet6_addrstr(&laddr6));
py_raddr = Py_BuildValue("(si)", addrbuf, rport);
if (!py_raddr)
goto error;
}
}
else {
py_raddr = Py_BuildValue("()");
}
if (!py_raddr)
goto error;
py_tuple = Py_BuildValue(
"(iiiNNi)",
kif->fd_fd,
kif->so_family,
kif->so_type,
py_laddr,
py_raddr,
state);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
// UNIX socket
else if (kif->so_family == AF_UNIX) {
py_tuple = Py_BuildValue(
"(iiisOi)",
kif->fd_fd,
kif->so_family,
kif->so_type,
kif->unp_path,
Py_None,
PSUTIL_CONN_NONE);
if (!py_tuple)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
Py_INCREF(Py_None);
}
}
}
free(freep);
free(tcplist);
return py_retlist;
error:
Py_XDECREF(py_tuple);
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
Py_DECREF(py_retlist);
if (freep != NULL)
free(freep);
if (tcplist != NULL)
free(tcplist);
return NULL;
}
PyObject *
psutil_per_cpu_times(PyObject *self, PyObject *args) {
int mib[3];
int ncpu;
size_t len;
size_t size;
int i;
PyObject *py_retlist = PyList_New(0);
PyObject *py_cputime = NULL;
if (py_retlist == NULL)
return NULL;
// retrieve the number of cpus
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
uint64_t cpu_time[CPUSTATES];
for (i = 0; i < ncpu; i++) {
// per-cpu info
mib[0] = CTL_KERN;
mib[1] = KERN_CPTIME2;
mib[2] = i;
size = sizeof(cpu_time);
if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) {
warn("failed to get kern.cptime2");
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
py_cputime = Py_BuildValue(
"(ddddd)",
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC);
if (!py_cputime)
goto error;
if (PyList_Append(py_retlist, py_cputime))
goto error;
Py_DECREF(py_cputime);
}
return py_retlist;
error:
Py_XDECREF(py_cputime);
Py_DECREF(py_retlist);
return NULL;
}
PyObject *
psutil_disk_io_counters(PyObject *self, PyObject *args) {
int i, dk_ndrive, mib[3];
size_t len;
struct diskstats *stats;
PyObject *py_retdict = PyDict_New();
PyObject *py_disk_info = NULL;
if (py_retdict == NULL)
return NULL;
mib[0] = CTL_HW;
mib[1] = HW_DISKSTATS;
len = 0;
if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) {
warn("can't get hw.diskstats size");
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
dk_ndrive = (int)(len / sizeof(struct diskstats));
stats = malloc(len);
if (stats == NULL) {
warn("can't malloc");
PyErr_NoMemory();
goto error;
}
if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) {
warn("could not read hw.diskstats");
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
for (i = 0; i < dk_ndrive; i++) {
py_disk_info = Py_BuildValue(
"(KKKK)",
stats[i].ds_rxfer, // num reads
stats[i].ds_wxfer, // num writes
stats[i].ds_rbytes, // read bytes
stats[i].ds_wbytes // write bytes
);
if (!py_disk_info)
goto error;
if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info))
goto error;
Py_DECREF(py_disk_info);
}
free(stats);
return py_retdict;
error:
Py_XDECREF(py_disk_info);
Py_DECREF(py_retdict);
if (stats != NULL)
free(stats);
return NULL;
}
PyObject *
psutil_cpu_stats(PyObject *self, PyObject *args) {
size_t size;
struct uvmexp uv;
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
size = sizeof(uv);
if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return Py_BuildValue(
"IIIIIII",
uv.swtch, // ctx switches
uv.intrs, // interrupts - XXX always 0, will be determined via /proc
uv.softs, // soft interrupts
uv.syscalls, // syscalls - XXX always 0
uv.traps, // traps
uv.faults, // faults
uv.forks // forks
);
}
-27
View File
@@ -1,27 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
* All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <Python.h>
typedef struct kinfo_proc kinfo_proc;
int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc);
struct kinfo_file * kinfo_getfile(long pid, int* cnt);
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
char **_psutil_get_argv(long pid);
PyObject * psutil_get_cmdline(long pid);
//
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
PyObject *psutil_proc_cwd(PyObject *self, PyObject *args);
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
-372
View File
@@ -1,372 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Helper functions related to fetching process information.
* Used by _psutil_osx module methods.
*/
#include <Python.h>
#include <assert.h>
#include <errno.h>
#include <limits.h> // for INT_MAX
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/sysctl.h>
#include <libproc.h>
#include "process_info.h"
#include "../../_psutil_common.h"
/*
* 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) {
int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t size, size2;
void *ptr;
int err;
int lim = 8; // some limit
assert( procList != NULL);
assert(*procList == NULL);
assert(procCount != NULL);
*procCount = 0;
/*
* We start by calling sysctl with ptr == NULL and size == 0.
* That will succeed, and set size to the appropriate length.
* We then allocate a buffer of at least that size and call
* sysctl with that buffer. If that succeeds, we're done.
* If that call fails with ENOMEM, we throw the buffer away
* and try again.
* Note that the loop calls sysctl with NULL again. This is
* is necessary because the ENOMEM failure case sets size to
* the amount of data returned, not the amount of data that
* could have been returned.
*/
while (lim-- > 0) {
size = 0;
if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1)
return errno;
size2 = size + (size >> 3); // add some
if (size2 > size) {
ptr = malloc(size2);
if (ptr == NULL)
ptr = malloc(size);
else
size = size2;
}
else {
ptr = malloc(size);
}
if (ptr == NULL)
return ENOMEM;
if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) {
err = errno;
free(ptr);
if (err != ENOMEM)
return err;
}
else {
*procList = (kinfo_proc *)ptr;
*procCount = size / sizeof(kinfo_proc);
return 0;
}
}
return ENOMEM;
}
// Read the maximum argument size for processes
int
psutil_get_argmax() {
int argmax;
int mib[] = { CTL_KERN, KERN_ARGMAX };
size_t size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0)
return argmax;
return 0;
}
// return process args as a python list
PyObject *
psutil_get_cmdline(long pid) {
int mib[3];
int nargs;
size_t len;
char *procargs = NULL;
char *arg_ptr;
char *arg_end;
char *curr_arg;
size_t argmax;
PyObject *py_arg = NULL;
PyObject *py_retlist = NULL;
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
if (pid == 0)
return Py_BuildValue("[]");
// read argmax and allocate memory for argument space.
argmax = psutil_get_argmax();
if (! argmax) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
procargs = (char *)malloc(argmax);
if (NULL == procargs) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
// read argument space
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = (pid_t)pid;
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
if (EINVAL == errno) {
// EINVAL == access denied OR nonexistent PID
if (psutil_pid_exists(pid))
AccessDenied();
else
NoSuchProcess();
}
goto error;
}
arg_end = &procargs[argmax];
// copy the number of arguments to nargs
memcpy(&nargs, procargs, sizeof(nargs));
arg_ptr = procargs + sizeof(nargs);
len = strlen(arg_ptr);
arg_ptr += len + 1;
if (arg_ptr == arg_end) {
free(procargs);
return Py_BuildValue("[]");
}
// skip ahead to the first argument
for (; arg_ptr < arg_end; arg_ptr++) {
if (*arg_ptr != '\0')
break;
}
// iterate through arguments
curr_arg = arg_ptr;
py_retlist = Py_BuildValue("[]");
if (!py_retlist)
goto error;
while (arg_ptr < arg_end && nargs > 0) {
if (*arg_ptr++ == '\0') {
#if PY_MAJOR_VERSION >= 3
py_arg = PyUnicode_DecodeFSDefault(curr_arg);
#else
py_arg = Py_BuildValue("s", curr_arg);
#endif
if (!py_arg)
goto error;
if (PyList_Append(py_retlist, py_arg))
goto error;
Py_DECREF(py_arg);
// iterate to next arg and decrement # of args
curr_arg = arg_ptr;
nargs--;
}
}
free(procargs);
return py_retlist;
error:
Py_XDECREF(py_arg);
Py_XDECREF(py_retlist);
if (procargs != NULL)
free(procargs);
return NULL;
}
// return process environment as a python string
PyObject *
psutil_get_environ(long pid) {
int mib[3];
int nargs;
char *procargs = NULL;
char *procenv = NULL;
char *arg_ptr;
char *arg_end;
char *env_start;
size_t argmax;
PyObject *py_ret = NULL;
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
if (pid == 0)
goto empty;
// 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_t)pid;
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
if (EINVAL == errno) {
// EINVAL == access denied OR nonexistent PID
if (psutil_pid_exists(pid))
AccessDenied();
else
NoSuchProcess();
}
goto error;
}
arg_end = &procargs[argmax];
// copy the number of arguments to nargs
memcpy(&nargs, procargs, sizeof(nargs));
// skip executable path
arg_ptr = procargs + sizeof(nargs);
arg_ptr = memchr(arg_ptr, '\0', arg_end - arg_ptr);
if (arg_ptr == NULL || arg_ptr == arg_end)
goto empty;
// skip ahead to the first argument
for (; arg_ptr < arg_end; arg_ptr++) {
if (*arg_ptr != '\0')
break;
}
// iterate through arguments
while (arg_ptr < arg_end && nargs > 0) {
if (*arg_ptr++ == '\0')
nargs--;
}
// build an environment variable block
env_start = arg_ptr;
procenv = calloc(1, arg_end - arg_ptr);
if (procenv == NULL) {
PyErr_NoMemory();
goto error;
}
while (*arg_ptr != '\0' && arg_ptr < arg_end) {
char *s = memchr(arg_ptr + 1, '\0', arg_end - arg_ptr);
if (s == NULL)
break;
memcpy(procenv + (arg_ptr - env_start), arg_ptr, s - arg_ptr);
arg_ptr = s + 1;
}
#if PY_MAJOR_VERSION >= 3
py_ret = PyUnicode_DecodeFSDefaultAndSize(
procenv, arg_ptr - env_start + 1);
#else
py_ret = PyString_FromStringAndSize(procenv, arg_ptr - env_start + 1);
#endif
if (!py_ret) {
// XXX: don't want to free() this as per:
// https://github.com/giampaolo/psutil/issues/926
// It sucks but not sure what else to do.
procargs = NULL;
goto error;
}
free(procargs);
free(procenv);
return py_ret;
empty:
if (procargs != NULL)
free(procargs);
return Py_BuildValue("s", "");
error:
Py_XDECREF(py_ret);
if (procargs != NULL)
free(procargs);
if (procenv != NULL)
free(procargs);
return NULL;
}
int
psutil_get_kinfo_proc(long 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_t)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 wrapper around proc_pidinfo().
* Returns 0 on failure (and Python exception gets already set).
*/
int
psutil_proc_pidinfo(long pid, int flavor, uint64_t arg, void *pti, int size) {
errno = 0;
int ret = proc_pidinfo((int)pid, flavor, arg, pti, size);
if ((ret <= 0) || ((unsigned long)ret < sizeof(pti))) {
psutil_raise_for_pid(pid, "proc_pidinfo() syscall failed");
return 0;
}
return ret;
}
-17
View File
@@ -1,17 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <Python.h>
typedef struct kinfo_proc kinfo_proc;
int psutil_get_argmax(void);
int psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp);
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
int psutil_proc_pidinfo(
long pid, int flavor, uint64_t arg, void *pti, int size);
PyObject* psutil_get_cmdline(long pid);
PyObject* psutil_get_environ(long pid);
-124
View File
@@ -1,124 +0,0 @@
/* Refrences:
* https://lists.samba.org/archive/samba-technical/2009-February/063079.html
* http://stackoverflow.com/questions/4139405/#4139811
* https://code.google.com/p/openpgm/source/browse/trunk/openpgm/pgm/getifaddrs.c
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include "ifaddrs.h"
#define MAX(x,y) ((x)>(y)?(x):(y))
#define SIZE(p) MAX((p).ss_len,sizeof(p))
static struct sockaddr *
sa_dup (struct sockaddr *sa1)
{
struct sockaddr *sa2;
size_t sz = sizeof(sa1);
sa2 = (struct sockaddr *) calloc(1,sz);
memcpy(sa2,sa1,sz);
return(sa2);
}
void freeifaddrs (struct ifaddrs *ifp)
{
if (NULL == ifp) return;
free(ifp->ifa_name);
free(ifp->ifa_addr);
free(ifp->ifa_netmask);
free(ifp->ifa_dstaddr);
freeifaddrs(ifp->ifa_next);
free(ifp);
}
int getifaddrs (struct ifaddrs **ifap)
{
int sd = -1;
char *ccp, *ecp;
struct lifconf ifc;
struct lifreq *ifr;
struct lifnum lifn;
struct ifaddrs *cifa = NULL; /* current */
struct ifaddrs *pifa = NULL; /* previous */
const size_t IFREQSZ = sizeof(struct lifreq);
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0)
goto error;
ifc.lifc_buf = NULL;
*ifap = NULL;
/* find how much memory to allocate for the SIOCGLIFCONF call */
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = 0;
if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0)
goto error;
/* Sun and Apple code likes to pad the interface count here in case interfaces
* are coming up between calls */
lifn.lifn_count += 4;
ifc.lifc_family = AF_UNSPEC;
ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq);
ifc.lifc_buf = calloc(1, ifc.lifc_len);
if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0)
goto error;
ccp = (char *)ifc.lifc_req;
ecp = ccp + ifc.lifc_len;
while (ccp < ecp) {
ifr = (struct lifreq *) ccp;
cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs));
cifa->ifa_next = NULL;
cifa->ifa_name = strdup(ifr->lifr_name);
if (pifa == NULL) *ifap = cifa; /* first one */
else pifa->ifa_next = cifa;
if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0)
goto error;
cifa->ifa_addr = sa_dup((struct sockaddr*)&ifr->lifr_addr);
if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0)
goto error;
cifa->ifa_netmask = sa_dup((struct sockaddr*)&ifr->lifr_addr);
cifa->ifa_flags = 0;
cifa->ifa_dstaddr = NULL;
if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */
cifa->ifa_flags = ifr->lifr_flags;
if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) {
if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ))
cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr);
}
else cifa->ifa_dstaddr = sa_dup((struct sockaddr*)&ifr->lifr_addr);
pifa = cifa;
ccp += IFREQSZ;
}
free(ifc.lifc_buf);
close(sd);
return 0;
error:
if (ifc.lifc_buf != NULL)
free(ifc.lifc_buf);
if (sd != -1)
close(sd);
return (-1);
}
-26
View File
@@ -1,26 +0,0 @@
/* Reference: https://lists.samba.org/archive/samba-technical/2009-February/063079.html */
#ifndef __IFADDRS_H___
#define __IFADDRS_H___
#include <sys/socket.h>
#include <net/if.h>
#undef ifa_dstaddr
#undef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
};
extern int getifaddrs(struct ifaddrs **);
extern void freeifaddrs(struct ifaddrs *);
#endif
-41
View File
@@ -1,41 +0,0 @@
// mingw headers are missing this
typedef enum _LOGICAL_PROCESSOR_RELATIONSHIP {
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationAll=0xffff
} LOGICAL_PROCESSOR_RELATIONSHIP;
typedef enum _PROCESSOR_CACHE_TYPE {
CacheUnified,CacheInstruction,CacheData,CacheTrace
} PROCESSOR_CACHE_TYPE;
typedef struct _CACHE_DESCRIPTOR {
BYTE Level;
BYTE Associativity;
WORD LineSize;
DWORD Size;
PROCESSOR_CACHE_TYPE Type;
} CACHE_DESCRIPTOR,*PCACHE_DESCRIPTOR;
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
ULONG_PTR ProcessorMask;
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
union {
struct {
BYTE Flags;
} ProcessorCore;
struct {
DWORD NodeNumber;
} NumaNode;
CACHE_DESCRIPTOR Cache;
ULONGLONG Reserved[2];
};
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION,*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION;
WINBASEAPI WINBOOL WINAPI
GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer,
PDWORD ReturnedLength);
-38
View File
@@ -1,38 +0,0 @@
#include "inet_ntop.h"
// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
PCSTR
WSAAPI
inet_ntop(__in INT Family,
__in PVOID pAddr,
__out_ecount(StringBufSize) PSTR pStringBuf,
__in size_t StringBufSize) {
DWORD dwAddressLength = 0;
struct sockaddr_storage srcaddr;
struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
srcaddr.ss_family = Family;
if (Family == AF_INET)
{
dwAddressLength = sizeof(struct sockaddr_in);
memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
} else if (Family == AF_INET6)
{
dwAddressLength = sizeof(struct sockaddr_in6);
memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
} else {
return NULL;
}
if (WSAAddressToString((LPSOCKADDR) &srcaddr,
dwAddressLength,
0,
pStringBuf,
(LPDWORD) &StringBufSize) != 0) {
return NULL;
}
return pStringBuf;
}
-10
View File
@@ -1,10 +0,0 @@
#include <ws2tcpip.h>
PCSTR
WSAAPI
inet_ntop(
__in INT Family,
__in PVOID pAddr,
__out_ecount(StringBufSize) PSTR pStringBuf,
__in size_t StringBufSize
);
-341
View File
@@ -1,341 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#if !defined(__NTEXTAPI_H__)
#define __NTEXTAPI_H__
#include <winternl.h>
typedef struct {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
ULONG InterruptCount;
} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
typedef struct {
LARGE_INTEGER IdleProcessTime;
LARGE_INTEGER IoReadTransferCount;
LARGE_INTEGER IoWriteTransferCount;
LARGE_INTEGER IoOtherTransferCount;
ULONG IoReadOperationCount;
ULONG IoWriteOperationCount;
ULONG IoOtherOperationCount;
ULONG AvailablePages;
ULONG CommittedPages;
ULONG CommitLimit;
ULONG PeakCommitment;
ULONG PageFaultCount;
ULONG CopyOnWriteCount;
ULONG TransitionCount;
ULONG CacheTransitionCount;
ULONG DemandZeroCount;
ULONG PageReadCount;
ULONG PageReadIoCount;
ULONG CacheReadCount;
ULONG CacheIoCount;
ULONG DirtyPagesWriteCount;
ULONG DirtyWriteIoCount;
ULONG MappedPagesWriteCount;
ULONG MappedWriteIoCount;
ULONG PagedPoolPages;
ULONG NonPagedPoolPages;
ULONG PagedPoolAllocs;
ULONG PagedPoolFrees;
ULONG NonPagedPoolAllocs;
ULONG NonPagedPoolFrees;
ULONG FreeSystemPtes;
ULONG ResidentSystemCodePage;
ULONG TotalSystemDriverPages;
ULONG TotalSystemCodePages;
ULONG NonPagedPoolLookasideHits;
ULONG PagedPoolLookasideHits;
ULONG AvailablePagedPoolPages;
ULONG ResidentSystemCachePage;
ULONG ResidentPagedPoolPage;
ULONG ResidentSystemDriverPage;
ULONG CcFastReadNoWait;
ULONG CcFastReadWait;
ULONG CcFastReadResourceMiss;
ULONG CcFastReadNotPossible;
ULONG CcFastMdlReadNoWait;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadResourceMiss;
ULONG CcFastMdlReadNotPossible;
ULONG CcMapDataNoWait;
ULONG CcMapDataWait;
ULONG CcMapDataNoWaitMiss;
ULONG CcMapDataWaitMiss;
ULONG CcPinMappedDataCount;
ULONG CcPinReadNoWait;
ULONG CcPinReadWait;
ULONG CcPinReadNoWaitMiss;
ULONG CcPinReadWaitMiss;
ULONG CcCopyReadNoWait;
ULONG CcCopyReadWait;
ULONG CcCopyReadNoWaitMiss;
ULONG CcCopyReadWaitMiss;
ULONG CcMdlReadNoWait;
ULONG CcMdlReadWait;
ULONG CcMdlReadNoWaitMiss;
ULONG CcMdlReadWaitMiss;
ULONG CcReadAheadIos;
ULONG CcLazyWriteIos;
ULONG CcLazyWritePages;
ULONG CcDataFlushes;
ULONG CcDataPages;
ULONG ContextSwitches;
ULONG FirstLevelTbFills;
ULONG SecondLevelTbFills;
ULONG SystemCalls;
} _SYSTEM_PERFORMANCE_INFORMATION;
typedef struct {
ULONG ContextSwitches;
ULONG DpcCount;
ULONG DpcRate;
ULONG TimeIncrement;
ULONG DpcBypassCount;
ULONG ApcBypassCount;
} _SYSTEM_INTERRUPT_INFORMATION;
typedef enum _KTHREAD_STATE {
Initialized,
Ready,
Running,
Standby,
Terminated,
Waiting,
Transition,
DeferredReady,
GateWait,
MaximumThreadState
} KTHREAD_STATE, *PKTHREAD_STATE;
typedef enum _KWAIT_REASON {
Executive = 0,
FreePage = 1,
PageIn = 2,
PoolAllocation = 3,
DelayExecution = 4,
Suspended = 5,
UserRequest = 6,
WrExecutive = 7,
WrFreePage = 8,
WrPageIn = 9,
WrPoolAllocation = 10,
WrDelayExecution = 11,
WrSuspended = 12,
WrUserRequest = 13,
WrEventPair = 14,
WrQueue = 15,
WrLpcReceive = 16,
WrLpcReply = 17,
WrVirtualMemory = 18,
WrPageOut = 19,
WrRendezvous = 20,
Spare2 = 21,
Spare3 = 22,
Spare4 = 23,
Spare5 = 24,
WrCalloutStack = 25,
WrKernel = 26,
WrResource = 27,
WrPushLock = 28,
WrMutex = 29,
WrQuantumEnd = 30,
WrDispatchInt = 31,
WrPreempted = 32,
WrYieldExecution = 33,
WrFastMutex = 34,
WrGuardedMutex = 35,
WrRundown = 36,
MaximumWaitReason = 37
} KWAIT_REASON, *PKWAIT_REASON;
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
LONG Priority;
LONG BasePriority;
ULONG ContextSwitches;
ULONG ThreadState;
KWAIT_REASON WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef struct _TEB *PTEB;
// private
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
SYSTEM_THREAD_INFORMATION ThreadInfo;
PVOID StackBase;
PVOID StackLimit;
PVOID Win32StartAddress;
PTEB TebBase;
ULONG_PTR Reserved2;
ULONG_PTR Reserved3;
ULONG_PTR Reserved4;
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
LARGE_INTEGER SpareLi2;
LARGE_INTEGER SpareLi3;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
LONG BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR PageDirectoryBase;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
DWORD PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
SYSTEM_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2;
#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2
#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2
// ================================================
// psutil.users() support
// ================================================
typedef struct _WINSTATION_INFO {
BYTE Reserved1[72];
ULONG SessionId;
BYTE Reserved2[4];
FILETIME ConnectTime;
FILETIME DisconnectTime;
FILETIME LastInputTime;
FILETIME LoginTime;
BYTE Reserved3[1096];
FILETIME CurrentTime;
} WINSTATION_INFO, *PWINSTATION_INFO;
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
/*
* NtQueryInformationProcess code taken from
* http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
* typedefs needed to compile against ntdll functions not exposted in the API
*/
typedef LONG NTSTATUS;
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength,
PDWORD ReturnLength
);
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
DWORD ProcessInformationLength
);
typedef enum _PROCESSINFOCLASS2 {
_ProcessBasicInformation,
ProcessQuotaLimits,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessRaisePriority,
_ProcessDebugPort,
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers,
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup,
ProcessPriorityClass,
ProcessWx86Information,
ProcessHandleCount,
ProcessAffinityMask,
ProcessPriorityBoost,
ProcessDeviceMap,
ProcessSessionInformation,
ProcessForegroundInformation,
_ProcessWow64Information,
/* added after XP+ */
_ProcessImageFileName,
ProcessLUIDDeviceMapsEnabled,
_ProcessBreakOnTermination,
ProcessDebugObjectHandle,
ProcessDebugFlags,
ProcessHandleTracing,
ProcessIoPriority,
ProcessExecuteFlags,
ProcessResourceManagement,
ProcessCookie,
ProcessImageInformation,
MaxProcessInfoClass
} PROCESSINFOCLASS2;
#define PROCESSINFOCLASS PROCESSINFOCLASS2
#define ProcessBasicInformation _ProcessBasicInformation
#define ProcessWow64Information _ProcessWow64Information
#define ProcessDebugPort _ProcessDebugPort
#define ProcessImageFileName _ProcessImageFileName
#define ProcessBreakOnTermination _ProcessBreakOnTermination
#endif // __NTEXTAPI_H__
-522
View File
@@ -1,522 +0,0 @@
/*
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
*/
#include "process_handles.h"
static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
static _NtQueryObject __NtQueryObject = NULL;
CRITICAL_SECTION g_cs;
BOOL g_initialized = FALSE;
NTSTATUS g_status;
HANDLE g_hFile = NULL;
HANDLE g_hEvtStart = NULL;
HANDLE g_hEvtFinish = NULL;
HANDLE g_hThread = NULL;
PUNICODE_STRING g_pNameBuffer = NULL;
ULONG g_dwSize = 0;
ULONG g_dwLength = 0;
PVOID
GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) {
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
}
PyObject *
psutil_get_open_files(long dwPid, HANDLE hProcess) {
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
// Threaded version only works for Vista+
if (osvi.dwMajorVersion >= 6)
return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
else
return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
}
VOID
psutil_get_open_files_init(BOOL threaded) {
if (g_initialized == TRUE)
return;
// Resolve the Windows API calls
__NtQuerySystemInformation =
GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation");
__NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
// Create events for signalling work between threads
if (threaded == TRUE) {
g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&g_cs);
}
g_initialized = TRUE;
}
PyObject *
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
DWORD dwInfoSize = 0x10000;
DWORD dwRet = 0;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
DWORD i = 0;
BOOLEAN error = FALSE;
DWORD dwWait = 0;
PyObject* py_retlist = NULL;
PyObject* py_path = NULL;
if (g_initialized == FALSE)
psutil_get_open_files_init(TRUE);
// Due to the use of global variables, ensure only 1 call
// to psutil_get_open_files() is running
EnterCriticalSection(&g_cs);
if (__NtQuerySystemInformation == NULL ||
__NtQueryObject == NULL ||
g_hEvtStart == NULL ||
g_hEvtFinish == NULL)
{
PyErr_SetFromWindowsErr(0);
error = TRUE;
goto cleanup;
}
// Py_BuildValue raises an exception if NULL is returned
py_retlist = PyList_New(0);
if (py_retlist == NULL) {
error = TRUE;
goto cleanup;
}
do {
if (pHandleInfo != NULL) {
HeapFree(GetProcessHeap(), 0, pHandleInfo);
pHandleInfo = NULL;
}
// NtQuerySystemInformation won't give us the correct buffer size,
// so we guess by doubling the buffer size.
dwInfoSize *= 2;
pHandleInfo = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwInfoSize);
if (pHandleInfo == NULL) {
PyErr_NoMemory();
error = TRUE;
goto cleanup;
}
} while ((status = __NtQuerySystemInformation(
SystemExtendedHandleInformation,
pHandleInfo,
dwInfoSize,
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
if (!NT_SUCCESS(status)) {
PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
error = TRUE;
goto cleanup;
}
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
hHandle = &pHandleInfo->Handles[i];
// Check if this hHandle belongs to the PID the user specified.
if (hHandle->UniqueProcessId != (HANDLE)dwPid)
goto loop_cleanup;
if (!DuplicateHandle(hProcess,
hHandle->HandleValue,
GetCurrentProcess(),
&g_hFile,
0,
TRUE,
DUPLICATE_SAME_ACCESS))
{
/*
printf("[%d] DuplicateHandle (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
goto loop_cleanup;
}
// Guess buffer size is MAX_PATH + 1
g_dwLength = (MAX_PATH+1) * sizeof(WCHAR);
do {
// Release any previously allocated buffer
if (g_pNameBuffer != NULL) {
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
g_pNameBuffer = NULL;
g_dwSize = 0;
}
// NtQueryObject puts the required buffer size in g_dwLength
// WinXP edge case puts g_dwLength == 0, just skip this handle
if (g_dwLength == 0)
goto loop_cleanup;
g_dwSize = g_dwLength;
if (g_dwSize > 0) {
g_pNameBuffer = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
g_dwSize);
if (g_pNameBuffer == NULL)
goto loop_cleanup;
}
dwWait = psutil_NtQueryObject();
// If the call does not return, skip this handle
if (dwWait != WAIT_OBJECT_0)
goto loop_cleanup;
} while (g_status == STATUS_INFO_LENGTH_MISMATCH);
// NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH
if (!NT_SUCCESS(g_status))
goto loop_cleanup;
// Convert to PyUnicode and append it to the return list
if (g_pNameBuffer->Length > 0) {
/*
printf("[%d] Filename (%#x) %#d bytes: %S\n",
dwPid,
hHandle->HandleValue,
g_pNameBuffer->Length,
g_pNameBuffer->Buffer);
*/
py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
g_pNameBuffer->Length/2);
if (py_path == NULL) {
/*
printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
error = TRUE;
goto loop_cleanup;
}
if (PyList_Append(py_retlist, py_path)) {
/*
printf("[%d] PyList_Append (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
error = TRUE;
goto loop_cleanup;
}
}
loop_cleanup:
Py_XDECREF(py_path);
py_path = NULL;
if (g_pNameBuffer != NULL)
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
g_pNameBuffer = NULL;
g_dwSize = 0;
g_dwLength = 0;
if (g_hFile != NULL)
CloseHandle(g_hFile);
g_hFile = NULL;
}
cleanup:
if (g_pNameBuffer != NULL)
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
g_pNameBuffer = NULL;
g_dwSize = 0;
g_dwLength = 0;
if (g_hFile != NULL)
CloseHandle(g_hFile);
g_hFile = NULL;
if (pHandleInfo != NULL)
HeapFree(GetProcessHeap(), 0, pHandleInfo);
pHandleInfo = NULL;
if (error) {
Py_XDECREF(py_retlist);
py_retlist = NULL;
}
LeaveCriticalSection(&g_cs);
return py_retlist;
}
DWORD
psutil_NtQueryObject() {
DWORD dwWait = 0;
if (g_hThread == NULL)
g_hThread = CreateThread(
NULL,
0,
psutil_NtQueryObjectThread,
NULL,
0,
NULL);
if (g_hThread == NULL)
return GetLastError();
// Signal the worker thread to start
SetEvent(g_hEvtStart);
// Wait for the worker thread to finish
dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
// If the thread hangs, kill it and cleanup
if (dwWait == WAIT_TIMEOUT) {
SuspendThread(g_hThread);
TerminateThread(g_hThread, 1);
WaitForSingleObject(g_hThread, INFINITE);
CloseHandle(g_hThread);
g_hThread = NULL;
}
return dwWait;
}
DWORD WINAPI
psutil_NtQueryObjectThread(LPVOID lpvParam) {
// Loop infinitely waiting for work
while (TRUE) {
WaitForSingleObject(g_hEvtStart, INFINITE);
g_status = __NtQueryObject(g_hFile,
ObjectNameInformation,
g_pNameBuffer,
g_dwSize,
&g_dwLength);
SetEvent(g_hEvtFinish);
}
}
PyObject *
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
DWORD dwInfoSize = 0x10000;
DWORD dwRet = 0;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
HANDLE hFile = NULL;
HANDLE hMap = NULL;
DWORD i = 0;
BOOLEAN error = FALSE;
PyObject* py_retlist = NULL;
PyObject* py_path = NULL;
ULONG dwSize = 0;
LPVOID pMem = NULL;
TCHAR pszFilename[MAX_PATH+1];
if (g_initialized == FALSE)
psutil_get_open_files_init(FALSE);
if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) {
PyErr_SetFromWindowsErr(0);
error = TRUE;
goto cleanup;
}
// Py_BuildValue raises an exception if NULL is returned
py_retlist = PyList_New(0);
if (py_retlist == NULL) {
error = TRUE;
goto cleanup;
}
do {
if (pHandleInfo != NULL) {
HeapFree(GetProcessHeap(), 0, pHandleInfo);
pHandleInfo = NULL;
}
// NtQuerySystemInformation won't give us the correct buffer size,
// so we guess by doubling the buffer size.
dwInfoSize *= 2;
pHandleInfo = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwInfoSize);
if (pHandleInfo == NULL) {
PyErr_NoMemory();
error = TRUE;
goto cleanup;
}
} while ((status = __NtQuerySystemInformation(
SystemExtendedHandleInformation,
pHandleInfo,
dwInfoSize,
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
if (!NT_SUCCESS(status)) {
PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
error = TRUE;
goto cleanup;
}
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
hHandle = &pHandleInfo->Handles[i];
// Check if this hHandle belongs to the PID the user specified.
if (hHandle->UniqueProcessId != (HANDLE)dwPid)
goto loop_cleanup;
if (!DuplicateHandle(hProcess,
hHandle->HandleValue,
GetCurrentProcess(),
&hFile,
0,
TRUE,
DUPLICATE_SAME_ACCESS))
{
/*
printf("[%d] DuplicateHandle (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
goto loop_cleanup;
}
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMap == NULL) {
/*
printf("[%d] CreateFileMapping (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
goto loop_cleanup;
}
pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1);
if (pMem == NULL) {
/*
printf("[%d] MapViewOfFile (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
goto loop_cleanup;
}
dwSize = GetMappedFileName(
GetCurrentProcess(), pMem, pszFilename, MAX_PATH);
if (dwSize == 0) {
/*
printf("[%d] GetMappedFileName (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
goto loop_cleanup;
}
pszFilename[dwSize] = '\0';
/*
printf("[%d] Filename (%#x) %#d bytes: %S\n",
dwPid,
hHandle->HandleValue,
dwSize,
pszFilename);
*/
py_path = PyUnicode_FromWideChar(pszFilename, dwSize);
if (py_path == NULL) {
/*
printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
error = TRUE;
goto loop_cleanup;
}
if (PyList_Append(py_retlist, py_path)) {
/*
printf("[%d] PyList_Append (%#x): %#x \n",
dwPid,
hHandle->HandleValue,
GetLastError());
*/
error = TRUE;
goto loop_cleanup;
}
loop_cleanup:
Py_XDECREF(py_path);
py_path = NULL;
if (pMem != NULL)
UnmapViewOfFile(pMem);
pMem = NULL;
if (hMap != NULL)
CloseHandle(hMap);
hMap = NULL;
if (hFile != NULL)
CloseHandle(hFile);
hFile = NULL;
dwSize = 0;
}
cleanup:
if (pMem != NULL)
UnmapViewOfFile(pMem);
pMem = NULL;
if (hMap != NULL)
CloseHandle(hMap);
hMap = NULL;
if (hFile != NULL)
CloseHandle(hFile);
hFile = NULL;
if (pHandleInfo != NULL)
HeapFree(GetProcessHeap(), 0, pHandleInfo);
pHandleInfo = NULL;
if (error) {
Py_XDECREF(py_retlist);
py_retlist = NULL;
}
return py_retlist;
}
-111
View File
@@ -1,111 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef __PROCESS_HANDLES_H__
#define __PROCESS_HANDLES_H__
#ifndef UNICODE
#define UNICODE
#endif
#include <Python.h>
#include <stdio.h>
#include <windows.h>
#include <strsafe.h>
#include <winternl.h>
#include <psapi.h>
#ifndef NT_SUCCESS
#define NT_SUCCESS(x) ((x) >= 0)
#endif
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2
#define HANDLE_TYPE_FILE 28
#define NTQO_TIMEOUT 100
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef NTSTATUS (NTAPI *_NtQueryObject)(
HANDLE ObjectHandle,
ULONG ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength
);
// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
PVOID Object;
HANDLE UniqueProcessId;
HANDLE HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
ULONG_PTR NumberOfHandles;
ULONG_PTR Reserved;
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
typedef enum _POOL_TYPE {
NonPagedPool,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS
} POOL_TYPE, *PPOOL_TYPE;
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
ULONG TotalPagedPoolUsage;
ULONG TotalNonPagedPoolUsage;
ULONG TotalNamePoolUsage;
ULONG TotalHandleTableUsage;
ULONG HighWaterNumberOfObjects;
ULONG HighWaterNumberOfHandles;
ULONG HighWaterPagedPoolUsage;
ULONG HighWaterNonPagedPoolUsage;
ULONG HighWaterNamePoolUsage;
ULONG HighWaterHandleTableUsage;
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
USHORT MaintainTypeList;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName);
VOID psutil_get_open_files_init(BOOL threaded);
PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
DWORD psutil_NtQueryObject(void);
DWORD WINAPI psutil_NtQueryObjectThread(LPVOID lpvParam);
#endif // __PROCESS_HANDLES_H__
-873
View File
@@ -1,873 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Helper functions related to fetching process information. Used by
* _psutil_windows module methods.
*/
#include <Python.h>
#include <windows.h>
#include <Psapi.h>
#include <tlhelp32.h>
#include "security.h"
#include "process_info.h"
#include "ntextapi.h"
#include "../../_psutil_common.h"
/*
* A wrapper around OpenProcess setting NSP exception if process
* no longer exists.
* "pid" is the process pid, "dwDesiredAccess" is the first argument
* exptected by OpenProcess.
* Return a process handle or NULL.
*/
HANDLE
psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) {
HANDLE hProcess;
DWORD processExitCode = 0;
if (pid == 0) {
// otherwise we'd get NoSuchProcess
return AccessDenied();
}
hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
if (hProcess == NULL) {
if (GetLastError() == ERROR_INVALID_PARAMETER)
NoSuchProcess();
else
PyErr_SetFromWindowsErr(0);
return NULL;
}
// make sure the process is running
GetExitCodeProcess(hProcess, &processExitCode);
if (processExitCode == 0) {
NoSuchProcess();
CloseHandle(hProcess);
return NULL;
}
return hProcess;
}
/*
* Same as psutil_handle_from_pid_waccess but implicitly uses
* PROCESS_QUERY_INFORMATION | PROCESS_VM_READ as dwDesiredAccess
* parameter for OpenProcess.
*/
HANDLE
psutil_handle_from_pid(DWORD pid) {
DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
return psutil_handle_from_pid_waccess(pid, dwDesiredAccess);
}
/*
* Given a Python int referencing a process handle close the process handle.
*/
PyObject *
psutil_win32_CloseHandle(PyObject *self, PyObject *args) {
unsigned long handle;
if (! PyArg_ParseTuple(args, "k", &handle))
return NULL;
// TODO: may want to check return value;
CloseHandle((HANDLE)handle);
Py_RETURN_NONE;
}
DWORD *
psutil_get_pids(DWORD *numberOfReturnedPIDs) {
// Win32 SDK says the only way to know if our process array
// wasn't large enough is to check the returned size and make
// sure that it doesn't match the size of the array.
// If it does we allocate a larger array and try again
// Stores the actual array
DWORD *procArray = NULL;
DWORD procArrayByteSz;
int procArraySz = 0;
// Stores the byte size of the returned array from enumprocesses
DWORD enumReturnSz = 0;
do {
procArraySz += 1024;
free(procArray);
procArrayByteSz = procArraySz * sizeof(DWORD);
procArray = malloc(procArrayByteSz);
if (procArray == NULL) {
PyErr_NoMemory();
return NULL;
}
if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) {
free(procArray);
PyErr_SetFromWindowsErr(0);
return NULL;
}
} while (enumReturnSz == procArraySz * sizeof(DWORD));
// The number of elements is the returned size / size of each element
*numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD);
return procArray;
}
int
psutil_pid_is_running(DWORD pid) {
HANDLE hProcess;
DWORD exitCode;
// Special case for PID 0 System Idle Process
if (pid == 0)
return 1;
if (pid < 0)
return 0;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
if (NULL == hProcess) {
// invalid parameter is no such process
if (GetLastError() == ERROR_INVALID_PARAMETER) {
CloseHandle(hProcess);
return 0;
}
// access denied obviously means there's a process to deny access to...
if (GetLastError() == ERROR_ACCESS_DENIED) {
CloseHandle(hProcess);
return 1;
}
CloseHandle(hProcess);
PyErr_SetFromWindowsErr(0);
return -1;
}
if (GetExitCodeProcess(hProcess, &exitCode)) {
CloseHandle(hProcess);
return (exitCode == STILL_ACTIVE);
}
// access denied means there's a process there so we'll assume
// it's running
if (GetLastError() == ERROR_ACCESS_DENIED) {
CloseHandle(hProcess);
return 1;
}
PyErr_SetFromWindowsErr(0);
CloseHandle(hProcess);
return -1;
}
int
psutil_pid_in_proclist(DWORD pid) {
DWORD *proclist = NULL;
DWORD numberOfReturnedPIDs;
DWORD i;
proclist = psutil_get_pids(&numberOfReturnedPIDs);
if (proclist == NULL)
return -1;
for (i = 0; i < numberOfReturnedPIDs; i++) {
if (pid == proclist[i]) {
free(proclist);
return 1;
}
}
free(proclist);
return 0;
}
// Check exit code from a process handle. Return FALSE on an error also
// XXX - not used anymore
int
handlep_is_running(HANDLE hProcess) {
DWORD dwCode;
if (NULL == hProcess)
return 0;
if (GetExitCodeProcess(hProcess, &dwCode)) {
if (dwCode == STILL_ACTIVE)
return 1;
}
return 0;
}
// Helper structures to access the memory correctly. Some of these might also
// be defined in the winternl.h header file but unfortunately not in a usable
// way.
// see http://msdn2.microsoft.com/en-us/library/aa489609.aspx
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx
typedef struct {
BYTE Reserved1[16];
PVOID Reserved2[5];
UNICODE_STRING CurrentDirectoryPath;
PVOID CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
LPCWSTR env;
} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_;
// https://msdn.microsoft.com/en-us/library/aa813706(v=vs.85).aspx
#ifdef _WIN64
typedef struct {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[21];
PVOID LoaderData;
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
/* More fields ... */
} PEB_;
#else
typedef struct {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PVOID Ldr;
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
/* More fields ... */
} PEB_;
#endif
#ifdef _WIN64
/* When we are a 64 bit process accessing a 32 bit (WoW64) process we need to
use the 32 bit structure layout. */
typedef struct {
USHORT Length;
USHORT MaxLength;
DWORD Buffer;
} UNICODE_STRING32;
typedef struct {
BYTE Reserved1[16];
DWORD Reserved2[5];
UNICODE_STRING32 CurrentDirectoryPath;
DWORD CurrentDirectoryHandle;
UNICODE_STRING32 DllPath;
UNICODE_STRING32 ImagePathName;
UNICODE_STRING32 CommandLine;
DWORD env;
} RTL_USER_PROCESS_PARAMETERS32;
typedef struct {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
DWORD Reserved3[2];
DWORD Ldr;
DWORD ProcessParameters;
/* More fields ... */
} PEB32;
#else
/* When we are a 32 bit (WoW64) process accessing a 64 bit process we need to
use the 64 bit structure layout and a special function to read its memory.
*/
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 Size,
OUT PULONG64 NumberOfBytesRead);
typedef enum {
MemoryInformationBasic
} MEMORY_INFORMATION_CLASS;
typedef NTSTATUS (NTAPI *_NtWow64QueryVirtualMemory64)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
OUT PMEMORY_BASIC_INFORMATION64 MemoryInformation,
IN ULONG64 Size,
OUT PULONG64 ReturnLength OPTIONAL);
typedef struct {
PVOID Reserved1[2];
PVOID64 PebBaseAddress;
PVOID Reserved2[4];
PVOID UniqueProcessId[2];
PVOID Reserved3[2];
} PROCESS_BASIC_INFORMATION64;
typedef struct {
USHORT Length;
USHORT MaxLength;
PVOID64 Buffer;
} UNICODE_STRING64;
typedef struct {
BYTE Reserved1[16];
PVOID64 Reserved2[5];
UNICODE_STRING64 CurrentDirectoryPath;
PVOID64 CurrentDirectoryHandle;
UNICODE_STRING64 DllPath;
UNICODE_STRING64 ImagePathName;
UNICODE_STRING64 CommandLine;
PVOID64 env;
} RTL_USER_PROCESS_PARAMETERS64;
typedef struct {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[21];
PVOID64 LoaderData;
PVOID64 ProcessParameters;
/* More fields ... */
} PEB64;
#endif
/* Given a pointer into a process's memory, figure out how much data can be
* read from it. */
static int psutil_get_process_region_size(HANDLE hProcess,
LPCVOID src,
SIZE_T *psize) {
MEMORY_BASIC_INFORMATION info;
if (!VirtualQueryEx(hProcess, src, &info, sizeof(info))) {
PyErr_SetFromWindowsErr(0);
return -1;
}
*psize = info.RegionSize - ((char*)src - (char*)info.BaseAddress);
return 0;
}
#ifndef _WIN64
/* Given a pointer into a process's memory, figure out how much data can be
* read from it. */
static int psutil_get_process_region_size64(HANDLE hProcess,
const PVOID64 src64,
PULONG64 psize) {
static _NtWow64QueryVirtualMemory64 NtWow64QueryVirtualMemory64 = NULL;
MEMORY_BASIC_INFORMATION64 info64;
if (NtWow64QueryVirtualMemory64 == NULL) {
NtWow64QueryVirtualMemory64 =
(_NtWow64QueryVirtualMemory64)GetProcAddress(
GetModuleHandleA("ntdll.dll"),
"NtWow64QueryVirtualMemory64");
if (NtWow64QueryVirtualMemory64 == NULL) {
PyErr_SetString(PyExc_NotImplementedError,
"NtWow64QueryVirtualMemory64 missing");
return -1;
}
}
if (!NT_SUCCESS(NtWow64QueryVirtualMemory64(
hProcess,
src64,
0,
&info64,
sizeof(info64),
NULL))) {
PyErr_SetFromWindowsErr(0);
return -1;
}
*psize = info64.RegionSize - ((char*)src64 - (char*)info64.BaseAddress);
return 0;
}
#endif
enum psutil_process_data_kind {
KIND_CMDLINE,
KIND_CWD,
KIND_ENVIRON,
};
/* Get data from the process with the given pid. The data is returned in the
pdata output member as a nul terminated string which must be freed on
success.
On success 0 is returned. On error the output parameter is not touched, -1
is returned, and an appropriate Python exception is set. */
static int psutil_get_process_data(long pid,
enum psutil_process_data_kind kind,
WCHAR **pdata,
SIZE_T *psize) {
/* This function is quite complex because there are several cases to be
considered:
Two cases are really simple: we (i.e. the python interpreter) and the
target process are both 32 bit or both 64 bit. In that case the memory
layout of the structures matches up and all is well.
When we are 64 bit and the target process is 32 bit we need to use
custom 32 bit versions of the structures.
When we are 32 bit and the target process is 64 bit we need to use
custom 64 bit version of the structures. Also we need to use separate
Wow64 functions to get the information.
A few helper structs are defined above so that the compiler can handle
calculating the correct offsets.
Additional help also came from the following sources:
https://github.com/kohsuke/winp and
http://wj32.org/wp/2009/01/24/howto-get-the-command-line-of-processes/
http://stackoverflow.com/a/14012919
http://www.drdobbs.com/embracing-64-bit-windows/184401966
*/
static _NtQueryInformationProcess NtQueryInformationProcess = NULL;
#ifndef _WIN64
static _NtQueryInformationProcess NtWow64QueryInformationProcess64 = NULL;
static _NtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = NULL;
#endif
HANDLE hProcess = NULL;
LPCVOID src;
SIZE_T size;
WCHAR *buffer = NULL;
#ifdef _WIN64
LPVOID ppeb32 = NULL;
#else
PVOID64 src64;
BOOL weAreWow64;
BOOL theyAreWow64;
#endif
hProcess = psutil_handle_from_pid(pid);
if (hProcess == NULL)
return -1;
if (NtQueryInformationProcess == NULL) {
NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
}
#ifdef _WIN64
/* 64 bit case. Check if the target is a 32 bit process running in WoW64
* mode. */
if (!NT_SUCCESS(NtQueryInformationProcess(hProcess,
ProcessWow64Information,
&ppeb32,
sizeof(LPVOID),
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
if (ppeb32 != NULL) {
/* We are 64 bit. Target process is 32 bit running in WoW64 mode. */
PEB32 peb32;
RTL_USER_PROCESS_PARAMETERS32 procParameters32;
// read PEB
if (!ReadProcessMemory(hProcess, ppeb32, &peb32, sizeof(peb32), NULL)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read process parameters
if (!ReadProcessMemory(hProcess,
UlongToPtr(peb32.ProcessParameters),
&procParameters32,
sizeof(procParameters32),
NULL)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
switch (kind) {
case KIND_CMDLINE:
src = UlongToPtr(procParameters32.CommandLine.Buffer),
size = procParameters32.CommandLine.Length;
break;
case KIND_CWD:
src = UlongToPtr(procParameters32.CurrentDirectoryPath.Buffer);
size = procParameters32.CurrentDirectoryPath.Length;
break;
case KIND_ENVIRON:
src = UlongToPtr(procParameters32.env);
break;
}
} else
#else
/* 32 bit case. Check if the target is also 32 bit. */
if (!IsWow64Process(GetCurrentProcess(), &weAreWow64) ||
!IsWow64Process(hProcess, &theyAreWow64)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
if (weAreWow64 && !theyAreWow64) {
/* We are 32 bit running in WoW64 mode. Target process is 64 bit. */
PROCESS_BASIC_INFORMATION64 pbi64;
PEB64 peb64;
RTL_USER_PROCESS_PARAMETERS64 procParameters64;
if (NtWow64QueryInformationProcess64 == NULL) {
NtWow64QueryInformationProcess64 =
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"),
"NtWow64QueryInformationProcess64");
if (NtWow64QueryInformationProcess64 == NULL) {
PyErr_SetString(PyExc_NotImplementedError,
"NtWow64QueryInformationProcess64 missing");
goto error;
}
}
if (!NT_SUCCESS(NtWow64QueryInformationProcess64(
hProcess,
ProcessBasicInformation,
&pbi64,
sizeof(pbi64),
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read peb
if (NtWow64ReadVirtualMemory64 == NULL) {
NtWow64ReadVirtualMemory64 =
(_NtWow64ReadVirtualMemory64)GetProcAddress(
GetModuleHandleA("ntdll.dll"),
"NtWow64ReadVirtualMemory64");
if (NtWow64ReadVirtualMemory64 == NULL) {
PyErr_SetString(PyExc_NotImplementedError,
"NtWow64ReadVirtualMemory64 missing");
goto error;
}
}
if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
pbi64.PebBaseAddress,
&peb64,
sizeof(peb64),
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read process parameters
if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
peb64.ProcessParameters,
&procParameters64,
sizeof(procParameters64),
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
switch (kind) {
case KIND_CMDLINE:
src64 = procParameters64.CommandLine.Buffer;
size = procParameters64.CommandLine.Length;
break;
case KIND_CWD:
src64 = procParameters64.CurrentDirectoryPath.Buffer,
size = procParameters64.CurrentDirectoryPath.Length;
break;
case KIND_ENVIRON:
src64 = procParameters64.env;
break;
}
} else
#endif
/* Target process is of the same bitness as us. */
{
PROCESS_BASIC_INFORMATION pbi;
PEB_ peb;
RTL_USER_PROCESS_PARAMETERS_ procParameters;
if (!NT_SUCCESS(NtQueryInformationProcess(hProcess,
ProcessBasicInformation,
&pbi,
sizeof(pbi),
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read peb
if (!ReadProcessMemory(hProcess,
pbi.PebBaseAddress,
&peb,
sizeof(peb),
NULL)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// read process parameters
if (!ReadProcessMemory(hProcess,
peb.ProcessParameters,
&procParameters,
sizeof(procParameters),
NULL)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
switch (kind) {
case KIND_CMDLINE:
src = procParameters.CommandLine.Buffer;
size = procParameters.CommandLine.Length;
break;
case KIND_CWD:
src = procParameters.CurrentDirectoryPath.Buffer;
size = procParameters.CurrentDirectoryPath.Length;
break;
case KIND_ENVIRON:
src = procParameters.env;
break;
}
}
if (kind == KIND_ENVIRON) {
#ifndef _WIN64
if (weAreWow64 && !theyAreWow64) {
ULONG64 size64;
if (psutil_get_process_region_size64(hProcess, src64, &size64) != 0)
goto error;
size = (SIZE_T)size64;
}
else
#endif
if (psutil_get_process_region_size(hProcess, src, &size) != 0)
goto error;
}
buffer = calloc(size + 2, 1);
if (buffer == NULL) {
PyErr_NoMemory();
goto error;
}
#ifndef _WIN64
if (weAreWow64 && !theyAreWow64) {
if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(hProcess,
src64,
buffer,
size,
NULL))) {
PyErr_SetFromWindowsErr(0);
goto error;
}
} else
#endif
if (!ReadProcessMemory(hProcess, src, buffer, size, NULL)) {
PyErr_SetFromWindowsErr(0);
goto error;
}
CloseHandle(hProcess);
*pdata = buffer;
*psize = size;
return 0;
error:
if (hProcess != NULL)
CloseHandle(hProcess);
if (buffer != NULL)
free(buffer);
return -1;
}
/*
* returns a Python list representing the arguments for the process
* with given pid or NULL on error.
*/
PyObject *
psutil_get_cmdline(long pid) {
PyObject *ret = NULL;
WCHAR *data = NULL;
SIZE_T size;
PyObject *py_retlist = NULL;
PyObject *py_unicode = NULL;
LPWSTR *szArglist = NULL;
int nArgs, i;
if (psutil_get_process_data(pid, KIND_CMDLINE, &data, &size) != 0)
goto out;
// attempt to parse the command line using Win32 API
szArglist = CommandLineToArgvW(data, &nArgs);
if (szArglist == NULL) {
PyErr_SetFromWindowsErr(0);
goto out;
}
// arglist parsed as array of UNICODE_STRING, so convert each to
// Python string object and add to arg list
py_retlist = PyList_New(nArgs);
if (py_retlist == NULL)
goto out;
for (i = 0; i < nArgs; i++) {
py_unicode = PyUnicode_FromWideChar(szArglist[i],
wcslen(szArglist[i]));
if (py_unicode == NULL)
goto out;
PyList_SET_ITEM(py_retlist, i, py_unicode);
py_unicode = NULL;
}
ret = py_retlist;
py_retlist = NULL;
out:
LocalFree(szArglist);
free(data);
Py_XDECREF(py_unicode);
Py_XDECREF(py_retlist);
return ret;
}
PyObject *psutil_get_cwd(long pid) {
PyObject *ret = NULL;
WCHAR *data = NULL;
SIZE_T size;
if (psutil_get_process_data(pid, KIND_CWD, &data, &size) != 0)
goto out;
// convert wchar array to a Python unicode string
ret = PyUnicode_FromWideChar(data, wcslen(data));
out:
free(data);
return ret;
}
/*
* returns a Python string containing the environment variable data for the
* process with given pid or NULL on error.
*/
PyObject *psutil_get_environ(long pid) {
PyObject *ret = NULL;
WCHAR *data = NULL;
SIZE_T size;
if (psutil_get_process_data(pid, KIND_ENVIRON, &data, &size) != 0)
goto out;
// convert wchar array to a Python unicode string
ret = PyUnicode_FromWideChar(data, size / 2);
out:
free(data);
return ret;
}
#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))
#define PH_NEXT_PROCESS(Process) ( \
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \
NULL)
const int STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
/*
* Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
* fills the structure with various process information by using
* NtQuerySystemInformation.
* We use this as a fallback when faster functions fail with access
* denied. This is slower because it iterates over all processes.
* On success return 1, else 0 with Python exception already set.
*/
int
psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
PVOID *retBuffer) {
static ULONG initialBufferSize = 0x4000;
NTSTATUS status;
PVOID buffer;
ULONG bufferSize;
PSYSTEM_PROCESS_INFORMATION process;
// get NtQuerySystemInformation
typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
NTQSI_PROC NtQuerySystemInformation;
HINSTANCE hNtDll;
hNtDll = LoadLibrary(TEXT("ntdll.dll"));
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
hNtDll, "NtQuerySystemInformation");
bufferSize = initialBufferSize;
buffer = malloc(bufferSize);
if (buffer == NULL) {
PyErr_NoMemory();
goto error;
}
while (TRUE) {
status = NtQuerySystemInformation(SystemProcessInformation, buffer,
bufferSize, &bufferSize);
if (status == STATUS_BUFFER_TOO_SMALL ||
status == STATUS_INFO_LENGTH_MISMATCH)
{
free(buffer);
buffer = malloc(bufferSize);
if (buffer == NULL) {
PyErr_NoMemory();
goto error;
}
}
else {
break;
}
}
if (status != 0) {
PyErr_Format(
PyExc_RuntimeError, "NtQuerySystemInformation() syscall 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;
}
-34
View File
@@ -1,34 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#if !defined(__PROCESS_INFO_H)
#define __PROCESS_INFO_H
#include <Python.h>
#include <windows.h>
#include "security.h"
#include "ntextapi.h"
#define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle)
#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
HANDLE psutil_handle_from_pid(DWORD pid);
HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
PyObject* psutil_win32_OpenProcess(PyObject *self, PyObject *args);
PyObject* psutil_win32_CloseHandle(PyObject *self, PyObject *args);
int psutil_handlep_is_running(HANDLE hProcess);
int psutil_pid_in_proclist(DWORD pid);
int psutil_pid_is_running(DWORD pid);
PyObject* psutil_get_cmdline(long pid);
PyObject* psutil_get_cwd(long pid);
PyObject* psutil_get_environ(long pid);
int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
PVOID *retBuffer);
#endif
-225
View File
@@ -1,225 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
*/
#include <windows.h>
#include <Python.h>
/*
* Convert a process handle to a process token handle.
*/
HANDLE
psutil_token_from_handle(HANDLE hProcess) {
HANDLE hToken = NULL;
if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
return PyErr_SetFromWindowsErr(0);
return hToken;
}
/*
* http://www.ddj.com/windows/184405986
*
* There's a way to determine whether we're running under the Local System
* account. However (you guessed it), we have to call more Win32 functions to
* determine this. Backing up through the code listing, we need to make another
* call to GetTokenInformation, but instead of passing through the TOKEN_USER
* constant, we pass through the TOKEN_PRIVILEGES constant. This value returns
* an array of privileges that the account has in the environment. Iterating
* through the array, we call the function LookupPrivilegeName looking for the
* string “SeTcbPrivilege. If the function returns this string, then this
* account has Local System privileges
*/
int
psutil_has_system_privilege(HANDLE hProcess) {
DWORD i;
DWORD dwSize = 0;
DWORD dwRetval = 0;
TCHAR privName[256];
DWORD dwNameSize = 256;
// PTOKEN_PRIVILEGES tp = NULL;
BYTE *pBuffer = NULL;
TOKEN_PRIVILEGES *tp = NULL;
HANDLE hToken = psutil_token_from_handle(hProcess);
if (NULL == hToken)
return -1;
// call GetTokenInformation first to get the buffer size
if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) {
dwRetval = GetLastError();
// if it failed for a reason other than the buffer, bail out
if (dwRetval != ERROR_INSUFFICIENT_BUFFER ) {
PyErr_SetFromWindowsErr(dwRetval);
return 0;
}
}
// allocate buffer and call GetTokenInformation again
// tp = (PTOKEN_PRIVILEGES) GlobalAlloc(GPTR, dwSize);
pBuffer = (BYTE *) malloc(dwSize);
if (pBuffer == NULL) {
PyErr_NoMemory();
return -1;
}
if (! GetTokenInformation(hToken, TokenPrivileges, pBuffer,
dwSize, &dwSize))
{
PyErr_SetFromWindowsErr(0);
free(pBuffer);
return -1;
}
// convert the BYTE buffer to a TOKEN_PRIVILEGES struct pointer
tp = (TOKEN_PRIVILEGES *)pBuffer;
// check all the privileges looking for SeTcbPrivilege
for (i = 0; i < tp->PrivilegeCount; i++) {
// reset the buffer contents and the buffer size
strcpy(privName, "");
dwNameSize = sizeof(privName) / sizeof(TCHAR);
if (! LookupPrivilegeName(NULL,
&tp->Privileges[i].Luid,
(LPTSTR)privName,
&dwNameSize))
{
PyErr_SetFromWindowsErr(0);
free(pBuffer);
return -1;
}
// if we find the SeTcbPrivilege then it's a LocalSystem process
if (! lstrcmpi(privName, TEXT("SeTcbPrivilege"))) {
free(pBuffer);
return 1;
}
}
free(pBuffer);
return 0;
}
BOOL
psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) {
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
if (!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;
// first pass. get current privilege setting
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
// second pass. set privilege based on previous setting
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
else
tpPrevious.Privileges[0].Attributes ^=
(SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL
);
if (GetLastError() != ERROR_SUCCESS) return FALSE;
return TRUE;
}
int
psutil_set_se_debug() {
HANDLE hToken;
if (! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
) {
if (GetLastError() == ERROR_NO_TOKEN) {
if (!ImpersonateSelf(SecurityImpersonation)) {
CloseHandle(hToken);
return 0;
}
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
) {
RevertToSelf();
CloseHandle(hToken);
return 0;
}
}
}
// enable SeDebugPrivilege (open any process)
if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, TRUE)) {
RevertToSelf();
CloseHandle(hToken);
return 0;
}
RevertToSelf();
CloseHandle(hToken);
return 1;
}
int
psutil_unset_se_debug() {
HANDLE hToken;
if (! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken)
) {
if (GetLastError() == ERROR_NO_TOKEN) {
if (! ImpersonateSelf(SecurityImpersonation))
return 0;
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken))
{
return 0;
}
}
}
// now disable SeDebug
if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE))
return 0;
CloseHandle(hToken);
return 1;
}
-17
View File
@@ -1,17 +0,0 @@
/*
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
*/
#include <windows.h>
BOOL psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege);
HANDLE psutil_token_from_handle(HANDLE hProcess);
int psutil_has_system_privilege(HANDLE hProcess);
int psutil_set_se_debug();
int psutil_unset_se_debug();
-496
View File
@@ -1,496 +0,0 @@
/*
* 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 <Python.h>
#include <windows.h>
#include <Winsvc.h>
#include "services.h"
// ==================================================================
// utils
// ==================================================================
SC_HANDLE
psutil_get_service_handler(char *service_name, DWORD scm_access, DWORD access)
{
ENUM_SERVICE_STATUS_PROCESS *lpService = NULL;
SC_HANDLE sc = NULL;
SC_HANDLE hService = NULL;
SERVICE_DESCRIPTION *scd = NULL;
sc = OpenSCManager(NULL, NULL, scm_access);
if (sc == NULL) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
hService = OpenService(sc, service_name, access);
if (hService == NULL) {
CloseServiceHandle(sc);
PyErr_SetFromWindowsErr(0);
return NULL;
}
CloseServiceHandle(sc);
return hService;
}
// XXX - expose these as constants?
static const char *
get_startup_string(DWORD startup) {
switch (startup) {
case SERVICE_AUTO_START:
return "automatic";
case SERVICE_DEMAND_START:
return "manual";
case SERVICE_DISABLED:
return "disabled";
/*
// drivers only (since we use EnumServicesStatusEx() with
// SERVICE_WIN32)
case SERVICE_BOOT_START:
return "boot-start";
case SERVICE_SYSTEM_START:
return "system-start";
*/
default:
return "unknown";
}
}
// XXX - expose these as constants?
static const char *
get_state_string(DWORD state) {
switch (state) {
case SERVICE_RUNNING:
return "running";
case SERVICE_PAUSED:
return "paused";
case SERVICE_START_PENDING:
return "start_pending";
case SERVICE_PAUSE_PENDING:
return "pause_pending";
case SERVICE_CONTINUE_PENDING:
return "continue_pending";
case SERVICE_STOP_PENDING:
return "stop_pending";
case SERVICE_STOPPED:
return "stopped";
default:
return "unknown";
}
}
// ==================================================================
// APIs
// ==================================================================
/*
* Enumerate all services.
*/
PyObject *
psutil_winservice_enumerate(PyObject *self, PyObject *args) {
ENUM_SERVICE_STATUS_PROCESS *lpService = NULL;
BOOL ok;
SC_HANDLE sc = NULL;
DWORD bytesNeeded = 0;
DWORD srvCount;
DWORD resumeHandle = 0;
DWORD dwBytes = 0;
DWORD i;
PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
PyObject *py_unicode_display_name = NULL;
if (py_retlist == NULL)
return NULL;
sc = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (sc == NULL) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
for (;;) {
ok = EnumServicesStatusEx(
sc,
SC_ENUM_PROCESS_INFO,
SERVICE_WIN32, // XXX - extend this to include drivers etc.?
SERVICE_STATE_ALL,
(LPBYTE)lpService,
dwBytes,
&bytesNeeded,
&srvCount,
&resumeHandle,
NULL);
if (ok || (GetLastError() != ERROR_MORE_DATA))
break;
if (lpService)
free(lpService);
dwBytes = bytesNeeded;
lpService = (ENUM_SERVICE_STATUS_PROCESS*)malloc(dwBytes);
}
for (i = 0; i < srvCount; i++) {
// Get unicode display name.
py_unicode_display_name = NULL;
py_unicode_display_name = PyUnicode_Decode(
lpService[i].lpDisplayName,
_tcslen(lpService[i].lpDisplayName),
Py_FileSystemDefaultEncoding,
"replace");
if (py_unicode_display_name == NULL)
goto error;
// Construct the result.
py_tuple = Py_BuildValue(
"(sO)",
lpService[i].lpServiceName, // name
py_unicode_display_name // display_name
);
if (py_tuple == NULL)
goto error;
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_unicode_display_name);
Py_DECREF(py_tuple);
}
// Free resources.
CloseServiceHandle(sc);
free(lpService);
return py_retlist;
error:
Py_XDECREF(py_unicode_display_name);
Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (sc != NULL)
CloseServiceHandle(sc);
if (lpService != NULL)
free(lpService);
return NULL;
}
/*
* Get service config information. Returns:
* - display_name
* - binpath
* - username
* - startup_type
*/
PyObject *
psutil_winservice_query_config(PyObject *self, PyObject *args) {
char *service_name;
SC_HANDLE hService = NULL;
BOOL ok;
DWORD bytesNeeded = 0;
DWORD resumeHandle = 0;
DWORD dwBytes = 0;
QUERY_SERVICE_CONFIG *qsc = NULL;
PyObject *py_tuple = NULL;
PyObject *py_unicode_display_name = NULL;
PyObject *py_unicode_binpath = NULL;
PyObject *py_unicode_username = NULL;
if (!PyArg_ParseTuple(args, "s", &service_name))
return NULL;
hService = psutil_get_service_handler(
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG);
if (hService == NULL)
goto error;
// First call to QueryServiceConfig() is necessary to get the
// right size.
bytesNeeded = 0;
QueryServiceConfig(hService, NULL, 0, &bytesNeeded);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
PyErr_SetFromWindowsErr(0);
goto error;
}
qsc = (QUERY_SERVICE_CONFIG *)malloc(bytesNeeded);
ok = QueryServiceConfig(hService, qsc, bytesNeeded, &bytesNeeded);
if (ok == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
// Get unicode display name.
py_unicode_display_name = PyUnicode_Decode(
qsc->lpDisplayName,
_tcslen(qsc->lpDisplayName),
Py_FileSystemDefaultEncoding,
"replace");
if (py_unicode_display_name == NULL)
goto error;
// Get unicode bin path.
py_unicode_binpath = PyUnicode_Decode(
qsc->lpBinaryPathName,
_tcslen(qsc->lpBinaryPathName),
Py_FileSystemDefaultEncoding,
"replace");
if (py_unicode_binpath == NULL)
goto error;
// Get unicode username.
py_unicode_username = PyUnicode_Decode(
qsc->lpServiceStartName,
_tcslen(qsc->lpServiceStartName),
Py_FileSystemDefaultEncoding,
"replace");
if (py_unicode_username == NULL)
goto error;
// Construct result tuple.
py_tuple = Py_BuildValue(
"(OOOs)",
py_unicode_display_name,
py_unicode_binpath,
py_unicode_username,
get_startup_string(qsc->dwStartType) // startup
);
if (py_tuple == NULL)
goto error;
// Free resources.
Py_DECREF(py_unicode_display_name);
Py_DECREF(py_unicode_binpath);
Py_DECREF(py_unicode_username);
free(qsc);
CloseServiceHandle(hService);
return py_tuple;
error:
Py_XDECREF(py_unicode_display_name);
Py_XDECREF(py_unicode_binpath);
Py_XDECREF(py_unicode_username);
Py_XDECREF(py_tuple);
if (hService != NULL)
CloseServiceHandle(hService);
if (qsc != NULL)
free(qsc);
return NULL;
}
/*
* Get service status information. Returns:
* - status
* - pid
*/
PyObject *
psutil_winservice_query_status(PyObject *self, PyObject *args) {
char *service_name;
SC_HANDLE hService = NULL;
BOOL ok;
DWORD bytesNeeded = 0;
DWORD resumeHandle = 0;
DWORD dwBytes = 0;
SERVICE_STATUS_PROCESS *ssp = NULL;
PyObject *py_tuple = NULL;
if (!PyArg_ParseTuple(args, "s", &service_name))
return NULL;
hService = psutil_get_service_handler(
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_STATUS);
if (hService == NULL)
goto error;
// First call to QueryServiceStatusEx() is necessary to get the
// right size.
QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0,
&bytesNeeded);
if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
// Also services.msc fails in the same manner, so we return an
// empty string.
CloseServiceHandle(hService);
return Py_BuildValue("s", "");
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
PyErr_SetFromWindowsErr(0);
goto error;
}
ssp = (SERVICE_STATUS_PROCESS *)HeapAlloc(
GetProcessHeap(), 0, bytesNeeded);
if (ssp == NULL) {
PyErr_NoMemory();
goto error;
}
// Actual call.
ok = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)ssp,
bytesNeeded, &bytesNeeded);
if (ok == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
py_tuple = Py_BuildValue(
"(sk)",
get_state_string(ssp->dwCurrentState),
ssp->dwProcessId
);
if (py_tuple == NULL)
goto error;
CloseServiceHandle(hService);
HeapFree(GetProcessHeap(), 0, ssp);
return py_tuple;
error:
Py_XDECREF(py_tuple);
if (hService != NULL)
CloseServiceHandle(hService);
if (ssp != NULL)
HeapFree(GetProcessHeap(), 0, ssp);
return NULL;
}
/*
* Get service description.
*/
PyObject *
psutil_winservice_query_descr(PyObject *self, PyObject *args) {
ENUM_SERVICE_STATUS_PROCESS *lpService = NULL;
BOOL ok;
DWORD bytesNeeded = 0;
DWORD resumeHandle = 0;
DWORD dwBytes = 0;
SC_HANDLE hService = NULL;
SERVICE_DESCRIPTION *scd = NULL;
char *service_name;
PyObject *py_retstr = NULL;
if (!PyArg_ParseTuple(args, "s", &service_name))
return NULL;
hService = psutil_get_service_handler(
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG);
if (hService == NULL)
goto error;
// This first call to QueryServiceConfig2() is necessary in order
// to get the right size.
bytesNeeded = 0;
QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0,
&bytesNeeded);
if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
// Also services.msc fails in the same manner, so we return an
// empty string.
CloseServiceHandle(hService);
return Py_BuildValue("s", "");
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
PyErr_SetFromWindowsErr(0);
goto error;
}
scd = (SERVICE_DESCRIPTION *)malloc(bytesNeeded);
ok = QueryServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,
(LPBYTE)scd, bytesNeeded, &bytesNeeded);
if (ok == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
if (scd->lpDescription == NULL) {
py_retstr = Py_BuildValue("s", "");
}
else {
py_retstr = PyUnicode_Decode(
scd->lpDescription,
_tcslen(scd->lpDescription),
Py_FileSystemDefaultEncoding,
"replace");
}
if (!py_retstr)
goto error;
free(scd);
CloseServiceHandle(hService);
return py_retstr;
error:
if (hService != NULL)
CloseServiceHandle(hService);
if (lpService != NULL)
free(lpService);
return NULL;
}
/*
* Start service.
* XXX - note: this is exposed but not used.
*/
PyObject *
psutil_winservice_start(PyObject *self, PyObject *args) {
char *service_name;
BOOL ok;
SC_HANDLE hService = NULL;
if (!PyArg_ParseTuple(args, "s", &service_name))
return NULL;
hService = psutil_get_service_handler(
service_name, SC_MANAGER_ALL_ACCESS, SERVICE_START);
if (hService == NULL) {
goto error;
}
ok = StartService(hService, 0, NULL);
if (ok == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
Py_RETURN_NONE;
error:
if (hService != NULL)
CloseServiceHandle(hService);
return NULL;
}
/*
* Stop service.
* XXX - note: this is exposed but not used.
*/
PyObject *
psutil_winservice_stop(PyObject *self, PyObject *args) {
char *service_name;
BOOL ok;
SC_HANDLE hService = NULL;
SERVICE_STATUS ssp;
if (!PyArg_ParseTuple(args, "s", &service_name))
return NULL;
hService = psutil_get_service_handler(
service_name, SC_MANAGER_ALL_ACCESS, SERVICE_STOP);
if (hService == NULL)
goto error;
// Note: this can hang for 30 secs.
Py_BEGIN_ALLOW_THREADS
ok = ControlService(hService, SERVICE_CONTROL_STOP, &ssp);
Py_END_ALLOW_THREADS
if (ok == 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
CloseServiceHandle(hService);
Py_RETURN_NONE;
error:
if (hService != NULL)
CloseServiceHandle(hService);
return NULL;
}
-17
View File
@@ -1,17 +0,0 @@
/*
* 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 <Python.h>
#include <Winsvc.h>
SC_HANDLE psutil_get_service_handle(
char service_name, DWORD scm_access, DWORD access);
PyObject *psutil_winservice_enumerate(PyObject *self, PyObject *args);
PyObject *psutil_winservice_query_config(PyObject *self, PyObject *args);
PyObject *psutil_winservice_query_status(PyObject *self, PyObject *args);
PyObject *psutil_winservice_query_descr(PyObject *self, PyObject *args);
PyObject *psutil_winservice_start(PyObject *self, PyObject *args);
PyObject *psutil_winservice_stop(PyObject *self, PyObject *args);
+3
View File
@@ -116,6 +116,9 @@ setup(
'console_scripts': ['pipenv=pipenv:cli'],
},
install_requires=required,
extras_require={
':sys_platform=="win32"': ['psutil']
},
include_package_data=True,
license='MIT',
classifiers=[