| import errno |
| import subprocess |
| import sys |
|
|
| from ._core import Process |
|
|
|
|
| class PsNotAvailable(EnvironmentError): |
| pass |
|
|
|
|
| def iter_process_parents(pid, max_depth=10): |
| """Try to look up the process tree via the output of `ps`.""" |
| try: |
| cmd = ["ps", "-ww", "-o", "pid=", "-o", "ppid=", "-o", "args="] |
| output = subprocess.check_output(cmd) |
| except OSError as e: |
| if e.errno != errno.ENOENT: |
| raise |
| raise PsNotAvailable("ps not found") |
| except subprocess.CalledProcessError as e: |
| |
| |
| if not e.output.strip(): |
| return |
| raise |
| if not isinstance(output, str): |
| encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() |
| output = output.decode(encoding) |
|
|
| processes_mapping = {} |
| for line in output.split("\n"): |
| try: |
| _pid, ppid, args = line.strip().split(None, 2) |
| |
| |
| |
| |
| |
| args = tuple(a.strip() for a in args.split(" ")) |
| except ValueError: |
| continue |
| processes_mapping[_pid] = Process(args=args, pid=_pid, ppid=ppid) |
|
|
| for _ in range(max_depth): |
| try: |
| process = processes_mapping[pid] |
| except KeyError: |
| return |
| yield process |
| pid = process.ppid |
|
|