Skip to content

Commit 6c1d2c0

Browse files
committed
[Linux] fix for cases fdinfo has only flags (#2596)
1 parent 990f781 commit 6c1d2c0

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

psutil/_pslinux.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,22 @@ def wrapper(self, *args, **kwargs):
16571657
return wrapper
16581658

16591659

1660+
def _parse_fdinfo(f):
1661+
# f: a file opened in binary
1662+
pos, flags = None, None
1663+
for _ in [0, 1]:
1664+
line_vals = f.readline().split()
1665+
if line_vals is None or len(line_vals) < 2:
1666+
continue
1667+
key = decode(line_vals[0])
1668+
if key == "pos:":
1669+
pos = int(line_vals[1])
1670+
elif key == "flags:":
1671+
flags = int(line_vals[1], 8)
1672+
1673+
return pos, flags
1674+
1675+
16601676
class Process:
16611677
"""Linux process implementation."""
16621678

@@ -2273,8 +2289,7 @@ def open_files(self):
22732289
file = f"{self._procfs_path}/{self.pid}/fdinfo/{fd}"
22742290
try:
22752291
with open_binary(file) as f:
2276-
pos = int(f.readline().split()[1])
2277-
flags = int(f.readline().split()[1], 8)
2292+
pos, flags = _parse_fdinfo(f)
22782293
except (FileNotFoundError, ProcessLookupError):
22792294
# fd gone in the meantime; process may
22802295
# still be alive

psutil/tests/test_linux.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,38 @@ def test_open_files_enametoolong(self):
19551955
assert p.open_files() == []
19561956
assert m.called
19571957

1958+
# Test parsing variants of fdinfo content ( during Process.open_files() )
1959+
1960+
def test_open_files_fdinfo_parsing_avg(self):
1961+
# Case typical fdinfo file content
1962+
fdinfo_content = """\
1963+
pos: 0
1964+
flags: 02100000
1965+
mnt_id: 129
1966+
ino: 29836347532685335"""
1967+
self._do_test_fdinfo_parsing(fdinfo_content, (0, 0o2100000))
1968+
1969+
def test_open_files_fdinfo_parsing_only_flags(self):
1970+
# Case only flags.
1971+
# Seen in Docker python + Google Cloud Run
1972+
# https://github.com/giampaolo/psutil/issues/2596
1973+
fdinfo_content = """\
1974+
flags: 02100000"""
1975+
self._do_test_fdinfo_parsing(fdinfo_content, (None, 0o2100000))
1976+
1977+
def test_open_files_fdinfo_parsing_empty(self):
1978+
# extereme case the file is empty (not seen in practice)
1979+
fdinfo_content = ""
1980+
self._do_test_fdinfo_parsing(fdinfo_content, (None, None))
1981+
1982+
def _do_test_fdinfo_parsing(self, content, expected):
1983+
# `f`` needs to be a file in binary mode,
1984+
# simulating what is done in Process.open_flles()
1985+
f = io.BytesIO(content.encode())
1986+
actual_pos, actual_flags = psutil._pslinux._parse_fdinfo(f)
1987+
assert actual_pos == expected[0]
1988+
assert actual_flags == expected[1]
1989+
19581990
# --- mocked tests
19591991

19601992
def test_terminal_mocked(self):

0 commit comments

Comments
 (0)