73 lines
2.1 KiB
Python
73 lines
2.1 KiB
Python
import io
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from ._core import Process
|
|
|
|
|
|
STAT_PPID = 3
|
|
STAT_TTY = 6
|
|
|
|
STAT_PATTERN = re.compile(r'\(.+\)|\S+')
|
|
|
|
|
|
def detect_proc():
|
|
"""Detect /proc filesystem style.
|
|
|
|
This checks the /proc/{pid} directory for possible formats. Returns one of
|
|
the followings as str:
|
|
|
|
* `stat`: Linux-style, i.e. ``/proc/{pid}/stat``.
|
|
* `status`: BSD-style, i.e. ``/proc/{pid}/status``.
|
|
"""
|
|
pid = os.getpid()
|
|
for name in ('stat', 'status'):
|
|
if os.path.exists(os.path.join('/proc', str(pid), name)):
|
|
return name
|
|
raise ProcFormatError('unsupported proc format')
|
|
|
|
|
|
def _get_stat(pid, name):
|
|
path = os.path.join('/proc', str(pid), name)
|
|
with io.open(path, encoding='ascii', errors='replace') as f:
|
|
# We only care about TTY and PPID -- all numbers.
|
|
parts = STAT_PATTERN.findall(f.read())
|
|
return parts[STAT_TTY], parts[STAT_PPID]
|
|
|
|
|
|
def _get_cmdline(pid):
|
|
path = os.path.join('/proc', str(pid), 'cmdline')
|
|
encoding = sys.getfilesystemencoding() or 'utf-8'
|
|
with io.open(path, encoding=encoding, errors='replace') as f:
|
|
# XXX: Command line arguments can be arbitrary byte sequences, not
|
|
# necessarily decodable. For Shellingham's purpose, however, we don't
|
|
# care. (pypa/pipenv#2820)
|
|
# cmdline appends an extra NULL at the end, hence the [:-1].
|
|
return tuple(f.read().split('\0')[:-1])
|
|
|
|
|
|
class ProcFormatError(EnvironmentError):
|
|
pass
|
|
|
|
|
|
def get_process_mapping():
|
|
"""Try to look up the process tree via the /proc interface.
|
|
"""
|
|
stat_name = detect_proc()
|
|
self_tty = _get_stat(os.getpid(), stat_name)[0]
|
|
processes = {}
|
|
for pid in os.listdir('/proc'):
|
|
if not pid.isdigit():
|
|
continue
|
|
try:
|
|
tty, ppid = _get_stat(pid, stat_name)
|
|
if tty != self_tty:
|
|
continue
|
|
args = _get_cmdline(pid)
|
|
processes[pid] = Process(args=args, pid=pid, ppid=ppid)
|
|
except IOError:
|
|
# Process has disappeared - just ignore it.
|
|
continue
|
|
return processes
|