Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,22 @@ def wrapper(self, *args, **kwargs):
return wrapper


def _parse_fdinfo(f):
# f: a file opened in binary
pos, flags = None, None
for _ in [0, 1]:
line_vals = f.readline().split()
if line_vals is None or len(line_vals) < 2:
continue
key = decode(line_vals[0])
if key == "pos:":
pos = int(line_vals[1])
elif key == "flags:":
flags = int(line_vals[1], 8)

return pos, flags


class Process:
"""Linux process implementation."""

Expand Down Expand Up @@ -2273,8 +2289,7 @@ def open_files(self):
file = f"{self._procfs_path}/{self.pid}/fdinfo/{fd}"
try:
with open_binary(file) as f:
pos = int(f.readline().split()[1])
flags = int(f.readline().split()[1], 8)
pos, flags = _parse_fdinfo(f)
except (FileNotFoundError, ProcessLookupError):
# fd gone in the meantime; process may
# still be alive
Expand Down
32 changes: 32 additions & 0 deletions psutil/tests/test_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -1955,6 +1955,38 @@ def test_open_files_enametoolong(self):
assert p.open_files() == []
assert m.called

# Test parsing variants of fdinfo content ( during Process.open_files() )

def test_open_files_fdinfo_parsing_avg(self):
# Case typical fdinfo file content
fdinfo_content = """\
pos: 0
flags: 02100000
mnt_id: 129
ino: 29836347532685335"""
self._do_test_fdinfo_parsing(fdinfo_content, (0, 0o2100000))

def test_open_files_fdinfo_parsing_only_flags(self):
# Case only flags.
# Seen in Docker python + Google Cloud Run
# https://github.com/giampaolo/psutil/issues/2596
fdinfo_content = """\
flags: 02100000"""
self._do_test_fdinfo_parsing(fdinfo_content, (None, 0o2100000))

def test_open_files_fdinfo_parsing_empty(self):
# extereme case the file is empty (not seen in practice)
fdinfo_content = ""
self._do_test_fdinfo_parsing(fdinfo_content, (None, None))

def _do_test_fdinfo_parsing(self, content, expected):
# `f`` needs to be a file in binary mode,
# simulating what is done in Process.open_flles()
f = io.BytesIO(content.encode())
actual_pos, actual_flags = psutil._pslinux._parse_fdinfo(f)
assert actual_pos == expected[0]
assert actual_flags == expected[1]

# --- mocked tests

def test_terminal_mocked(self):
Expand Down