#945019 binfmt-support: please use dpkg triggers

Package:
binfmt-support
Source:
binfmt-support
Description:
Support for extra binary formats
Submitter:
Helmut Grohne
Date:
2019-11-19 11:27:08 UTC
Severity:
wishlist
#945019#5
Date:
2019-11-18 13:35:03 UTC
From:
To:
Hi Colin,

/usr/share/doc/binfmt-support/README.Debian advises developers to put
"update-binfmts --import $PACKAGENAME" into their postinst script and
"update-binfmts --unimport $PACKAGENAME" into their prerm script. Doing
so has four drawbacks:

1. It is repetitive across each user of binfmt-support. If the call
   needs to change somehow, we'll have a long transition of a MBF. And
   yes, it did change (qemu still uses the old interface).
2. If binfmt-support integration is optional (as is the case with qemu),
   one also must check for the presence of update-binfmts, which makes
   maintainer scripts longer.
3. If binfmt-support integration is optional (as is the case with qemu)
   and binfmt-support is installed after the integrating package, the
   kernel support goes missing. This has been reported as #866756 for
   instance. As such, optional integration does not work reliably at
   all, but it is the common way of working with binfmt-support (for
   instance python suffers from the same issue).
4. We want to get rid of maintainer scripts as much as possible.

All of the above issues are addressed by having binfmt-support handle
the importing and exporting using dpkg triggers. binfmt-support could
declare an interest-noawait on /usr/share/binfmts and import all missing
formats automatically. Thus installing binfmt-support would immediately
register already installed formats without running configure scripts of
other packages again.

What do you think?

This does pose a significant change in interface and needs to interact
with the existing --import/--unimport calls in some way, but after
moving there, we'll get rid of a pile of maintainer scripts. Does it
have any other drawbacks? I know you know about triggers, so very likely
this has crossed your mind already and possibly the --import/--unimport
was preparing for triggers.

Helmut

#945019#14
Date:
2019-11-18 14:22:53 UTC
From:
To:
This is only because qemu uses the old interface.  If it used the "new"
(from 2002 ...) interface with files in /usr/share/binfmts/, then the
call to "update-binfmts --import" in binfmt-support.postinst would take
care of it.

I can confirm that this was my ultimate intention, although it's true we
haven't quite got there yet.  Things that need to be fixed and/or
carefully checked:

 * --import and --unimport exist, but there isn't quite a "sync"
   operation that imports any binary formats that have been added to
   /usr/share/binfmts/ and unimports any that have been removed.
   --unimport immediately followed by --import sort of does the job, but
   is invasive.

 * qemu-user-static does conditional registration partly in order to
   avoid registering a binary format for the native architecture, which
   would immediately crash the system.  This could surely be done in
   debian/rules instead, conditionally installing binary format files
   for use by --import, but the consequences are serious if it goes
   wrong so we need to be careful.

 * We'll probably have to audit all other relevant maintainer scripts
   for weird stuff too.

 * I don't think the duplication with existing --import/--unimport calls
   would be a serious problem.  As long as --unimport goes with actually
   removing the file, they should IIRC be idempotent, though of course
   we need to check that.

#945019#19
Date:
2019-11-19 07:35:16 UTC
From:
To:
Hi Colin,

I disagree here. If qemu-user-static's postinst runs before
binfmt-support is unpacked, it'll skip the update-binfmts calls
regardless of whether it uses --import or the old interface. This is
only dependent on the order of binfmts-support unpack vs.
qemu-user-static.postinst.

Of course for getting the trigger behaviour that I was asking for, we
must change qemu. To that end, I've sent a patch to #866756 that
converts it to use --import/--unimport. I agree this is part of the
solution, but this part is insufficient. (I had to wait for greylisting,
to know the bug number of this bug.)

Great!

How about this pseudo code being added to binfmt-support.postinst into a
section that acts on triggers?

for fmt in /var/lib/binfmts/*; do
    fmt=${fmt#/var/lib/binfmts/}
    if ! test -e "/usr/share/binfmts/$fmt" || \
       test "/usr/share/binfmts/$fmt" -nt "/var/lib/binfmts/$fmt"; then
        update-binfmts --unimport "$fmt"
    fi
done
for fmt in /usr/share/binfmts/*; do
    fmt=${fmt#/usr/share/binfmts/}
    if ! test -e "/var/lib/binfmts/$fmt"; then
        update-binfmts --import "$fmt"
    fi
done

Unless I am mistaken, this is the sync operation you are looking for.

As bad as it looks, this is actually easy. The condition is on the host
architecture, which is something we know at build time. We can do the
heavy lifting at build time and check the generated /usr/share/binfmts/*
before installing the package. The format files for native (and sibling)
architectures simply go missing. My patch for #866756 does that.

Regardless of the patch, bad things do happen if you attempt to install
say qemu-user-static:arm64 on and amd64 system. I don't see any use case
for this though given that qemu-user-static is M-A:foreign.

Yes. To the best of my knowledge, this has not been done by anyone yet.

Great.

So provided someone checked maintainer scripts for weird stuff, would
you add my sync code to binfmt-support with a interest-noawait on
/usr/share/binfmts?

Helmut

#945019#24
Date:
2019-11-19 10:38:43 UTC
From:
To:
It'll skip it in qemu-user-static.postinst, yes, but then when
binfmt-support is configured it will catch up with any format files that
are already installed.

Are you missing something or am I?

Thanks.  I haven't gone through it in detail but it looks credible
enough (except that "command -v" is I think non-portable, which is why
binfmt-support's README.Debian recommends the use of "which").

How about the versioned Conflicts suggested in binfmt-support's
README.Debian to ensure that --unimport is available?  (Or versioned
Breaks would probably do as well.)

I think this may work, but I'd like to at least investigate doing it in
update-binfmts's C code instead.  The older I get the less interested I
am in following careful logic in shell. :-)

Agreed - I just wanted to flag it as needing care.

As I say I'd prefer something like "update-binfmts --sync", but in
principle yes.  (Hopefully I will have time to have a look at that
soonish.)

#945019#29
Date:
2019-11-19 11:23:39 UTC
From:
To:
Hi Colin,

I am. Thank you for insisting. I was missing the bare update-binfmts
--import call.

So the patch I sent fully resolves the problem on the qemu side without
further changes to binfmt-support. \o/

Triggers are still nice to have.

Oh, I missed those. I vaguely question their utility though given that
you'd have to upgrade from stretch to bullseye directly to experience an
issue.

Oh sure. I do prefer less code in maintainer scripts. :)

Given that I missed the --import part, I'm less interested in the "soon"
part now. ;)

Thank you for the quick and helpful replies.

Helmut