packaging: maintainer script templating and control metadata - #107
Christopher Obbard (obbardc) wants to merge 9 commits into
Conversation
The worked example of how KVER is composed added -qcom-next-20260826 to a 7.0.0-rc2 base and arrived at 7.2.0-qcom-next-20260826, so the base version on the left and the release on the right disagreed: the LOCALVERSION suffix is appended to the base version and nothing in 'prepare' rewrites it, which is the one thing the example exists to show. Say 7.2.0-rc7 on both sides. The arithmetic is the point here, not which particular release is current, and -rc7 is the version the surrounding examples already use. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Only the postinst was a @kver@ template; the preinst and postrm were copied in verbatim. That left the postrm reconstructing the kernel release at run time, by stripping "linux-image-" and a trailing "-qcom" off DPKG_MAINTSCRIPT_PACKAGE. The suffix is not part of the package name any more -- the package is linux-image-<kernelrelease>, and the release carries its own +qcom-next-<date>-g<sha> -- so the strip is a no-op at best, and at worst chops a real part of the version off and runs the hooks for a kernel that does not exist. Rename all three to .in and substitute @kver@ into each, so every script names its own kernel release the way the postinst already did. The scripts now share one shape: header, set -e, KVER, #DEBHELPER#, body. override_dh_installdeb generates them in one loop over the four maintainer script names, taking whichever templates exist, so adding a prerm becomes a matter of adding debian/linux-image.prerm.in. debian/clean and .gitignore already cover all four generated names. Which hook directories those scripts run is unchanged here, and wrong on forky; the next commit fixes that. Verified that the three generated scripts are shellcheck-clean with no @kver@ left in them, and that the postrm now names the same release the postinst does. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Kernel hooks used to live only in /etc/kernel/{postinst,postrm}.d, so that is
the one directory the maintainer scripts run. Since linux-base 4.11 a package
that ships its own hook installs it in /usr/share/kernel/*.d instead, leaving
/etc for the administrator, and systemd-boot's zz-systemd-boot made that move
in forky: on trixie it is a conffile in /etc/kernel/postinst.d, on forky
nothing is installed there at all.
The result is that installing this package on forky writes the kernel to /boot
and stops. No loader entry and no loader.conf are generated, so the new kernel
is invisible to sd-boot and the board comes back on the old one. The workaround
people have been using is to symlink the hooks into /etc before installing the
kernel package, which is the administrator's directory and not ours to
populate.
Dispatch through linux-run-hooks(1) instead, which is what Debian's own
linux-image packages call: it runs both directories in the documented order
and sets DEB_MAINT_PARAMS. The postrm gains the same treatment, so removing a
kernel drops its loader entry rather than leaving sd-boot offering a kernel
that is gone.
The command ships in linux-base, and nothing said it had to be there --
linux-base arrived unversioned, if at all, through the initramfs-tools or
dracut we merely recommend. Declare it the way Debian's linux-image packages
do, with Pre-Depends: linux-base (>= 4.12~). Pre- is the right strength for
the same reason it is right for them: the command runs from our postinst, so
it has to be configured before we are.
There is deliberately no run-parts fallback for the case where the command is
missing. Running /etc/kernel/*.d alone is not a degraded path, it is precisely
the silent unbootable install above, so a fallback could only reintroduce the
bug this commit exists to fix while hiding the missing dependency. The
postinst calls the command unguarded, as Debian's does.
The postrm is the exception and tests for it first. Pre-Depends holds while
the package is installed, not while it is being removed: dpkg may remove
linux-base in the same run, and on purge it can already be gone. Debian's
postrm guards it for the same reason and warns rather than failing -- a kernel
has to stay removable, and a skipped hook run there costs a stale bootloader
entry, not a system that will not boot. The warning says as much, on stderr.
The field is a plain line in control.in rather than something 'prepare'
decides per suite, because there is no suite to make an exception for: the
matrix builds trixie, forky and resolute, carrying 4.12.1, 4.17 and
4.15ubuntu5. Only noble in build-kernel.sh's list of accepted --distro values
predates 4.12, and nothing builds it. A build aimed there would produce a
package noble refuses to install, which is the better failure.
Note that linux-run-hooks arrived in linux-base 4.12, not the 4.11 that
release notes for the /usr/share move suggest: 4.12's changelog adds the
command, and Debian's kernel pre-depends on that same 4.12.
Verified on forky that linux-run-hooks runs both directories; over the
generated scripts, that postinst and postrm both dispatch with the version and
image path when the command is present, that the postrm takes the warning
branch and still exits 0 when it is absent, and that all three scripts are
shellcheck-clean; that 'prepare' emits the Pre-Depends field whatever DISTRO
it is given, the stanza parsing through Dpkg::Control::Info; and that
dpkg --compare-versions agrees 4.12.1 and 4.15ubuntu5 satisfy the clause while
4.11 and 4.5ubuntu9 do not.
Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The -dbg package ships each module's debug file only at the path that mirrors where the module installs, /usr/lib/debug + /lib/modules/<ver>/ kernel/<path>. scripts/package/builddeb, which this package otherwise follows, writes that path and also a /usr/lib/debug/.build-id/xx/yyy.debug symlink to it. We were missing the second one. It matters because the mirrored path only answers a lookup for a module addressed as /lib/modules/...: /lib is a symlink to /usr/lib, so a tool that reaches the module by its canonical name looks for /usr/lib/debug/usr/lib/modules/..., which nothing in the package provides. The build-id path does not depend on how the module was addressed at all, and it is the one gdb and debuginfod consult first. Extract the build ID with readelf -n in the same loop that extracts the symbols, and link the two paths together relatively, so the link is correct in the staging tree and stays correct once installed. A module built without a build ID keeps its mirrored debug file and gets a warning rather than a .build-id/.debug entry named after an empty ID. bundle-dkms-modules.sh gets the same treatment for the modules it puts in extra/, reading the ID from the module before Stage 3 strips it. It calls the host readelf, as its DWARF assertion already does -- readelf parses ELF directly and is not tied to a target. debian/rules resolves a cross readelf alongside its cross objcopy instead, which is what builddeb does. Verified by replaying the loop over a small ELF tree: the symlink lands at .build-id/<first two hex>/<rest>.debug, resolves to the mirrored debug file through a relative path that survives installation, and a module with --build-id=none takes the warning branch and still ships its symbols. Not verified with a debugger actually resolving a module by build ID. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The image carries a built copy of every module named in DKMS_MODULES, installed in /lib/modules/<kver>/extra/ by bundle-dkms-modules.sh, but nothing in the package says so. Anything that depends on kgsl-dkms to get the kgsl module has to be told separately that this kernel already has it. Emit a Provides entry per bundled module, generated in 'prepare' from the same DKMS_LIST that already drives Build-Depends and the dkms-modules manifest, so the three cannot drift. With DKMS_MODULES=kgsl,camx the image package now provides kgsl-dkms and camx-dkms alongside linux-image and linux-image-arm64; with the list empty the field is exactly what control.in spells, as with Build-Depends. The entries are unversioned. A dkms source's PACKAGE_VERSION is the module version, not the version of the Debian package that shipped it, so a version clause here would claim something we cannot check -- and an unversioned Provides deliberately does not satisfy a versioned dependency, which is the right answer when the caller wants a specific dkms release. This says "the module is here", not "the dkms source is here": the kernel provides a module built for one kernel release, and cannot build one for any other. Installing the real -dkms package alongside is still possible after this commit, and still builds a second copy into updates/dkms/ that shadows ours. Refusing that outright -- a Breaks against the -dkms packages we provide -- is a separate decision, and not one this commit makes. Verified by running prepare over a stub kernel tree: DKMS_MODULES=kgsl,camx produces "Provides: linux-image, linux-image-arm64, kgsl-dkms, camx-dkms" and an empty list leaves the line untouched, both parsing clean through Dpkg::Control::Info. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The image package recommended initramfs-tools | dracut | linux-initramfs-tool. Debian's own linux-image packages depend on that same set, and they are right to: the postinst runs the kernel hooks, but the hook that builds the initramfs belongs to the tool, so with none of them installed the install succeeds, runs no such hook, and leaves a kernel with no initrd. On these boards that is not a degraded install, it is one that does not boot. A Recommends is enough only until someone builds an image with --no-install-recommends, which image recipes routinely do. Promote it to Depends and drop the now-empty Recommends field. The alternatives keep the order they had, initramfs-tools first. Debian's forky kernel lists dracut first, but which generator a board should prefer is an image decision and not one to change in passing here. Verified that prepare still generates a control file Dpkg::Control::Info parses, with the alternatives in Depends and no Recommends field left. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Both metapackages depended on their versioned package by name alone:
linux-image-qcom-next on linux-image-<kver>, linux-headers-qcom-next on
linux-headers-<kver>. The name carries the kernel release, so that much is
pinned, but not the Debian version -- an earlier build of the same release,
a different revision or an earlier respin, satisfies the dependency just as
well as the one the metapackage was built beside.
Add (= ${binary:Version}), which is what Debian's linux-image-amd64 does
with its image package and what our own -dbg stanza already does. All the
binaries take the same version from dh_gencontrol -v, so the clause resolves
to the build the metapackage came from.
Verified over the generated control: both metapackages now carry the clause
and the -dbg package is unchanged, all parsing through Dpkg::Control::Info.
Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
Standards-Version said 4.6.2, which is several policy releases behind; lintian reports it as out-of-date. Say 4.7.4, the current release (4.7.4.1 is an editorial revision of it, and the three-component form is the convention). This is a claim of compliance, so it is worth saying what backs it: nothing in the packaging changed for it, and the upgrading checklist between the two was not readable from this machine. The fields policy governs here are the ordinary ones -- a kernel image, its headers, their metapackages -- and lintian over a built package is what will confirm or deny it. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
The source stanza named a Homepage but not where the packaging itself is maintained, so a built package gave no way back to the tree that produced it. The changelog records the kernel repository, ref and commit; this is the other half, the repository this debian/ directory lives in. Vcs-Git carries the .git clone URL and Vcs-Browser the plain one, both over HTTPS -- the same repository the checkout's origin points at, spelled the way a stranger can clone it without an account. Signed-off-by: Christopher Obbard <chris.obbard@oss.qualcomm.com>
26d0b66 to
7a5f892
Compare
|
The linux-base 4.12 pre-depends and the linux-run-hooks calls are the same as what Debian does, and they fix zz-systemd-boot getting skipped now that it lives under /usr/share/kernel/postinst.d on forky and resolute. The metapackage pin and the .build-id links look good too. A few things I noticed. Standards-Version 4.7.4 includes the 4.7.1 rule about not installing into /lib, but the modules still go to /lib/modules. I opened #119 to move them to /usr/lib/modules once #114 is in, since that reworks the bundler anyway, so I'm fine keeping the bump here as long as that's tracked. Related and minor, 4.7.3 says Priority: optional shouldn't be set on the source since it's the default, so that one and the one on the dbg package can just go. Debian's image scripts also run hooks in preinst and prerm, with prerm calling linux-check-removal before the prerm hooks. Here preinst doesn't do anything and there's no prerm template, so prerm.d never runs, including the dkms hook in /etc/kernel/prerm.d. Worth matching that? What's the Provides for the dkms packages meant to cover? I'm guessing it's to stop apt pulling the dkms package and a toolchain onto targets that already have the module. #114 drops it again though, and the per-module packages there also carry the modprobe.d bits the bundled module doesn't have here, so I'm wondering if it needs to be in this one at all. Last small one, build-kernel.sh still lists noble, which can't install these anymore since its linux-base doesn't have linux-run-hooks. |
|
I split the immediatly required changes which fix forky into #121 so we can come back to this PR after. |
Nine packaging changes with no CI dependencies, kept together because they all
concern how the binary packages are assembled and described.
The substantial one generates every maintainer script from a template, so
preinst/postinst/postrmstop drifting from each other, and runs the kernelhooks through
linux-run-hooksrather than open-coding them. Alongside that:module debug files are linked into
.build-idso debuginfod can find them, theimage package depends on an initramfs generator instead of merely recommending
one, the metapackages are pinned to the build they were made from, and
Standards-Versionand theVcs-*fields are brought up to date.No CI or matrix changes. Independent of any other PRs; can be merged immediately.