mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 14:50:16 +00:00
Vendored
-2376
File diff suppressed because it is too large
Load Diff
Vendored
-449
@@ -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
|
||||
Vendored
-249
@@ -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
|
||||
Vendored
-855
@@ -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)
|
||||
Vendored
-1872
File diff suppressed because it is too large
Load Diff
Vendored
-506
@@ -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)
|
||||
Vendored
-184
@@ -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
|
||||
Vendored
-702
@@ -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)
|
||||
Vendored
-1047
File diff suppressed because it is too large
Load Diff
-126
@@ -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
@@ -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
|
||||
Vendored
-688
@@ -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(ðcmd, 0, sizeof ethcmd);
|
||||
ethcmd.cmd = ETHTOOL_GSET;
|
||||
ifr.ifr_data = (void *)ðcmd;
|
||||
ret = ioctl(sock, SIOCETHTOOL, &ifr);
|
||||
|
||||
if (ret != -1) {
|
||||
duplex = ethcmd.duplex;
|
||||
speed = ethcmd.speed;
|
||||
}
|
||||
else {
|
||||
if ((errno == EOPNOTSUPP) || (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
|
||||
}
|
||||
Vendored
-1910
File diff suppressed because it is too large
Load Diff
Vendored
-619
@@ -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
|
||||
}
|
||||
Vendored
-5
@@ -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.
|
||||
*/
|
||||
Vendored
-1539
File diff suppressed because it is too large
Load Diff
-3775
File diff suppressed because it is too large
Load Diff
Vendored
-965
@@ -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)
|
||||
-1020
File diff suppressed because it is too large
Load Diff
-32
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
Reference in New Issue
Block a user