[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#1110696: libglib2.0-0t64: Purging libglib2.0-0:i386 removed gschemas.compiled



On Sun, 10 Aug 2025 at 15:14:47 +0800, Tianyu Chen wrote:
This is a similar bug to #1065022. but a more corner case.

During the t64 transition, purging libglib2.0-0 removed
/usr/share/glib-2.0/schemas/gschemas.compiled, libglib2.0-0t64 added a
preinst script removing all libglib2.0-0:$arch.postrm to prevent file
loss. [1]

Context for the dpkg team (in cc): GLib uses dpkg triggers to maintain some functionally-necessary cache files which list data files and plugins installed by dependent packages in a more efficient format, which is quite a standard pattern for use of dpkg triggers. When the last instance of GLib is removed, these cache files should also be removed (otherwise they will hang around on the system indefinitely, wasting a small amount of disk space), and the current implementation is to do that during purge.

Unfortunately, the GLib in releases <= bookworm assumed that the package containing GLib 2 would always be libglib2.0-0; this didn't account for ABI-breaking transitions like time64, which renamed that package to libglib2.0-0t64. As a result it is harmful to run the postrm of the old GLib after a new GLib has been installed. Newer GLib releases avoid this happening by having the libglib2.0-0t64 preinst delete the faulty libglib2.0-0 postrm.

Sometime before the t64 transition, I decided to drop all :i386 packages
on my laptop. I removed [but did not purge] all i386 packages,
[and then ran] $(dpkg --remove-architecture i386).

I'm a little surprised that dpkg allows this: I would have expected it not to allow the i386 architecture to be removed until all i386 packages had been fully removed, i.e. purged?

In the [preinst] script, [libglib2.0-0t64] uses:

   for arch in $(dpkg --print-architecture) $(dpkg --print-foreign-architectures)

to loop through all architectures, which should look good, but I encountered
a corner case here.

So, yes, the problem here was that libglib2.0-0t64 disarms the faulty maintainer scripts of libglib2.0-0 on architectures that are still enabled, but does not disarm the maintainer script of architectures that dpkg no longer allows installing on this system (in this case i386), and dpkg can still end up running those maintainer scripts when old packages are purged.

dpkg team: is there a good way to ask dpkg for a full list of architectures that might conceivably have a package installed?

I suppose there's

    dpkg-query -W -f '${Architecture}\n' | sort -u | grep -v '^all$'

but, ugh. (Would that be considered a reasonable thing to do in a maintscript?) Or is there a better way?

With hindsight, it would probably have been a good safety-catch against accidents if the postrm refused to remove the cache files as long as one of the files that contributes to the cache exists:

- don't delete /usr/share/glib-2.0/schemas/gschemas.compiled if at least one file /usr/share/glib-2.0/schemas/*.xml exists; - don't delete /usr/lib/${multiarch}/gio/modules/giomodule.cache if at least one file /usr/lib/${multiarch}/gio/modules/*.so exists

Obviously we can't make that change retroactively without a time machine, but we could make that change in testing/unstable, in trixie via trixie-pu, and even in bookworm via bookworm-pu, which would mean that at least users with a fully upgraded (old)stable can't encounter this.

Also with hindsight, it would perhaps have been better if libglib2.0-0:*.postrm cleaned up the cache files during remove, rather than during purge, which would not have solved the original issue but would at least have avoided the action-at-a-distance of deferring their deletion until the packages are finally purged?

I think the ideal solution to this would be if dpkg had a way for packages to declare that they (perhaps jointly) "own" a generated file (prior art: I believe this is what RPM %ghost files are for), so that *dpkg* could be responsible for deleting the generated file at the reference-count transition from 1 to 0 owners. This would fit very nicely with triggers: declare a trigger on the inputs, and declare the generated file as a ghost file. But, again, in the absence of a time machine, new feature development in dpkg won't solve the immediate problem with GLib.

I've fixed this by dpkg-reconfigure libglib2.0-0t64, which runs
glib-compile-schemas.

I confirm that running `dpkg-reconfigure libglib2.0-0t64` is a good workaround for this issue: that brings back the deleted file /usr/share/glib-2.0/schemas/gschemas.compiled.

    smcv


Reply to: