Since the first version in 81516adcb7,
kernel-install would "gather" a return value by summing the exit codes
of the plugins… This makes no sense, because those are not additive values.
Let's just break off immediately. We now implement cleanup via trap, so if we
break, we should leave no garbage behind.
kernel's 'make install' invokes install.sh which calls /sbin/install-kernel.
Thus we are invoked as e.g.
/sbin/installkernel 5.18.0 arch/x86/boot/bzImage System.map /boot
The last two arguments would be passed as "initrds".
Before , we would just quitely ignore
/boot, because it doesn't pass the 'test -f' test, and possibly try to do
something with System.map. 742561efbe tightened
the check, so we now throw an error.
It seems that the correct thing is to ignore those two arguments, because
our plugin syntax has no notion of System.map. And the installation directory
we can figure out ourselves better. Effectively, this makes things behave
like before, but less by accident.
Fixes#23490.
Before 9e82a74cb0, we had a check like the
following:
if [[ -d /efi/loader/entries ]] || [[ -d /efi/$MACHINE_ID ]]; then
ENTRY_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
elif [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then
ENTRY_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]]; then
ENTRY_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
…
In stock Fedora 34-, /efi isn't used, but grub creates /boot/loader/entries and
installs kernels and initrds directly in /boot. Thus the second arm of the
check wins, and we end up with BOOT_ROOT=/boot.
After 9e82a74cb0, we iterate over the inner
directory first and over the second directory later:
[ -d /efi/<machine-id> ]
[ -d /boot/efi/<machine-id> ]
[ -d /boot/<machine-id> ]
[ -d /efi/Default ]
[ -d /boot/efi/Default ]
[ -d /boot/Default ]
[ -d /efi/loader/entries ]
[ -d /boot/efi/loader/entries ]
[ -d /boot/loader/entries ]
This was partially reverted by 447a822f8e which
removed Default from the list, and a5307e173b,
which moved checks for /boot up, so we ended up with:
[ -d /efi/<machine-id> ]
[ -d /boot/<machine-id> ]
[ -d /boot/efi/<machine-id> ]
[ -d /efi/loader/entries ]
[ -d /boot/loader/entries ]
[ -d /boot/efi/loader/entries ]
6637cf9db6 added autodetection of an entry
token, so we end up checking the following suffixes:
<machine-id>, $IMAGE_ID, $ID, Default
But the important unchanged characteristic is that we iterate over the suffix
first. Sadly this breaks Fedora, because we find /boot/efi/<machine-id> before
we could find /boot/loader/entries. It seems that every possible aspect of
behaviour matters for somebody, so we need to keep the original order of
detection.
With the patch:
[ -d /efi/<machine-id> ]
...
[ -d /efi/loader/entries ]
[ -d /boot/<machine-id> ]
...
[ -d /boot/loader/entries ]
[ -d /boot/efi/<machine-id> ]
...
[ -d /boot/efi/loader/entries ]
Note that we need to check for "loader/entries" too, even though it is not
an entry-token candidate, so that we get the same detection priority as
before.
Fixes https://bugzilla.redhat.com/show_bug.cgi?id=2071034.
If $BOOT_ROOT is specified, but entry-token not, we'd skip the detection
altogether, effectively defaulting to entry-token=machine-id.
The case where $BOOT_ROOT was not specied, but entry-token was configured
was handled correctly.
This patch makes the handling of both symmetrical, i.e. will only set what
wasn't configured.
No changes to behaviour, but let's print everything out as we discover it.
The docs say that BOOT_ROOT can be specified by the environment. I have
it locally in /etc/kernel/install.conf, and then the override doesn't work.
It'd be nice to handle such cases more reliably.
In --help output, change "$0" → "kernel-install". We generally don't include
the full path in --help output, and let's not do this here either.
kernel-install is now in build/ directly, not in the subdirectory.
If not explicitly configured, let's search a bit harder for the
ENTRY_TOKEN, and let's try the machine ID, the IMAGE_ID and ID fields of
/etc/os-release and finally "Default", all below potential $XBOOTLDR.
Now that we can distinguish the naming of the boot loader spec
dirs/files and the machine ID let's tweak the logic for suffixing the
kernel cmdline with systemd.boot_id=: let's only do that when we
actually need the boot ID for naming these dirs/files. If we don't,
let's not bother.
This should be beneficial for "golden" images that shall not carry any
machine IDs at all, i.e acquire their identity only once the final
userspace is actually reached.
This cleans up naming of boot loader spec boot entries a bit (i.e. the
naming of the .conf snippet files, and the directory in $BOOT where the
kernel images and initrds are placed), and isolates it from the actual machine
ID concept.
Previously there was a sinlge concept for both things, because typically
the entries are just named after the machine ID. However one could also
use a different identifier, i.e. not a 128bit ID in which cases issues
pop up everywhere. For example, the "machine-id" field in the generated
snippets would not be a machine ID anymore, and the newly added
systemd.machine_id= kernel parameter would possibly get passed invalid
data.
Hence clean this up:
$MACHINE_ID → always a valid 128bit ID.
$ENTRY_TOKEN → usually the $MACHINE_ID but can be any other string too.
This is used to name the directory to put kernels/initrds in. It's also
used for naming the *.conf snippets that implement the Boot Loader Type
1 spec.
This reworks the how machine ID used by the boot loader spec snippet
generation logic. Instead of persisting it automatically to /etc/ we'll
append it via systemd.machined_id= to the kernel command line, and thus
persist it in the generated boot loader spec snippets instead. This has
nice benefits:
1. We do not collide with read-only root
2. The machine ID remains stable across factory reset, so that we can
safely recognize the path in $BOOT we drop our kernel images in
again, i.e. kernel updates will work correctly and safely across
kernel factory resets.
3. Previously regular systems had different machine IDs while in
initrd and after booting into the host system. With this change
they will now have the same.
This then drops implicit persisting of KERNEL_INSTALL_MACHINE_ID, as its
unnecessary then. The field is still honoured though, for compat
reasons.
This also drops the "Default" fallback previously used, as it actually
is without effect, the randomized ID generation already took precedence
in all cases. This means $MACHNE_ID/KERNEL_INSTALL_MACHINE_ID are now
guaranteed to look like a proper machine ID, which is useful for us,
given you need it that way to be able to pass it to the
systemd.machine_id= kernel command line option.
The general approach of kernel-install was that each plugin would drop in some
files into the entry directory. But this doesn't scale well, because if we have
multiple initrd generators, or multiple initrds, each generator would need to
recreate the logic to put the generated files in the right place.
Also, effective cleanup is impossible if anything goes wrong on the way, so we
could end up with unused files in $BOOT.
So let's invert the process: plugins drop files into $KERNEL_INSTALL_STAGING_AREA,
and at the end 90-loaderentry.install DTRT with those files.
This allow new plugins like 50-mkosi-initrd.install to be significantly simpler.
kernel-install would continue after errors… We don't want this, as it
makes the results totally unpredicatable. If we didn't install the kernel
or didn't do some important part of the setup, let's just return an error
and let the user deal with it.
When looking at output, the error was often hard to distinguish, esp.
with -v. Add "Error:" everywhere to make the output easier to parse.
The idea is that when not set, we do whatever we did in the past. But
with a new setting of initrd_generator=mkosi-initrd, mkosi-initrd will
generate an initrd.
This restores the preference order from before 9e82a74. The code
previous to that change 'preferred' /boot over /boot/efi; that
commit changed it to check /boot/efi before checking /boot.
Changing this precedence could (and did, for me) have unexpected
effects - it seems safer to leave it how it was.
Signed-off-by: Adam Williamson <awilliam@redhat.com>
341890de86 made "bootctl install" create
ESP\MID, in preparation of cf73f65089 that
followed it and created 00-entry-directory.install to make ESP\MID\KVER
if ESP\MID existed ‒ this meant that "bootctl install" followed by
"kernel-install $(uname -r) /boot/vml*$(uname -r) /boot/ini*$(uname -r)"
actually installed the kernel correctly.
Later, 31e57550b5 reverted the first
commit, meaning, that now running those two commands first installs
sd-boot, but then does nothing. Everything appears to work right,
nothing errors out, but no changes are actually done. To the untrained
eye (all of them), even running with -v appears to work:
all the hooks are run, as is depmod, but, again, nothing happens.
This is horrible. Nothing in either manpage suggests what to do
(nor should it, really), but the user is left with a bootloader that
appears fully funxional, since nothing suggests a failure in the output,
but with an unbootable machine, /no way to boot it/, even if they drop
to an EFI shell, since the boot bundle isn't present on the ESP,
and no real recourse even if they boot into a recovery system,
apart from installing like GRUB or whatever.
00- is purely instrumentation for 90-,
and separating one from the other has led to downstream dissatisfaxion
(indeed, the last mentioned commit cited cited exactly that as the
reversion reason), while creating $ENTRY_DIR_ABS is only required
for bootloaders using the BLS, and shouldn't itself toggle anything.
To that end, introduce an /{e,l}/k/install.conf file that allows
overriding the detected layout, and detect it as "bls" if
$BOOT_ROOT/$MACHINE_ID ($ENTRY_DIR_ABS/..) exists, otherwise "other" ‒
if a user wishes to select a different bootloader,
like GRUB, they (or, indeed, the postinst script) can specify
layout=grub. This disables 90- and $ENTRY_DIR_ABS manipulation.
If KERNEL_INSTALL_MACHINE_ID is defined in /etc/machine-info, prefer it
over the machine ID from /etc/machine-id. If a machine ID is defined in
neither /etc/machine-info nor in /etc/machine-id, generate a new UUID
and try to write it to /etc/machine-info as KERNEL_INSTALL_MACHINE_ID
and use it as the machine ID if writing it to /etc/machine-info succeeds.
In practice, this means we have a more robust fallback if there's no
machine ID in /etc/machine-id than just using "Default" and allows
image builders to force kernel-install to use KERNEL_INSTALL_MACHINE_ID
by simply writing it to /etc/machine-info themselves.
This was an undocumented change in behavior introduced by
9e82a74cb0. Previously, we only
checked for "Default" if we didn't find a machine ID. Let's make
sure we keep the previous behavior intact.
The previous approach, to strip "$MACHINE_ID/$KERNEL_VERSION" from the
end, is pretty bad and encourages this for users, which makes them
inflexible to this being modified locally
Confer https://github.com/systemd/systemd/pull/19006#issuecomment-800234022:
On some systems it's the admin's explicit choice not to to have the
machine ID leak into the ESP
On some systems the machine ID is transient, generated at every boot,
and hence should not be written to the ESP
The manpage says that exiting 77 is the same as exiting 0,
then skipping all other hooks, but the behaviour heretofor
was to exit 0, skip all, and behave as if all hooks exited 0
This reverts commit 5ffa2eaa54.
It seems that if install_dir is not specified, meson decides install path
based on file type, and non-executable binary files are installed under
/usr/share.
kernel-install is a script. So, we need to set install_dir argument
explicitly.
Fixes#18754.