Bug#1061248: glibc: DEP17: move most files but rtld to /usr
Hi Aurelien and Sven,
On Wed, Jan 24, 2024 at 09:19:12PM +0100, Aurelien Jarno wrote:
> On 2024-01-23 17:40, Helmut Grohne wrote:
> > Conflicting runtime dynamic linkers between multiarch packages
> > ==============================================================
> >
> > Some architecture combinations such as s390, powerpc, hppa, m68k,
> > mipsn32, and hurd-i386 or alpha, i386, sh4, and sparc have conflicting
> > runtime dynamic loaders. In theory this violates Multi-Arch: same, but
> > there is basically nothing we can do about this and dropping Multi-Arch:
> > same from the packages would completely break any kind of multiarch
> > setup. There is little we can do here and this is also unrelated to
> > DEP17.
>
> We tried to add conflicts for those, like it's done for the multilib
> packages, but at the time the infrastructure exploded (see #745552). I
> don't remember the details, but I guess it was either dak or
> dose-builddebcheck.
Yeah, I also remember something like that. It's not the first time I
trip into this. "There is little we can do here" still counts.
> I guess the symlink in the maintainer script could indeed work. I am not
> sure why it has been done like that, it was part of the multiarch
> patchset from Steve Langasek more than 10 years ago.
Practically speaking, it appears to work rather well. On the flip side,
I also thought that way of my first patch. ;)
> Note however that the those packages are used by cross-toolchain-base
> (which builds them from glibc-source) and mangled to install them in the
> cross path. See for instance libc6-amd64-x32-cross. For such cases, we
> probably do want to keep the dynamic linker symlink, as those packages
> do not have maintainer scripts.
I don't think those -$arch-cross packages need the runtime dynamic
linker at all. Unlike the libc6-$multilib packages, we don't use
-$arch-cross packages to actaully run any binary. Simply not installing
it might just work in practice.
So here is an updated patch with a few notes:
* This patch moves all the files including the runtime dynamic linker
in the main multiarch library. Therefore, this patch needs to be
synced with the corresponding base-files change to add the aliasing
symlinks or debootstrap breaks. In other words: Don't upload this
yet.
* As mentioned earlier, only the multiarch packages install the runtime
dynamic linker via data.tar. All the multilib packages install it via
maintainer scripts now.
* When installing libc6-x32, /libx32 will be created because partial
upgrades might otherwise be broken. Removing libc6-x32 will not
remove /libx32 though. I suggest fixing this in base-files by
installing a trigger interest in /usr/libx32 and having
base-files.postinst create/remove /libx32 as needed. This way, we
centralize the management of aliasing links into base-files. libx32
only serves as an example here and it works the same way for any
other non-essential multilib directory. Do you agree with the
approach?
* The multilib packages install a trigger interest on the runtime
dynamic linker such that they notice when a multiarch package deletes
it and can then recreate it as needed. Thus the multiarch packages do
not have to pay attention to a possibly installed multilib package
when they are removed.
* I've tried quite a few multiarch upgrades involving amd64 and i386
using dpkg --auto-deconfigure --unpack with various packages and even
cross grading libc6-x32 from :i386 to :amd64 during the upgrade.
While dpkg --verify was occasionally unhappy during a partial upgrade
(where half-unpacked packages were around), once no package was
half-installed, dpkg --verify was also happy again in all attempts. I
did not come up with a systematic enumeration of possible upgrade
scenarios though.
* The patch works will deboostrap/cdebootstrap/mmdebstrap (in
combination with more patches including base-files, bash, dash and
util-linux).
* The change to install ldconfig to /usr/sbin can be uploaded right
away. It's limited to debian/debhelper.in/libc-bin.install and
debian/debhelper.in/libc-bin.lintian-overrides and doesn't contribute
much diff, so doing it later is fine as well.
I hope you don't manage to punch holes into my theory this time around.
Helmut
diff --minimal -Nru glibc-2.37/debian/changelog glibc-2.37/debian/changelog
--- glibc-2.37/debian/changelog 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/changelog 2024-01-19 15:56:06.000000000 +0100
@@ -1,3 +1,10 @@
+glibc (2.37-14.1) UNRELEASED; urgency=medium
+
+ * Non-maintainer upload.
+ * DEP17: Move files to /usr. (Closes: #-1)
+
+ -- Helmut Grohne <helmut@subdivi.de> Fri, 19 Jan 2024 15:56:06 +0100
+
glibc (2.37-14) unstable; urgency=medium
[ Aurelien Jarno ]
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-alt.install glibc-2.37/debian/debhelper.in/libc-alt.install
--- glibc-2.37/debian/debhelper.in/libc-alt.install 2022-09-22 22:06:02.000000000 +0200
+++ glibc-2.37/debian/debhelper.in/libc-alt.install 2024-01-19 15:56:06.000000000 +0100
@@ -1,6 +1,5 @@
# This file is used for biarch libraries.
-TMPDIR/RTLDDIR/*.so* RTLDDIR
-TMPDIR/SLIBDIR/*.so* SLIBDIR
+TMPDIR/SLIBDIR/*.so* /usrSLIBDIR
TMPDIR/LIBDIR/gconv/* LIBDIR/gconv/
TMPDIR/etc/ld.so.conf.d /etc
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-alt.postinst glibc-2.37/debian/debhelper.in/libc-alt.postinst
--- glibc-2.37/debian/debhelper.in/libc-alt.postinst 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-alt.postinst 2024-01-19 15:56:06.000000000 +0100
@@ -0,0 +1,31 @@
+#!/bin/sh
+set -e
+
+# begin-remove-after: released:forky
+if [ "$1" = configure ]; then
+ # These symbolic links are either included in base-files or created by
+ # base-files via triggers, but we also create them to avoid a versioned
+ # dependency on base-files. Cleanup will be handled by base-files.
+ if ! [ -h "$DPKG_ROOTRTLDDIR" ]; then
+ ln -s "usrRTLDDIR" "$DPKG_ROOTRTLDDIR"
+ fi
+ if ! [ -h "$DPKG_ROOTSLIBDIR" ]; then
+ ln -s usrSLIBDIR "$DPKG_ROOTSLIBDIR"
+ fi
+fi
+# end-remove-after
+
+if [ "$1" = configure -o "$1" = triggered ] && ! [ -h "$DPKG_ROOT/usrRTLDDIR/RTLD_SO" ]; then
+ # In principle, this package should contain this link, but it also is
+ # contained in the multiarch libc package. To avoid a conflict and the need
+ # for declaring Replaces (which work badly with the /usr-move due to
+ # aliasing), we manually create this link whenever we are installed or
+ # upgraded or the multiarch libc is installed, upgraded or importantly
+ # removed. The link target is given as absolute without /usr. The runtime
+ # linker directory is always one level deep, so we can simply prepend "..".
+ ln -s ..RTLD_TARGET "$DPKG_ROOT/usrRTLDDIR/RTLD_SO"
+fi
+
+#DEBHELPER#
+
+exit 0
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-alt.postrm glibc-2.37/debian/debhelper.in/libc-alt.postrm
--- glibc-2.37/debian/debhelper.in/libc-alt.postrm 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-alt.postrm 2024-01-19 15:56:06.000000000 +0100
@@ -2,13 +2,12 @@
set -e
if [ "$1" = remove ]; then
- # Native multiarch packages declare a Replaces: on the corresponding
- # biarch package. Therefore if both a biarch package and the corresponding
- # multiarch package are installed, then the multiarch package is removed,
- # and then the biarch package is removed, the dynamic linker symlink
- # becomes a dangling symlink. Remove it in that case.
- if [ -h RTLDDIR/RTLD_SO ] && [ ! -f RTLDDIR/RTLD_SO ]; then
- rm RTLDDIR/RTLD_SO
+ # We manually installed this link in postinst if missing. It is also
+ # installed by the native multiarch package as a proper file. We have
+ # to remove it if we are the last package to provide it. Detect that
+ # situation by checking for a dangling link.
+ if [ -h /usrRTLDDIR/RTLD_SO ] && [ ! -f /usrRTLDDIR/RTLD_SO ]; then
+ rm /usrRTLDDIR/RTLD_SO
fi
fi
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-alt.preinst glibc-2.37/debian/debhelper.in/libc-alt.preinst
--- glibc-2.37/debian/debhelper.in/libc-alt.preinst 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-alt.preinst 2024-01-19 15:56:06.000000000 +0100
@@ -1,6 +1,7 @@
#!/bin/sh
set -e
+# begin-remove-after: released:forky
# We create the top-level lib symlink on merged-usr systems, so that we can
# cover cases where for example libc-i386 on amd64 is installed and then removed
# (which deletes the symlink too). Note that we only suppor the simplest case,
@@ -14,11 +15,11 @@
# If it has not, is a directory already there? Half-merged systems are
# the problem of usrmerge, simply ignore them here.
if [ ! -L SLIBDIR ] && [ ! -d SLIBDIR ]; then
- mkdir -p /usrSLIBDIR
ln -s usrSLIBDIR SLIBDIR
fi
fi
fi
+# end-remove-after
#DEBHELPER#
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-alt.triggers glibc-2.37/debian/debhelper.in/libc-alt.triggers
--- glibc-2.37/debian/debhelper.in/libc-alt.triggers 1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-alt.triggers 2024-01-19 15:56:06.000000000 +0100
@@ -0,0 +1,3 @@
+# Monitor the dynamic linker from the native multiarch package that is shared
+# with us.
+interest-noawait /usrRTLDDIR/RTLD_SO
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-bin.install glibc-2.37/debian/debhelper.in/libc-bin.install
--- glibc-2.37/debian/debhelper.in/libc-bin.install 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-bin.install 2024-01-19 15:56:06.000000000 +0100
@@ -4,7 +4,7 @@
debian/local/etc/nsswitch.conf usr/share/libc-bin
debian/local/etc/nss etc/default
posix/gai.conf etc
-sbin/ldconfig sbin
+sbin/ldconfig usr/sbin
usr/bin/getconf
usr/bin/getent
usr/bin/iconv
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-bin.lintian-overrides glibc-2.37/debian/debhelper.in/libc-bin.lintian-overrides
--- glibc-2.37/debian/debhelper.in/libc-bin.lintian-overrides 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-bin.lintian-overrides 2024-01-19 15:56:06.000000000 +0100
@@ -1,10 +1,10 @@
# ldconfig must be executable even when the libc is not configured, and
# thus must be linked statically
-statically-linked-binary sbin/ldconfig
-shared-library-lacks-prerequisites [sbin/ldconfig]
+statically-linked-binary usr/sbin/ldconfig
+shared-library-lacks-prerequisites [usr/sbin/ldconfig]
# these manpages are provided by the manpages package
-no-manual-page [sbin/ldconfig]
+no-manual-page [usr/sbin/ldconfig]
no-manual-page [usr/bin/getent]
no-manual-page [usr/bin/iconv]
no-manual-page [usr/bin/ld.so]
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-udeb.install glibc-2.37/debian/debhelper.in/libc-udeb.install
--- glibc-2.37/debian/debhelper.in/libc-udeb.install 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-udeb.install 2024-01-19 15:56:06.000000000 +0100
@@ -1,11 +1,11 @@
-lib*/ld*.so*
-lib/*/ld*.so*
-lib/*/libm.so.*
-lib/*/libmvec.so.*
-lib/*/libdl.so.*
-lib/*/libresolv.so.*
-lib/*/libc.so.*
-lib/*/librt.so.*
-lib/*/libpthread.so.*
-lib/*/libnss_dns.so.*
-lib/*/libnss_files.so.*
+RTLDDIR/ld*.so* /usrRTLDDIR
+SLIBDIR/ld*.so* /usrSLIBDIR
+SLIBDIR/libm.so.* /usrSLIBDIR
+SLIBDIR/libmvec.so.* /usrSLIBDIR
+SLIBDIR/libdl.so.* /usrSLIBDIR
+SLIBDIR/libresolv.so.* /usrSLIBDIR
+SLIBDIR/libc.so.* /usrSLIBDIR
+SLIBDIR/librt.so.* /usrSLIBDIR
+SLIBDIR/libpthread.so.* /usrSLIBDIR
+SLIBDIR/libnss_dns.so.* /usrSLIBDIR
+SLIBDIR/libnss_files.so.* /usrSLIBDIR
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc-udeb.install.hurd-i386 glibc-2.37/debian/debhelper.in/libc-udeb.install.hurd-i386
--- glibc-2.37/debian/debhelper.in/libc-udeb.install.hurd-i386 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc-udeb.install.hurd-i386 2024-01-19 15:56:06.000000000 +0100
@@ -1,14 +1,14 @@
-lib*/ld*.so*
-lib/*/ld*.so*
-lib/*/libm.so.*
-lib/*/libmvec.so.*
-lib/*/libdl.so.*
-lib/*/libresolv.so.*
-lib/*/libc.so.*
-lib/*/libutil.so.*
-lib/*/librt.so.*
-lib/*/libpthread.so.*
-lib/*/libnss_dns.so.*
-lib/*/libnss_files.so.*
-lib/*/libmachuser.so.*
-lib/*/libhurduser.so.*
+RTLDDIR/ld*.so* /usrRTLDDIR
+SLIBDIR/ld*.so* /usrSLIBDIR
+SLIBDIR/libm.so.* /usrSLIBDIR
+SLIBDIR/libmvec.so.* /usrSLIBDIR
+SLIBDIR/libdl.so.* /usrSLIBDIR
+SLIBDIR/libresolv.so.* /usrSLIBDIR
+SLIBDIR/libc.so.* /usrSLIBDIR
+SLIBDIR/libutil.so.* /usrSLIBDIR
+SLIBDIR/librt.so.* /usrSLIBDIR
+SLIBDIR/libpthread.so.* /usrSLIBDIR
+SLIBDIR/libnss_dns.so.* /usrSLIBDIR
+SLIBDIR/libnss_files.so.* /usrSLIBDIR
+SLIBDIR/libmachuser.so.* /usrSLIBDIR
+SLIBDIR/libhurduser.so.* /usrSLIBDIR
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc.install glibc-2.37/debian/debhelper.in/libc.install
--- glibc-2.37/debian/debhelper.in/libc.install 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc.install 2024-01-19 15:56:06.000000000 +0100
@@ -1,4 +1,4 @@
etc/ld.so.conf.d
-lib*/ld*.so*
-lib/*/*.so*
+RTLDDIR/ld*.so* /usrRTLDDIR
+SLIBDIR/*.so* /usrSLIBDIR
usr/lib/*/gconv
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc.postrm glibc-2.37/debian/debhelper.in/libc.postrm
--- glibc-2.37/debian/debhelper.in/libc.postrm 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc.postrm 2024-01-19 15:56:06.000000000 +0100
@@ -2,18 +2,8 @@
set -e
if [ "$1" = remove ]; then
- # When both the multiarch and the corresponding biarch packages are
- # installed, removing the multiarch package will remove the dynamic
- # linker. Recreate it in the postinst.
- ARCH=${DPKG_MAINTSCRIPT_ARCH}
- target=$(dpkg-query -L LIBC-${ARCH} 2>/dev/null | grep -E '/lib.+/(ld\.so|RTLD_SO)$' || true)
- if [ -f "$target" ] && ! [ -f RTLDDIR/RTLD_SO ] ; then
- ln -sf ${target#RTLDDIR/} RTLDDIR/RTLD_SO
- fi
-fi
-
-if [ "$1" = deconfigure ]; then
- :; # blah, do something useful with ldso
+ # Remove DEP17 M8 protective diversion
+ dpkg-divert --quiet --remove --no-rename --divert "RTLDDIR/RTLD_SO.usr-is-merged" "RTLDDIR/RTLD_SO"
fi
#DEBHELPER#
diff --minimal -Nru glibc-2.37/debian/debhelper.in/libc.preinst glibc-2.37/debian/debhelper.in/libc.preinst
--- glibc-2.37/debian/debhelper.in/libc.preinst 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/debhelper.in/libc.preinst 2024-01-19 15:56:06.000000000 +0100
@@ -295,6 +295,25 @@
fi
fi
+# begin-remove-after: released:forky
+# Add DEP17 M4 protective diversions. These should be added by base-files, but
+# we want to avoid Pre-Depends: base-files (>= trixie) and therefore add them
+# for base-files. As bookworm's base-files installs bin lib and sbin, the only
+# directory we may miss is the one containing the runtime linker when it is not
+# /lib.
+if [ "$1" = install -o "$1" = upgrade ] && [ "RTLDDIR" != "/lib" ]; then
+ dpkg-divert --quiet --add --no-rename --package base-files --divert "RTLDDIR.usr-is-merged" "RTLDDIR"
+fi
+# end-remove-after
+
+# Add DEP17 M8 protective diversions for the runtime dynamic linker. It is
+# installed in both libc (multiarch) and libc-alt (multilib) amounting to a
+# move and thus DEP17 P1 problem. This diversion should be removed by forky's
+# libc.postinst.
+if [ "$1" = install ] || [ "$1" = upgrade ]; then
+ dpkg-divert --quiet --add --no-rename --divert "RTLDDIR/RTLD_SO.usr-is-merged" "RTLDDIR/RTLD_SO"
+fi
+
#DEBHELPER#
if [ -n "$preversion" ]; then
diff --minimal -Nru glibc-2.37/debian/rules glibc-2.37/debian/rules
--- glibc-2.37/debian/rules 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/rules 2024-01-19 15:56:06.000000000 +0100
@@ -91,6 +91,7 @@
mvec = no
rtld_so=$(shell awk 'BEGIN {FS="="} /^ld\.so-version/ {print $$2}' $(DEB_BUILDDIR)/soversions.mk)
+rtld_target=$(shell readlink $(debian-tmp)$(rtlddir)/$(rtld_so))
libc_so=$(shell awk 'BEGIN {FS="="} /^libc\.so-version/ {print "libc.so"$$2}' $(DEB_BUILDDIR)/soversions.mk)
BASE_CC = gcc
diff --minimal -Nru glibc-2.37/debian/rules.d/debhelper.mk glibc-2.37/debian/rules.d/debhelper.mk
--- glibc-2.37/debian/rules.d/debhelper.mk 2024-01-23 07:13:18.000000000 +0100
+++ glibc-2.37/debian/rules.d/debhelper.mk 2024-01-19 15:56:06.000000000 +0100
@@ -30,6 +30,14 @@
dh_installsystemd -p$(curpass)
dh_installdocs -p$(curpass)
dh_lintian -p $(curpass)
+
+ # Ensure that symlinks resolve even when /usr is unmerged.
+ set -e; \
+ find "debian/$(curpass)" \( -lname "*../lib*" -o -lname "/lib*" \) -printf "%p*%l\n" | \
+ while IFS='*' read -r p l; do \
+ ln -svf "$${l%%/lib*}/usr/lib$${l#*/lib}" "$$p"; \
+ done
+
dh_link -p$(curpass)
dh_bugfiles -p$(curpass)
@@ -89,6 +97,14 @@
dh_installdirs -p$(curpass)
dh_install -p$(curpass)
dh_strip -p$(curpass)
+
+ # Ensure that symlinks resolve even when /usr is unmerged.
+ set -e; \
+ find "debian/$(curpass)" \( -lname "*../lib*" -o -lname "/lib*" \) -printf "%p*%l\n" | \
+ while IFS='*' read -r p l; do \
+ ln -svf "$${l%%/lib*}/usr/lib$${l#*/lib}" "$$p"; \
+ done
+
dh_link -p$(curpass)
# when you want to install extra packages, use extra_pkg_install.
@@ -153,6 +169,8 @@
slibdir=$(call xx,slibdir) ; \
rtlddir=$(call xx,rtlddir) ; \
curpass=$(curpass) ; \
+ rtld_so=$(rtld_so) ; \
+ rtld_target=$(rtld_target) ; \
templates="libc-dev" ;\
pass="" ; \
suffix="" ;\
@@ -181,6 +199,8 @@
-e "s#RTLDDIR#$$rtlddir#g" \
-e "s#SLIBDIR#$$slibdir#g" \
-e "s#LIBDIR#$$libdir#g" \
+ -e "s#RTLD_SO#$$rtld_so#g" \
+ -e "s#RTLD_TARGET#$$rtld_target#g" \
-e "/gdb/d" \
-e "/audit/d" \
$$t; \
@@ -194,6 +214,7 @@
rtlddir=$(call xx,rtlddir) ; \
curpass=$(curpass) ; \
rtld_so=$(rtld_so) ; \
+ rtld_target=$(rtld_target) ; \
case "$$curpass:$$slibdir" in \
libc:*) \
templates="libc libc-dev libc-udeb" \
@@ -217,6 +238,7 @@
sed -e "s#SLIBDIR#$$slibdir#g" -i $$t; \
sed -e "s#LIBDIR#$$libdir#g" -i $$t; \
sed -e "s#RTLD_SO#$$rtld_so#g" -i $$t ; \
+ sed -e "s#RTLD_TARGET#$$rtld_target#g" -i $$t ; \
$(if $(filter $(call xx,mvec),no),sed -e "/libmvec/d" -e "/libm-\*\.a/d" -i $$t ;) \
$(if $(filter-out $(DEB_HOST_ARCH_OS),linux),sed -e "/gdb/d" -i $$t ;) \
done ; \
Reply to: