From c2aa0a89a93d998edbf4a66faf004ef5214484d4 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sun, 31 Dec 2023 18:26:54 +0100 Subject: [PATCH] try to unify everything --- psutil/_pslinux.py | 26 ++++++++++++++++++-------- psutil/tests/test_linux.py | 28 ++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index db1be4585..e48c75dc3 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -1258,12 +1258,15 @@ def find(self): def _disk_partitions_mountinfo(): - # Since Linux 2.6.26. Advantage: differently from /proc/self/mounts - # it provides the real device name for bind-mounts, see: - # https://github.com/giampaolo/psutil/issues/2347 + # /proc/pid/mountinfo was introduced in Linux 2.6.26. Advantage: it + # provides the real device name for bind-mounts, see: + # https://github.com/giampaolo/psutil/issues/2347. Also, despite + # not officially stated, it seems it deprecates /proc/pid/mounts. + # `strace mount` shows mount CLI uses /proc/pid/mountinfo, so we + # also use this as the default. retlist = [] procfs_path = get_procfs_path() - with open_text("%s/self/mountinfo" % procfs_path) as f: + with open_text("%s/%s/mountinfo" % (procfs_path, os.getpid())) as f: for line in f: fields = line.strip().split() ( @@ -1279,20 +1282,27 @@ def _disk_partitions_mountinfo(): device, opts2 ) = fields[:11] - opts = ",".join(dict.fromkeys(opts1.split(",") + opts2.split(","))) + opts1 = opts1.split(",") + opts2 = opts2.split(",") + opts = dict.fromkeys(opts1 + opts2) + if "ro" in opts and "rw" in opts: + del opts["rw"] + opts = ",".join(opts) retlist.append((device, mountpoint, fstype, opts)) return retlist def _disk_partitions_getmntent(): - # /proc/self/mounts introduced in Linux 2.4.19. + # /proc/pid/mounts introduced in Linux 2.4.19. # See: https://github.com/giampaolo/psutil/issues/1307 procfs_path = get_procfs_path() if procfs_path == "/proc" and os.path.isfile('/etc/mtab'): mounts_path = os.path.realpath("/etc/mtab") else: - mounts_path = os.path.realpath("%s/self/mounts" % procfs_path) + mounts_path = os.path.realpath( + "%s/%s/mounts" % (procfs_path, os.getpid()) + ) retlist = [] partitions = cext.disk_partitions(mounts_path) @@ -1318,7 +1328,7 @@ def disk_partitions(all=False): if fstype == "zfs": fstypes.add("zfs") - if os.path.exists("%s/self/mountinfo" % procfs_path): + if os.path.exists("%s/%s/mountinfo" % (procfs_path, os.getpid())): rawlist = _disk_partitions_mountinfo() else: rawlist = _disk_partitions_getmntent() diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index 90de0e682..9ee9bb69d 100755 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -1146,6 +1146,28 @@ def df(path): self.assertAlmostEqual(usage.used, used, delta=TOLERANCE_DISK_USAGE) + def test_against_mount(self): + def parse_mount(): + ls = [] + out = sh("mount") + for line in out.splitlines(): + fields = line.split() + device = fields[0] + mountpoint = fields[2] + fstype = fields[4] + opts = fields[5][1:-1] + ls.append((device, mountpoint, fstype, opts)) + return ls + + self.assertEqual( + parse_mount(), psutil._psplatform._disk_partitions_mountinfo()) + self.assertEqual( + parse_mount(), psutil._psplatform._disk_partitions_getmntent()) + self.assertEqual( + parse_mount(), + [tuple(x[:4]) for x in psutil.disk_partitions(all=True)] + ) + def test_zfs_fs(self): # Test that ZFS partitions are returned. with open("/proc/filesystems") as f: @@ -1187,10 +1209,8 @@ def test_getmntent_emulate_realpath_fail(self): def test_getmntent_mountinfo_parity(self): # exclude opts, because they're slightly different for some reason self.assertEqual( - sorted([x[:-1] for x in - psutil._psplatform._disk_partitions_getmntent()]), - sorted([x[:-1] for x in - psutil._psplatform._disk_partitions_mountinfo()]) + psutil._psplatform._disk_partitions_getmntent(), + psutil._psplatform._disk_partitions_mountinfo() )