diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:14:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:14:39 +0000 |
commit | ee17e45964b786b48b455959dfe68715971893fb (patch) | |
tree | 118f40aa65dc838499053413b05adfd00f839c62 /ldconfig.fakechroot | |
parent | Initial commit. (diff) | |
download | mmdebstrap-ee17e45964b786b48b455959dfe68715971893fb.tar.xz mmdebstrap-ee17e45964b786b48b455959dfe68715971893fb.zip |
Adding upstream version 1.4.3.upstream/1.4.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ldconfig.fakechroot')
-rwxr-xr-x | ldconfig.fakechroot | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/ldconfig.fakechroot b/ldconfig.fakechroot new file mode 100755 index 0000000..c3455af --- /dev/null +++ b/ldconfig.fakechroot @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +# +# This script is in the public domain +# +# Author: Johannes Schauer Marin Rodrigues <josch@mister-muffin.de> +# +# This is command substitution for ldconfig under fakechroot: +# +# export FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/path/to/ldconfig.fakechroot +# +# Statically linked binaries cannot work with fakechroot and thus have to be +# replaced by either /bin/true or a more clever solution like this one. The +# ldconfig command supports the -r option which allows passing a chroot +# directory for ldconfig to work in. This can be used to run ldconfig without +# fakechroot but still let it create /etc/ld.so.cache inside the chroot. +# +# Since absolute symlinks are broken without fakechroot to translate them, +# we read /etc/ld.so.conf and turn all absolute symlink shared libraries into +# relative ones. At program exit, the original state is restored. + + +import os +import sys +import subprocess +import atexit +import glob +from pathlib import Path + +symlinks = [] + + +def restore_symlinks(): + for (link, target, atime, mtime) in symlinks: + link.unlink() + link.symlink_to(target) + os.utime(link, times=None, ns=(atime, mtime), follow_symlinks=False) + + +atexit.register(restore_symlinks) + + +def get_libdirs(chroot, configs): + res = [] + for conf in configs: + for line in (Path(conf)).read_text().splitlines(): + line = line.strip() + if not line: + continue + if line.startswith("#"): + continue + if line.startswith("include "): + assert line.startswith("include /") + res.extend( + get_libdirs(chroot, chroot.glob(line.removeprefix("include /"))) + ) + continue + assert line.startswith("/"), line + line = line.lstrip("/") + if not (chroot / Path(line)).is_dir(): + continue + for f in (chroot / Path(line)).iterdir(): + if not f.is_symlink(): + continue + linktarget = f.readlink() + # make sure that the linktarget is an absolute path inside the + # chroot + if not str(linktarget).startswith("/"): + continue + if chroot not in linktarget.parents: + continue + # store original link so that we can restore it later + symlinks.append( + (f, linktarget, f.lstat().st_atime_ns, f.lstat().st_mtime_ns) + ) + # replace absolute symlink by relative link + relative = os.path.relpath(linktarget, f.parent) + f.unlink() + f.symlink_to(relative) + return res + + +def main(): + if "FAKECHROOT_BASE_ORIG" not in os.environ: + print("FAKECHROOT_BASE_ORIG is not set", file=sys.stderr) + print( + "must be executed under fakechroot using FAKECHROOT_CMD_SUBST", + file=sys.stderr, + ) + sys.exit(1) + + chroot = Path(os.environ["FAKECHROOT_BASE_ORIG"]) + + # if chrootless mode is used from within a fakechroot chroot, then + # FAKECHROOT_BASE_ORIG will point at the outer chroot. We want to use + # the path from DPKG_ROOT inside of that instead + if os.environ.get("DPKG_ROOT", "") not in ["", "/"]: + chroot /= os.environ["DPKG_ROOT"].lstrip("/") + + if not (chroot / "sbin" / "ldconfig").exists(): + sys.exit(0) + + (chroot / "var" / "cache" / "ldconfig").mkdir( + mode=0o700, parents=True, exist_ok=True + ) + + for d in get_libdirs(chroot, [chroot / "etc" / "ld.so.conf"]): + make_relative(d) + + rootarg = chroot + argv = sys.argv[1:] + for arg in sys.argv[1:]: + if arg == "-r": + rootarg = None + elif rootarg is None: + argpath = Path(arg) + if argpath.is_absolute(): + rootarg = chroot / argpath.relative_to("/") + else: + rootarg = Path.cwd() / argpath + if rootarg is None: + rootarg = chroot + + # we add any additional arguments before "-r" such that any other "-r" + # option will be overwritten by the one we set + subprocess.check_call( + [chroot / "sbin" / "ldconfig"] + sys.argv[1:] + ["-r", rootarg] + ) + + +if __name__ == "__main__": + main() |