aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/portage/util/_dyn_libs/dyn_libs.py')
-rw-r--r--lib/portage/util/_dyn_libs/dyn_libs.py65
1 files changed, 65 insertions, 0 deletions
diff --git a/lib/portage/util/_dyn_libs/dyn_libs.py b/lib/portage/util/_dyn_libs/dyn_libs.py
new file mode 100644
index 000000000..6f8a07d70
--- /dev/null
+++ b/lib/portage/util/_dyn_libs/dyn_libs.py
@@ -0,0 +1,65 @@
+# Copyright 2021-2024 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+import os
+import stat
+
+import portage
+
+
+def installed_dynlibs(directory):
+ """
+ This traverses installed *.so symlinks to check if they point to
+ regular files. If a symlink target is outside of the top directory,
+ traversal follows the corresponding file inside the top directory
+ if it exists, and otherwise stops following the symlink.
+ """
+ directory_prefix = f"{directory.rstrip(os.sep)}{os.sep}"
+ for parent, _dirnames, filenames in os.walk(directory):
+ for filename in filenames:
+ if filename.endswith(".so"):
+ filename_abs = os.path.join(parent, filename)
+ target = filename_abs
+ levels = 0
+ while True:
+ try:
+ st = os.lstat(target)
+ except OSError:
+ break
+ if stat.S_ISREG(st.st_mode):
+ return True
+ elif stat.S_ISLNK(st.st_mode):
+ levels += 1
+ if levels == 40:
+ portage.writemsg(
+ f"too many levels of symbolic links: {filename_abs}\n",
+ noiselevel=-1,
+ )
+ break
+ target = portage.abssymlink(target)
+ if not target.startswith(directory_prefix):
+ # If target is outside the top directory, then follow the
+ # corresponding file inside the top directory if it exists,
+ # and otherwise stop following.
+ target = os.path.join(
+ directory_prefix, target.lstrip(os.sep)
+ )
+ else:
+ break
+ return False
+
+
+def check_dyn_libs_inconsistent(directory, provides):
+ """Checks directory for whether any dynamic libraries were installed and
+ if PROVIDES corresponds."""
+
+ # Let's check if we've got inconsistent results.
+ # If we're installing dynamic libraries (.so files), we should
+ # really have a PROVIDES.
+ # (This is a complementary check at the point of ingestion for the
+ # creation check in doebuild.py)
+ # Note: we could check a non-empty PROVIDES against the list of .sos,
+ # but this doesn't gain us anything. We're interested in failure
+ # to properly parse the installed files at all, which should really
+ # be a global problem (e.g. bug #811462)
+ return not provides and installed_dynlibs(directory)