forked from josch/mmdebstrap
add ldconfig.fakechroot and translate symlinks for bit-by-bit identical buildd variant
parent
b3e08897c3
commit
6d59d51a4a
@ -0,0 +1,111 @@
|
||||
#!/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 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)
|
||||
|
||||
# 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", chroot]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue