mirror of
https://github.com/systemd/systemd.git
synced 2025-01-25 10:04:04 +03:00
Merge pull request #23504 from keszybz/bls-reordering
Refactor the BLS and add a description of version sorts
This commit is contained in:
commit
e1a8917ae1
35
NEWS
35
NEWS
@ -29,19 +29,19 @@ CHANGES WITH 251:
|
|||||||
and backward compatibility broken instead on the assumption that
|
and backward compatibility broken instead on the assumption that
|
||||||
nobody can be affected given the current state of this interface.
|
nobody can be affected given the current state of this interface.
|
||||||
|
|
||||||
* All kernels supported by systemd mix RDRAND (or similar) into the
|
* All kernels supported by systemd mix bytes returned by RDRAND (or
|
||||||
entropy pool at early boot. This means that on those systems, even if
|
similar) into the entropy pool at early boot. This means that on
|
||||||
/dev/urandom is not yet initialized, it still returns bytes that
|
those systems, even if /dev/urandom is not yet initialized, it still
|
||||||
are at least as high quality as RDRAND. For that reason, we no longer
|
returns bytes that are of at least RDRAND quality. For that reason,
|
||||||
have reason to invoke RDRAND from systemd itself, which has
|
we no longer have reason to invoke RDRAND from systemd itself, which
|
||||||
historically been a source of bugs. Furthermore, kernels ≥5.6 provide
|
has historically been a source of bugs. Furthermore, kernels ≥5.6
|
||||||
the getrandom(GRND_INSECURE) interface for returning random bytes
|
provide the getrandom(GRND_INSECURE) interface for returning random
|
||||||
before the entropy pool is initialized without warning into kmsg,
|
bytes before the entropy pool is initialized without warning into
|
||||||
which is what we attempt to use if available. systemd's direct usage
|
kmsg, which is what we attempt to use if available. systemd's direct
|
||||||
of RDRAND has been removed. x86 systems ≥Broadwell that are running
|
usage of RDRAND has been removed. x86 systems ≥Broadwell that are
|
||||||
an older kernel may experience kmsg warnings that were not seen with
|
running an older kernel may experience kmsg warnings that were not
|
||||||
250. For newer kernels, non-x86 systems, or older x86 systems, there
|
seen with 250. For newer kernels, non-x86 systems, or older x86
|
||||||
should be no visible changes.
|
systems, there should be no visible changes.
|
||||||
|
|
||||||
* sd-boot will now measure the kernel command line into TPM PCR 12
|
* sd-boot will now measure the kernel command line into TPM PCR 12
|
||||||
rather than PCR 8. This improves usefulness of the measurements on
|
rather than PCR 8. This improves usefulness of the measurements on
|
||||||
@ -59,11 +59,10 @@ CHANGES WITH 251:
|
|||||||
* busctl capture now writes output in the newer pcapng format instead
|
* busctl capture now writes output in the newer pcapng format instead
|
||||||
of pcap.
|
of pcap.
|
||||||
|
|
||||||
* A udev rule that imported hwdb matches for USB devices with
|
* A udev rule that imported hwdb matches for USB devices with lowercase
|
||||||
lowercase hexadecimal vendor/product ID digits was added in systemd
|
hexadecimal vendor/product ID digits was added in systemd 250. This
|
||||||
250. This has been reverted, since uppercase hexadecimal digits are
|
has been reverted, since uppercase hexadecimal digits are supposed to
|
||||||
supposed to be used, and we already had a rule for that with the
|
be used, and we already had a rule with the appropriate match.
|
||||||
appropriate match.
|
|
||||||
|
|
||||||
Users might need to adjust their local hwdb entries.
|
Users might need to adjust their local hwdb entries.
|
||||||
|
|
||||||
|
@ -7,142 +7,93 @@ SPDX-License-Identifier: LGPL-2.1-or-later
|
|||||||
|
|
||||||
# The Boot Loader Specification
|
# The Boot Loader Specification
|
||||||
|
|
||||||
_TL;DR: Currently there's no common boot scheme across architectures and
|
This document defines a set of file formats and naming conventions that allow
|
||||||
platforms for open-source operating systems. There's also little cooperation
|
the boot loader configuration to be shared between multiple operating systems
|
||||||
between multiple distributions in dual-boot (or triple, … multi-boot)
|
and boot loaders installed on one device.
|
||||||
setups. We'd like to improve this situation by getting everybody to commit to a
|
|
||||||
single boot configuration format that is based on drop-in files, and thus is
|
|
||||||
robust, simple, works without rewriting configuration files and is free of
|
|
||||||
namespace clashes._
|
|
||||||
|
|
||||||
The Boot Loader Specification defines a scheme how different operating systems
|
Operating systems cooperatively manage a boot loader configuration directory
|
||||||
can cooperatively manage a boot loader configuration directory, that accepts
|
that contains drop-in files, making multi-boot scenarios easy to support. Boot
|
||||||
drop-in files for boot menu items that are defined in a format that is shared
|
menu items are defined via a simple format that can be understood by different
|
||||||
between various boot loader implementations, operating systems, and userspace
|
boot loader implementations, operating systems, and userspace programs. The
|
||||||
programs. The same scheme can be used to prepare OS media for cases where the
|
same scheme can be used to prepare OS media for cases where the firmware
|
||||||
firmware includes a boot loader. The target audience for this specification is:
|
includes a boot loader.
|
||||||
|
|
||||||
|
## Target audience
|
||||||
|
|
||||||
|
The target audience for this specification is:
|
||||||
|
|
||||||
* Boot loader developers, to write a boot loader that directly reads its
|
* Boot loader developers, to write a boot loader that directly reads its
|
||||||
configuration at runtime from these drop-in snippets
|
configuration from these files
|
||||||
* Firmware developers, to add generic boot loading support directly to the
|
* Firmware developers, to add generic boot loading support directly to the
|
||||||
firmware itself
|
firmware itself
|
||||||
* Distribution and Core OS developers, in order to create these snippets at
|
* OS installer developers, to create appropriate partitions and set up the
|
||||||
OS/kernel package installation time
|
initial boot loader configuration
|
||||||
* UI developers, for implementing a user interface that discovers the available
|
* Distribution developers, to create appropriate configuration snippets when
|
||||||
boot options
|
installing or updating kernel packages
|
||||||
* OS Installer developers, to prepare their installation media and for setting
|
* UI developers, to implement user interfaces that list and select among the
|
||||||
up the initial drop-in directory
|
available boot options
|
||||||
|
|
||||||
## Why is there a need for this specification?
|
## The boot partition
|
||||||
|
|
||||||
Of course, without this specification things already work mostly fine. But here's why we think this specification is needed:
|
Everything described below is located on one or two partitions. The boot loader
|
||||||
|
or user-space programs reading the boot loader configuration should locate them
|
||||||
* To make the boot more robust, as no explicit rewriting of configuration files
|
in the following manner:
|
||||||
is required any more
|
|
||||||
* To allow an out of the box boot experience on any platform without the need
|
|
||||||
of traditional firmware mechanisms (e.g. BIOS calls, UEFI Boot Services)
|
|
||||||
* To improve dual-boot scenarios. Currently, multiple Linux installations tend
|
|
||||||
to fight over which boot loader becomes the primary one in possession of the
|
|
||||||
MBR, and only that one installation can then update the boot loader
|
|
||||||
configuration of it freely. Other Linux installs have to be manually
|
|
||||||
configured to never touch the MBR and instead install a chain-loaded boot
|
|
||||||
loader in their own partition headers. In this new scheme as all
|
|
||||||
installations share a loader directory no manual configuration has to take
|
|
||||||
place, and all participants implicitly cooperate due to removal of name
|
|
||||||
collisions and can install/remove their own boot menu entries at free will,
|
|
||||||
without interfering with the entries of other installed operating systems.
|
|
||||||
* Drop-in directories are otherwise now pretty ubiquitous on Linux as an easy
|
|
||||||
way to extend configuration without having to edit, regenerate or manipulate
|
|
||||||
configuration files. For the sake of uniformity, we should do the same for
|
|
||||||
extending the boot menu.
|
|
||||||
* Userspace code can sanely parse boot loader configuration which is essential
|
|
||||||
with modern BIOSes which do not necessarily initialize USB keyboards anymore
|
|
||||||
during boot, which makes boot menus hard to reach for the user. If userspace
|
|
||||||
code can parse the boot loader configuration, too, this allows for UIs that
|
|
||||||
can select a boot menu item to boot into, before rebooting the machine, thus
|
|
||||||
not requiring interactivity during early boot.
|
|
||||||
* To unify and thus simplify configuration of the various boot loaders around,
|
|
||||||
which makes configuration of the boot loading process easier for users,
|
|
||||||
administrators and developers alike.
|
|
||||||
* For boot loaders with configuration _scripts_ such as grub2, adopting this
|
|
||||||
spec allows for mostly static scripts that are generated only once at first
|
|
||||||
installation, but then do not need to be updated anymore as that is done via
|
|
||||||
drop-in files exclusively.
|
|
||||||
|
|
||||||
## Why not simply rely on the EFI boot menu logic?
|
|
||||||
|
|
||||||
EFI is not ubiquitous, especially not in embedded systems. If you have an EFI
|
|
||||||
system, it provides a boot options logic that can offer similar
|
|
||||||
functionality. Here's why we think that it is not enough for our uses:
|
|
||||||
|
|
||||||
* The various EFI implementations implement the boot order/boot item logic to
|
|
||||||
different levels. Some firmware implementations do not offer a boot menu at
|
|
||||||
all and instead unconditionally follow the EFI boot order, booting the first
|
|
||||||
item that is working.
|
|
||||||
* If the firmware setup is used to reset all data usually all EFI boot entries
|
|
||||||
are lost, making the system entirely unbootable, as the firmware setups
|
|
||||||
generally do not offer a UI to define additional boot items. By placing the
|
|
||||||
menu item information on disk, it is always available, regardless if the BIOS
|
|
||||||
setup data is lost.
|
|
||||||
* Harddisk images should be movable between machines and be bootable without
|
|
||||||
requiring explicit EFI variables to be set. This also requires that the list
|
|
||||||
of boot options is defined on disk, and not in EFI variables alone.
|
|
||||||
* EFI is not universal yet (especially on non-x86 platforms), this
|
|
||||||
specification is useful both for EFI and non-EFI boot loaders.
|
|
||||||
* Many EFI systems disable USB support during early boot to optimize boot
|
|
||||||
times, thus making keyboard input unavailable in the EFI menu. It is thus
|
|
||||||
useful if the OS UI has a standardized way to discover available boot options
|
|
||||||
which can be booted to.
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
Everything described below is located on a placeholder file system `$BOOT`. The
|
|
||||||
installer program should pick `$BOOT` according to the following rules:
|
|
||||||
|
|
||||||
* On disks with an MBR partition table:
|
* On disks with an MBR partition table:
|
||||||
* If the OS is installed on a disk with an MBR partition table, and a
|
|
||||||
partition with the type id of 0xEA already exists it should be used as
|
* The boot partition — partition with the type ID of 0xEA — shall be used
|
||||||
`$BOOT`.
|
for boot loader configuration and entries.
|
||||||
* Otherwise, if the OS is installed on a disk with an MBR partition table, a
|
|
||||||
new partition with type id of 0xEA shall be created, of a suitable size
|
|
||||||
(let's say 500MB), and it should be used as `$BOOT`.
|
|
||||||
* On disks with GPT (GUID Partition Table)
|
* On disks with GPT (GUID Partition Table)
|
||||||
* If the OS is installed on a disk with GPT, and an Extended Boot Loader
|
|
||||||
Partition (or XBOOTLDR partition for short), i.e. a partition with GPT type
|
|
||||||
GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172`, already exists, it should
|
|
||||||
be used as `$BOOT`.
|
|
||||||
* Otherwise, if the OS is installed on a disk with GPT, and an EFI System
|
|
||||||
Partition (or ESP for short), i.e. a partition with GPT type UID of
|
|
||||||
`c12a7328-f81f-11d2-ba4b-00a0c93ec93b` already exists and is large enough
|
|
||||||
(let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`.
|
|
||||||
* Otherwise, if the OS is installed on a disk with GPT, and if the ESP
|
|
||||||
already exists but is too small, a new suitably sized (let's say 500MB)
|
|
||||||
XBOOTLDR partition shall be created and used as `$BOOT`.
|
|
||||||
* Otherwise, if the OS is installed on a disk with GPT, and no ESP exists
|
|
||||||
yet, a new suitably sized (let's say 500MB) ESP should be created and used
|
|
||||||
as `$BOOT`.
|
|
||||||
|
|
||||||
This placeholder file system shall be determined during _installation time_,
|
* The EFI System Partition (ESP for short) — a partition with GPT type GUID
|
||||||
and an fstab entry may be created. It should be mounted to either `/boot/` or
|
of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b` — should be used for boot loader
|
||||||
`/efi/`. Additional locations like `/boot/efi/` (with `/boot/` being a separate
|
configuration and boot entries.
|
||||||
file system) might be supported by implementations. This is not recommended
|
|
||||||
because the mounting of `$BOOT` is then dependent on and requires the mounting
|
|
||||||
of the intermediate file system.
|
|
||||||
|
|
||||||
**Note:** _`$BOOT` should be considered **shared** among all OS installations
|
* Optionally, an Extended Boot Loader Partition (XBOOTLDR partition for
|
||||||
of a system. Instead of maintaining one `$BOOT` per installed OS (as `/boot/`
|
short) — a partition with GPT type GUID of
|
||||||
was traditionally handled), all installed OS share the same place to drop in
|
`bc13c2ff-59e6-4262-a352-b275fd6f7172` — may be used as an additional
|
||||||
their boot-time configuration._
|
location for boot loader entries. This partition must be located on the
|
||||||
|
same disk as the ESP.
|
||||||
|
|
||||||
For systems where the firmware is able to read file systems directly, `$BOOT`
|
In the text below, `$BOOT` will be used to refer to (the root of) the first of
|
||||||
must be a file system readable by the firmware. For other systems and generic
|
the two partitions (the boot partition on MBR disks and the ESP on GPT disks),
|
||||||
installation and live media, `$BOOT` must be a VFAT (16 or 32) file
|
and `$XBOOTLDR` will be used to refer to (the root of) the optional second
|
||||||
system. Applications accessing `$BOOT` should hence not assume that fancier
|
partition.
|
||||||
file system features such as symlinks, hardlinks, access control or case
|
|
||||||
sensitivity are supported.
|
An installer for the operating system should use this logic when selecting or
|
||||||
|
creating partitions:
|
||||||
|
|
||||||
|
* If `$BOOT` is not found, a new suitably sized partition (let's say 500MB)
|
||||||
|
should be created, matching the characteristics described above. On disks
|
||||||
|
with GPT, only the ESP partition without the XBOOTLDR partition should be
|
||||||
|
created.
|
||||||
|
|
||||||
|
* If the OS is installed on a disk with GPT and the ESP partition is found
|
||||||
|
but is too small, a new suitably sized (let's say 500MB) XBOOTLDR partition
|
||||||
|
shall be created.
|
||||||
|
|
||||||
|
Those file systems shall be determined during _installation time_, and an fstab
|
||||||
|
entry may be created. If only one partition is used, it should be mounted on
|
||||||
|
`/boot/`. If both XBOOTLDR partition and the ESP are used, they should be
|
||||||
|
mounted on `/boot` and `/efi`, or on `/boot` and `/boot/efi`.
|
||||||
|
|
||||||
|
**Note:** _Those file systems are **shared** among all OS installations on the
|
||||||
|
system. Instead of maintaining one boot partition per installed OS (as `/boot/`
|
||||||
|
was traditionally handled), all installed OSes use the same place for boot-time
|
||||||
|
configuration._
|
||||||
|
|
||||||
|
For systems where the firmware is able to read file systems directly, the ESP
|
||||||
|
must — and the XBOOTLDR partition should — be a file system readable by the
|
||||||
|
firmware. For most systems this means VFAT (16 or 32 bit). Applications
|
||||||
|
accessing both partitions should hence not assume that fancier file system
|
||||||
|
features such as symlinks, hardlinks, access control or case sensitivity are
|
||||||
|
supported.
|
||||||
|
|
||||||
|
## Boot loader entries
|
||||||
|
|
||||||
This specification defines two types of boot loader entries. The first type is
|
This specification defines two types of boot loader entries. The first type is
|
||||||
text based, very simple and suitable for a variety of firmware, architecture
|
text based, very simple, and suitable for a variety of firmware, architecture
|
||||||
and image types ("Type #1"). The second type is specific to EFI, but allows
|
and image types ("Type #1"). The second type is specific to EFI, but allows
|
||||||
single-file images that embed all metadata in the kernel binary itself, which
|
single-file images that embed all metadata in the kernel binary itself, which
|
||||||
is useful to cryptographically sign them as one file for the purpose of
|
is useful to cryptographically sign them as one file for the purpose of
|
||||||
@ -157,132 +108,151 @@ from the user. Only entries matching the feature set of boot loader and system
|
|||||||
shall be considered and displayed. This allows image builders to put together
|
shall be considered and displayed. This allows image builders to put together
|
||||||
images that transparently support multiple different architectures.
|
images that transparently support multiple different architectures.
|
||||||
|
|
||||||
Note that the `$BOOT` partition is not supposed to be exclusive territory of
|
Note that the boot partitions are not supposed to be the exclusive territory of
|
||||||
this specification. This specification only defines semantics of the `/loader/`
|
this specification. This specification only defines semantics of the `/loader/`
|
||||||
directory inside the file system (see below), but it doesn't intend to define
|
directory inside the file system (see below), but it doesn't intend to define
|
||||||
ownership of the whole file system exclusively. Boot loaders, firmware, and
|
ownership of the whole file system. Boot loaders, firmware, and other software
|
||||||
other software implementing this specification may choose to place other
|
implementing this specification may choose to place other files and directories
|
||||||
files and directories in the same file system. For example, boot loaders that
|
in the same file system. For example, boot loaders that implement this
|
||||||
implement this specification might install their own boot code into the `$BOOT`
|
specification might install their own boot code on the same partition; this is
|
||||||
partition. On systems where `$BOOT` is the ESP this is a particularly common
|
particularly common in the case of the ESP. Implementations of this specification
|
||||||
setup. Implementations of this specification must be able to operate correctly
|
must be able to operate correctly if files or directories other than `/loader/`
|
||||||
if files or directories other than `/loader/` are found in the top level
|
are found in the top level directory. Implementations that add their own files
|
||||||
directory. Implementations that add their own files or directories to the file
|
or directories to the file systems should use well-named directories, to make
|
||||||
systems should use well-named directories, to make name collisions between
|
name collisions between multiple users of the file system unlikely.
|
||||||
multiple users of the file system unlikely.
|
|
||||||
|
|
||||||
### Type #1 Boot Loader Specification Entries
|
### Type #1 Boot Loader Specification Entries
|
||||||
|
|
||||||
We define two directories below `$BOOT`:
|
`$ESP/loader/` is the main directory containing the configuration for the boot
|
||||||
|
loader.
|
||||||
* `$BOOT/loader/` is the directory containing all files needed for Type #1
|
|
||||||
entries
|
|
||||||
|
|
||||||
* `$BOOT/loader/entries/` is the directory containing the drop-in
|
|
||||||
snippets. This directory contains one `.conf` file for each boot menu item.
|
|
||||||
|
|
||||||
**Note:** _In all cases the `/loader/` directory should be located directly in
|
**Note:** _In all cases the `/loader/` directory should be located directly in
|
||||||
the root of the file system. Specifically, if `$BOOT` is the ESP, then
|
the root of the file system. Specifically, the `/loader/` directory should
|
||||||
`/loader/` directory should be located directly in the root directory of the
|
**not** be located under the `/EFI/` subdirectory on the ESP._
|
||||||
ESP, and not in the `/EFI/` subdirectory._
|
|
||||||
|
|
||||||
Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or
|
`$BOOT/loader/entries/` and `$XBOOTLDR/loader/entries/` are the directories
|
||||||
more configuration snippets with the suffix ".conf", one for each boot menu
|
containing the drop-in snippets defining boot entries, one `.conf` file for
|
||||||
item. The file name of the file is used for identification of the boot item but
|
each boot menu item. Each OS may provide one or more such entries. The boot
|
||||||
shall never be presented to the user in the UI. The file name may be chosen
|
loader should enumerate both directories and provide a merged list.
|
||||||
freely but should be unique enough to avoid clashes between OS
|
|
||||||
installations. More specifically it is suggested to include the machine ID
|
The file name is used for identification of the boot item but shall never be
|
||||||
(`/etc/machine-id` or the D-Bus machine ID for OSes that lack
|
presented to the user in the UI. The file name may be chosen freely but should
|
||||||
`/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS
|
be unique enough to avoid clashes between OS installations. More specifically,
|
||||||
identifier (The ID field of `/etc/os-release`). Example:
|
it is suggested to include the `entry-token` (see
|
||||||
`$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
|
[kernel-install](https://www.freedesktop.org/software/systemd/man/kernel-install.html))
|
||||||
|
or machine ID (see
|
||||||
|
[/etc/machine-id](https://www.freedesktop.org/software/systemd/man/machine-id.html)),
|
||||||
|
and the kernel version (as returned by `uname -r`, including the OS
|
||||||
|
identifier), so that the whole filename is
|
||||||
|
`$BOOT/loader/entries/<entry-token-or-machine-id>-<version>.conf`.
|
||||||
|
|
||||||
|
Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
|
||||||
|
|
||||||
In order to maximize compatibility with file system implementations and
|
In order to maximize compatibility with file system implementations and
|
||||||
restricted boot loader environments, and to minimize conflicting character use
|
restricted boot loader environments, and to minimize conflicting character use
|
||||||
with other programs, file names shall be chosen from a restricted character
|
with other programs, file names shall be chosen from a restricted character
|
||||||
set: ASCII upper and lower case characters, digits, "+", "-", "_" and
|
set: ASCII upper and lower case characters, digits, "+", "-", "_" and ".".
|
||||||
".". Also, the file names should have a length of at least one and at most 255
|
Also, the file names should have a length of at least one and at most 255
|
||||||
characters (including file name suffix).
|
characters (including the file name suffix).
|
||||||
|
|
||||||
These configuration snippets shall be Unix-style text files (i.e. line
|
These configuration snippets shall be UNIX-style text files (i.e. lines
|
||||||
separation with a single newline character), in the UTF-8 encoding. The
|
separated by a single newline character), in the UTF-8 encoding. The
|
||||||
configuration snippets are loosely inspired on Grub1's configuration
|
configuration snippets are loosely inspired by Grub1's configuration syntax.
|
||||||
syntax. Lines beginning with '#' shall be ignored and used for commenting. The
|
Lines beginning with "#" are used for comments and shall be ignored. The first
|
||||||
first word of a line is used as key and shall be separated by one or more
|
word of a line is used as key and is separated by one or more spaces from the
|
||||||
spaces from its value. The following keys are known:
|
value.
|
||||||
|
|
||||||
|
#### Type #1 Boot Loader Entry Keys
|
||||||
|
|
||||||
|
The following keys are recognized:
|
||||||
|
|
||||||
|
* `title` is a human-readable title for this menu item to be displayed in the
|
||||||
|
boot menu. It is a good idea to initialize this from the `PRETTY_NAME=` of
|
||||||
|
[os-release](https://www.freedesktop.org/software/systemd/man/os-release.html).
|
||||||
|
This name should be descriptive and does not have to be unique. If a boot
|
||||||
|
loader discovers two entries with the same title it should show more than
|
||||||
|
just the raw title in the UI, for example by appending the `version`
|
||||||
|
field. This field is optional.
|
||||||
|
|
||||||
|
Example: `title Fedora 18 (Spherical Cow)`
|
||||||
|
|
||||||
|
* `version` is a human-readable version for this menu item. This is usually the
|
||||||
|
kernel version and is intended for use by OSes to install multiple kernel
|
||||||
|
versions with the same `title` field. This field is used for sorting entries,
|
||||||
|
so that the boot loader can order entries by age or select the newest one
|
||||||
|
automatically. This field is optional.
|
||||||
|
|
||||||
|
See [Sorting](#sorting) below.
|
||||||
|
|
||||||
|
Example: `version 3.7.2-201.fc18.x86_64`
|
||||||
|
|
||||||
|
* `machine-id` is the machine ID of the OS. This can be used by boot loaders
|
||||||
|
and applications to filter out boot entries, for example to show only a
|
||||||
|
single newest kernel per OS, to group items by OS, or to filter out the
|
||||||
|
currently booted OS when showing only other installed operating systems.
|
||||||
|
This ID shall be formatted as 32 lower case hexadecimal characters
|
||||||
|
(i.e. without any UUID formatting). This key is optional.
|
||||||
|
|
||||||
|
Example: `machine-id 4098b3f648d74c13b1f04ccfba7798e8`
|
||||||
|
|
||||||
|
* `sort-key` is a short string used for sorting entries on display. This should
|
||||||
|
typically be initialized from the `IMAGE_ID=` or `ID=` fields of
|
||||||
|
[os-release](https://www.freedesktop.org/software/systemd/man/os-release.html),
|
||||||
|
possibly with an additional suffix. This field is optional.
|
||||||
|
|
||||||
|
Example: `sort-key fedora`
|
||||||
|
|
||||||
|
* `linux` is the Linux kernel to spawn and as a path relative to file system
|
||||||
|
root. It is recommended that every distribution creates a machine id and
|
||||||
|
version specific subdirectory and places its kernels and initial RAM disk
|
||||||
|
images there.
|
||||||
|
|
||||||
|
Example: `linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux`
|
||||||
|
|
||||||
|
* `initrd` is the initrd to use when executing the kernel. This key is
|
||||||
|
optional. This key may appear more than once in which case all specified
|
||||||
|
images are used, in the order they are listed.
|
||||||
|
|
||||||
|
Example: `initrd 6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd`
|
||||||
|
|
||||||
|
* `efi` refers to an arbitrary EFI program. If this key is set, and the system
|
||||||
|
is not an EFI system, this entry should be hidden.
|
||||||
|
|
||||||
* `title` shall contain a human readable title string for this menu item. This
|
|
||||||
will be displayed in the boot menu for the item. It is a good idea to
|
|
||||||
initialize this from the `PRETTY_NAME` of `/etc/os-release`. This name should
|
|
||||||
be descriptive and does not have to be unique. If a boot loader discovers two
|
|
||||||
entries with the same title it is a good idea to show more than just the raw
|
|
||||||
title in the UI, for example by appending the `version` field. This field is
|
|
||||||
optional. Example: "Fedora 18 (Spherical Cow)".
|
|
||||||
* `version` shall contain a human readable version string for this menu
|
|
||||||
item. This is usually the kernel version and is intended for use by OSes to
|
|
||||||
install multiple kernel versions at the same time with the same `title`
|
|
||||||
field. This field shall be in a syntax that is useful for Debian-style
|
|
||||||
version sorts, so that the boot loader UI can determine the newest version
|
|
||||||
easily and show it first or preselect it automatically. This field is
|
|
||||||
optional. Example: `3.7.2-201.fc18.x86_64`.
|
|
||||||
* `machine-id` shall contain the machine ID of the OS `/etc/machine-id`. This
|
|
||||||
is useful for boot loaders and applications to filter out boot entries, for
|
|
||||||
example to show only a single newest kernel per OS, or to group items by OS,
|
|
||||||
or to maybe filter out the currently booted OS in UIs that want to show only
|
|
||||||
other installed operating systems. This ID shall be formatted as 32 lower
|
|
||||||
case hexadecimal characters (i.e. without any UUID formatting). This key is
|
|
||||||
optional. Example: `4098b3f648d74c13b1f04ccfba7798e8`.
|
|
||||||
* `sort-key` shall contain a short string used for sorting entries on
|
|
||||||
display. This can be defined freely though should typically be initialized
|
|
||||||
from `IMAGE_ID=` or `ID=` from `/etc/os-release` of the relevant entry,
|
|
||||||
possibly suffixed. This field is optional. If set, it is used as primary
|
|
||||||
sorting key for the entries on display (lexicographically increasing). It
|
|
||||||
does not have to be unique (and usually is not). If non-unique the the
|
|
||||||
`machine-id` (lexicographically increasing) and `version` (lexicographically
|
|
||||||
decreasing, i.e. newest version first) fields described above are used as
|
|
||||||
secondary/ternary sorting keys. If this field is not set entries are
|
|
||||||
typically sorted by the `.conf` file name of the entry.
|
|
||||||
* `linux` refers to the Linux kernel to spawn and shall be a path relative to
|
|
||||||
`$BOOT`. It is recommended that every distribution creates a machine id and
|
|
||||||
version specific subdirectory below `$BOOT` and places its kernels and
|
|
||||||
initial RAM disk images there. Example:
|
|
||||||
`/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux`.
|
|
||||||
* `initrd` refers to the initrd to use when executing the kernel. This also
|
|
||||||
shall be a path relative to `$BOOT`. This key is optional. This key may
|
|
||||||
appear more than once in which case all specified images are used, in the
|
|
||||||
order they are listed. Example:
|
|
||||||
`6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd`.
|
|
||||||
* `efi` refers to an arbitrary EFI program. This also takes a path relative to
|
|
||||||
`$BOOT`. If this key is set, and the system is not an EFI system this entry
|
|
||||||
should be hidden.
|
|
||||||
* `options` shall contain kernel parameters to pass to the Linux kernel to
|
* `options` shall contain kernel parameters to pass to the Linux kernel to
|
||||||
spawn. This key is optional and may appear more than once in which case all
|
spawn. This key is optional and may appear more than once in which case all
|
||||||
specified parameters are used in the order they are listed.
|
specified parameters are used in the order they are listed.
|
||||||
|
|
||||||
|
Example: `options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet`
|
||||||
|
|
||||||
* `devicetree` refers to the binary device tree to use when executing the
|
* `devicetree` refers to the binary device tree to use when executing the
|
||||||
kernel. This also shall be a path relative to `$BOOT`. This key is
|
kernel. This key is optional.
|
||||||
optional. Example:
|
|
||||||
`6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb`.
|
Example: `devicetree 6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb`
|
||||||
|
|
||||||
* `devicetree-overlay` refers to a list of device tree overlays that should be
|
* `devicetree-overlay` refers to a list of device tree overlays that should be
|
||||||
applied by the boot loader. Multiple overlays are separated by spaces and
|
applied by the boot loader. Multiple overlays are separated by spaces and
|
||||||
applied in the same order as they are listed. This key is optional but
|
applied in the same order as they are listed. This key is optional but
|
||||||
depends on the `devicetree` key. Example:
|
depends on the `devicetree` key.
|
||||||
`/6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_A.dtbo
|
|
||||||
/6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_B.dtbo`
|
Example: `devicetree-overlay /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_A.dtbo /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_B.dtbo`
|
||||||
* `architecture` refers to the architecture this entry is defined for. The
|
|
||||||
argument should be an architecture identifier, using the architecture
|
* `architecture` refers to the architecture this entry is for. The argument
|
||||||
vocabulary defined by the EFI specification (i.e. `IA32`, `x64`, `IA64`,
|
should be an architecture identifier, using the architecture vocabulary
|
||||||
`ARM`, `AA64`, …). If specified and this does not match (case insensitively)
|
defined by the EFI specification (i.e. `IA32`, `x64`, `IA64`, `ARM`, `AA64`,
|
||||||
the local system architecture this entry should be hidden.
|
…). If specified and it does not match the local system architecture this
|
||||||
|
entry should be hidden. The comparison should be done case-insensitively.
|
||||||
|
|
||||||
|
Example: `architecture aa64`
|
||||||
|
|
||||||
Each configuration drop-in snippet must include at least a `linux` or an `efi`
|
Each configuration drop-in snippet must include at least a `linux` or an `efi`
|
||||||
key and is otherwise not valid. Here's an example for a complete drop-in file:
|
key. Here is an example for a complete drop-in file:
|
||||||
|
|
||||||
# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf
|
# /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf
|
||||||
title Fedora 19 (Rawhide)
|
title Fedora 19 (Rawhide)
|
||||||
sort-key fedora
|
sort-key fedora
|
||||||
machine-id 6a9857a393724b7a981ebb5b8495b9ea
|
machine-id 6a9857a393724b7a981ebb5b8495b9ea
|
||||||
version 3.8.0-2.fc19.x86_64
|
version 3.8.0-2.fc19.x86_64
|
||||||
options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2
|
options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet
|
||||||
architecture x64
|
architecture x64
|
||||||
linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux
|
linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux
|
||||||
initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd
|
initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd
|
||||||
@ -298,28 +268,40 @@ i.e. it is a good idea that both images shipped as UEFI PE images and those
|
|||||||
which are not don't make unnecessary assumption on the underlying firmware,
|
which are not don't make unnecessary assumption on the underlying firmware,
|
||||||
i.e. don't hard depend on legacy BIOS calls or UEFI boot services.
|
i.e. don't hard depend on legacy BIOS calls or UEFI boot services.
|
||||||
|
|
||||||
Note that these configuration snippets may only reference kernels (and EFI
|
When Type #1 configuration snippets refer to other files (for `linux`,
|
||||||
programs) that reside on the same file system as the configuration snippets,
|
`initrd`, `efi`, `devicetree`, and `devicetree-overlay`), those files must be
|
||||||
i.e. everything referenced must be contained in the same file system. This is
|
located on the same partition, and the paths must be absolute paths relative to
|
||||||
by design, as referencing other partitions or devices would require a
|
the root of that file system. The naming of those files can be chosen by the
|
||||||
non-trivial language for denoting device paths. If kernels/initrds are to be
|
installer. A recommended scheme is described in the next section.
|
||||||
read from other partitions/disks the boot loader can do this in its own native
|
|
||||||
configuration, using its own specific device path language, and this is out of
|
### Recommended Directory Layout for Additional Files
|
||||||
focus for this specification. More specifically, on non-EFI systems
|
|
||||||
configuration snippets following this specification cannot be used to spawn
|
It is recommened to place the kernel and other other files comprising a single
|
||||||
other operating systems (such as Windows).
|
boot loader entry in a separate directory:
|
||||||
|
`/<entry-token-or-machine-id>/<version>/`. This naming scheme uses the same
|
||||||
|
elements as the boot loader configuration snippet, providing the same level of
|
||||||
|
uniqueness.
|
||||||
|
|
||||||
|
Example: `$BOOT/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux`
|
||||||
|
`$BOOT/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd`
|
||||||
|
|
||||||
|
Other naming schemes are possible. In particular, traditionally a flat naming
|
||||||
|
scheme with files in the root directory was used. This is not recommended
|
||||||
|
because it is hard to avoid conflicts in a multi-boot installation.
|
||||||
|
|
||||||
|
### Standard-conformance Marker File
|
||||||
|
|
||||||
Unfortunately, there are implementations of boot loading infrastructure that
|
Unfortunately, there are implementations of boot loading infrastructure that
|
||||||
are also using the /loader/entries/ directory, but place files in them that are
|
are also using the `/loader/entries/` directory, but installing files that do
|
||||||
not valid by this specification. In order to minimize confusion a boot loader
|
not follow this specification. In order to minimize confusion, a boot loader
|
||||||
implementation may place a file /loader/entries.srel next to the
|
implementation may place the file `/loader/entries.srel` next to the
|
||||||
/loader/entries/ directory containing the ASCII string "type1" (suffixed
|
`/loader/entries/` directory containing the ASCII string `type1` (followed by a
|
||||||
with a UNIX newline). Tools that need to determine whether an existing
|
UNIX newline). Tools that need to determine whether an existing directory
|
||||||
directory implements the semantics described here may check for this file and
|
implements the semantics described here may check for this file and contents:
|
||||||
contents: if it exists and contains the mentioned string, it shall assume a
|
if it exists and contains the mentioned string, it shall assume a
|
||||||
standards compliant implementation is in place. If it exists but contains a
|
standards-compliant implementation is in place. If it exists but contains a
|
||||||
different string it shall assume non-standard semantics are implemented. If the
|
different string it shall assume other semantics are implemented. If the file
|
||||||
file does not exist no assumptions should be made.
|
does not exist, no assumptions should be made.
|
||||||
|
|
||||||
### Type #2 EFI Unified Kernel Images
|
### Type #2 EFI Unified Kernel Images
|
||||||
|
|
||||||
@ -327,31 +309,31 @@ A unified kernel image is a single EFI PE executable combining an EFI stub
|
|||||||
loader, a kernel image, an initramfs image, and the kernel command line. See
|
loader, a kernel image, an initramfs image, and the kernel command line. See
|
||||||
the description of the `--uefi` option in
|
the description of the `--uefi` option in
|
||||||
[dracut(8)](http://man7.org/linux/man-pages/man8/dracut.8.html). Such unified
|
[dracut(8)](http://man7.org/linux/man-pages/man8/dracut.8.html). Such unified
|
||||||
images will be searched for under `$BOOT/EFI/Linux/` and must have the
|
images are installed in the`$BOOT/EFI/Linux/` and `$XBOOTLDR/EFI/Linux/`
|
||||||
extension `.efi`. Support for images of this type is of course specific to
|
directories and must have the extension `.efi`.
|
||||||
systems with EFI firmware. Ignore this section if you work on systems not
|
Support for images of this type is of course specific to systems with EFI
|
||||||
supporting EFI.
|
firmware. Ignore this section if you work on systems not supporting EFI.
|
||||||
|
|
||||||
Type #2 file names should be chosen from the same restricted character set as
|
Type #2 file names should be chosen from the same restricted character set as
|
||||||
Type #1 described above (but use a different file name suffix of `.efi` instead
|
Type #1 described above (but with the file name suffix of `.efi` instead of
|
||||||
of `.conf`).
|
`.conf`).
|
||||||
|
|
||||||
Images of this type have the advantage that all metadata and payload that makes
|
Images of this type have the advantage that all metadata and payload that makes
|
||||||
up the boot entry is monopolized in a single PE file that can be signed
|
up the boot entry is contained in a single PE file that can be signed
|
||||||
cryptographically as one for the purpose of EFI SecureBoot.
|
cryptographically as one for the purpose of EFI SecureBoot.
|
||||||
|
|
||||||
A valid unified kernel image must contain two PE sections:
|
A valid unified kernel image must contain two PE sections:
|
||||||
|
|
||||||
* `.cmdline` section with the kernel command line
|
* `.cmdline` section with the kernel command line,
|
||||||
* `.osrel` section with an embedded copy of the
|
* `.osrel` section with an embedded copy of the
|
||||||
[os-release](https://www.freedesktop.org/software/systemd/man/os-release.html)
|
[os-release](https://www.freedesktop.org/software/systemd/man/os-release.html)
|
||||||
file describing the image
|
file describing the image.
|
||||||
|
|
||||||
The `PRETTY_NAME=` and `VERSION_ID=` fields in the embedded os-release file are
|
The `PRETTY_NAME=` and `VERSION_ID=` fields in the embedded `os-release` file
|
||||||
used the same as `title` and `version` in the "boot loader specification"
|
are used the same as `title` and `version` in the Type #1 entries. The
|
||||||
entries. The `.cmdline` section is used instead of the `options` field. `linux`
|
`.cmdline` section is used instead of the `options` field. `linux` and `initrd`
|
||||||
and `initrd` fields are not necessary, and there is no counterpart for the
|
fields are not necessary, and there is no counterpart for the `machine-id`
|
||||||
`machine-id` field.
|
field.
|
||||||
|
|
||||||
On EFI, any such images shall be added to the list of valid boot entries.
|
On EFI, any such images shall be added to the list of valid boot entries.
|
||||||
|
|
||||||
@ -374,43 +356,225 @@ path separator. This needs to be converted to an EFI-style "\\" separator in
|
|||||||
EFI boot loaders.
|
EFI boot loaders.
|
||||||
|
|
||||||
|
|
||||||
## Logic
|
## Locating boot entries
|
||||||
|
|
||||||
A _boot loader_ needs a file system driver to discover and read `$BOOT`, then
|
A _boot loader_ locates `$BOOT` and `$XBOOTLDR`, then simply reads all the
|
||||||
simply reads all files `$BOOT/loader/entries/*.conf`, and populates its boot
|
files `$BOOT/loader/entries/*.conf` and `$XBOOTLDR/loader/entries/*.conf`, and
|
||||||
menu with this. On EFI, it then extends this with any unified kernel images
|
populates its boot menu. On EFI, it then extends this with any unified kernel
|
||||||
found in `$BOOT/EFI/Linux/*.efi`. It may also add additional entries, for
|
images found in `$BOOT/EFI/Linux/*.efi` and `$XBOOTLDR/EFI/Linux/*.efi`. It may
|
||||||
example a "Reboot into firmware" option. Optionally it may sort the menu based
|
also add additional entries, for example a "Reboot into firmware" option.
|
||||||
on the `sort-key`, `machine-id` and `version` fields, and possibly others. It
|
Optionally it may sort the menu based on the `sort-key`, `machine-id` and
|
||||||
uses the file name to identify specific items, for example in case it supports
|
`version` fields, and possibly others. It uses the file name to identify
|
||||||
storing away default entry information somewhere. A boot loader should
|
specific items, for example in case it supports storing away default entry
|
||||||
generally not modify these files.
|
information somewhere. A boot loader should generally not modify these files.
|
||||||
|
|
||||||
For "Boot Loader Specification Entries" (Type #1), the _kernel package
|
For "Boot Loader Specification Entries" (Type #1), the _kernel package
|
||||||
installer_ installs the kernel and initrd images to `$BOOT` (it is recommended
|
installer_ installs the kernel and initrd images to `$XBOOTLDR` (if used) or
|
||||||
to place these files in a vendor and OS and installation specific directory)
|
`$BOOT`. It is recommended to place these files in a vendor and OS and
|
||||||
and then generates a configuration snippet for it, placing this in
|
installation specific directory. It then generates a configuration snippet,
|
||||||
`$BOOT/loader/entries/xyz.conf`, with xyz as concatenation of machine id and
|
placing it in `$BOOT/loader/entries/xyz.conf`, with "xyz" as concatenation of
|
||||||
version information (see above). The files created by a kernel package are
|
machine id and version information (see above). The files created by a kernel
|
||||||
private property of the kernel package and should be removed along with it.
|
package are tied to the kernel package and should be removed along with it.
|
||||||
|
|
||||||
For "EFI Unified Kernel Images" (Type #2), the vendor or kernel package
|
For "EFI Unified Kernel Images" (Type #2), the vendor or kernel package
|
||||||
installer creates the combined image and drops it into `$BOOT/EFI/Linux/`. This
|
installer should create the combined image and drop it into
|
||||||
file is also private property of the kernel package and should be removed along
|
`$BOOT/EFI/Linux/`. This file is also tied to the kernel package and should be
|
||||||
with it.
|
removed along with it.
|
||||||
|
|
||||||
A _UI application_ intended to show available boot options shall operate
|
A _UI application_ intended to show available boot options shall operate
|
||||||
similar to a boot loader, but might apply additional filters, for example by
|
similarly to a boot loader, but might apply additional filters, for example by
|
||||||
filtering out the booted OS via the machine ID, or by suppressing all but the
|
filtering the booted OS via the machine ID, or by suppressing all but the
|
||||||
newest kernel versions.
|
newest kernel versions.
|
||||||
|
|
||||||
An _OS installer_ picks the right place for `$BOOT` as defined above (possibly
|
An _OS installer_ picks the right place for `$BOOT` as defined above (possibly
|
||||||
creating a partition and file system for it) and pre-creates the
|
creating a partition and file system for it) and creates the `/loader/entries/`
|
||||||
`/loader/entries/` directory in it. It then installs an appropriate boot loader
|
directory in it. It then installs an appropriate boot loader that can read
|
||||||
that can read these snippets. Finally, it installs one or more kernel packages.
|
these snippets. Finally, it installs one or more kernel packages.
|
||||||
|
|
||||||
|
## Sorting
|
||||||
|
|
||||||
## Out of Focus
|
The boot loader menu should generally show entries in some order meaningful to
|
||||||
|
the user. The `title` key is free-form and not suitable to be used as the
|
||||||
|
primary sorting key. Instead, the boot loader should use the following rules:
|
||||||
|
if `sort-key` is set on both entries, use in order of priority,
|
||||||
|
the `sort-key` (A-Z, increasing [alphanumerical order](#alphanumerical-order)),
|
||||||
|
`machine-id` (A-Z, increasing alphanumerical order),
|
||||||
|
and `version` keys (decreasing [version order](#version-order)).
|
||||||
|
If `sort-key` is set on one entry, it sorts earlier.
|
||||||
|
At the end, if necessary, when `sort-key` is not set or those fields are not
|
||||||
|
set or are all equal, the boot loader should sort using the file name of the
|
||||||
|
entry (decreasing version sort), with the suffix removed.
|
||||||
|
|
||||||
|
**Note:** _This description assumes that the boot loader shows entries in a
|
||||||
|
traditional menu, with newest and "best" entries at the top, thus entries with
|
||||||
|
a higher version number are sorter *earlier*. The boot loader is free to
|
||||||
|
use a different direction (or none at all) during display._
|
||||||
|
|
||||||
|
### Alphanumerical order
|
||||||
|
|
||||||
|
Free-form strings and machine IDs should be compared using a method equivalent
|
||||||
|
to [strcmp(3)](https://man7.org/linux/man-pages/man3/strcmp.3.html) on their
|
||||||
|
UTF-8 represenations. If just one of the strings is unspecified or empty, it
|
||||||
|
compares lower. If both strings are unspecified or empty, they compare equal.
|
||||||
|
|
||||||
|
### Version order
|
||||||
|
|
||||||
|
The following method should be used to compare version strings. The algorithm
|
||||||
|
is based on rpm's `rpmvercmp()`, but not identical.
|
||||||
|
|
||||||
|
ASCII letters (`a-z`, `A-Z`) and digits (`0-9`) form alphanumerical components of the version.
|
||||||
|
Minus (`-`) separates the version and release parts.
|
||||||
|
Dot (`.`) separates parts of version or release.
|
||||||
|
Tilde (`~`) is a prefix that always compares lower.
|
||||||
|
Caret (`^`) is a prefix that always compares higher.
|
||||||
|
|
||||||
|
Both strings are compared from the beginning until the end, or until the
|
||||||
|
strings are found to compare as different. In a loop:
|
||||||
|
1. Any characters which are outside of the set of listed above (`a-z`, `A-Z`, `0-9`, `-`, `.`, `~`, `^`)
|
||||||
|
are skipped in both strings. In particular, this means that non-ASCII characters
|
||||||
|
that are Unicode digits or letters are skipped too.
|
||||||
|
2. If one of the strings has ended: if the other string hasn't, the string that
|
||||||
|
has remaining characters compares higher. Otherwise, the strings compare
|
||||||
|
equal.
|
||||||
|
3. If the remaining part of one of strings starts with `~`:
|
||||||
|
if other remaining part does not start with `~`,
|
||||||
|
the string with `~` compares lower. Otherwise, both tilde characters are skipped.
|
||||||
|
4. The check from point 2. is repeated here.
|
||||||
|
5. If the remaining part of one of strings starts with `-`:
|
||||||
|
if the other remaining part does not start with `-`,
|
||||||
|
the string with `-` compares lower. Otherwise, both minus characters are skipped.
|
||||||
|
6. If the remaining part of one of strings starts with `^`:
|
||||||
|
if the other remaining part does not start with `^`,
|
||||||
|
the string with `^` compares higher. Otherwise, both caret characters are skipped.
|
||||||
|
6. If the remaining part of one of strings starts with `.`:
|
||||||
|
if the other remaining part does not start with `.`,
|
||||||
|
the string with `.` compares lower. Otherwise, both dot characters are skipped.
|
||||||
|
7. If either of the remaining parts starts with a digit, numerical prefixes are
|
||||||
|
compared numerically. Any leading zeroes are skipped.
|
||||||
|
The numerical prefixes (until the first non-digit character) are evaluated as numbers.
|
||||||
|
If one of the prefixes is empty, it evaluates as 0.
|
||||||
|
If the numbers are different, the string with the bigger number compares higher.
|
||||||
|
Otherwise, the comparison continues at the following characters at point 1.
|
||||||
|
8. Leading alphabetical prefixes are compared alphabetically.
|
||||||
|
The substrings are compared letter-by-letter.
|
||||||
|
If both letters are the same, the comparison continues with the next letter.
|
||||||
|
Capital letters compare lower than lower-case letters (`A < a`).
|
||||||
|
When the end of one substring has been reached (a non-letter character or the end
|
||||||
|
of the whole string), if the other substring has remaining letters, it compares higher.
|
||||||
|
Otherwise, the comparison continues at the following characters at point 1.
|
||||||
|
|
||||||
|
Examples (with '' meaning the empty string):
|
||||||
|
|
||||||
|
* `11 == 11`
|
||||||
|
* `systemd-123 == systemd-123`
|
||||||
|
* `bar-123 < foo-123`
|
||||||
|
* `123a > 123`
|
||||||
|
* `123.a > 123`
|
||||||
|
* `123.a < 123.b`
|
||||||
|
* `123a > 123.a`
|
||||||
|
* `11α == 11β`
|
||||||
|
* `A < a`
|
||||||
|
* '' < `0`
|
||||||
|
* `0.` > `0`
|
||||||
|
* `0.0` > `0`
|
||||||
|
* `0` < `~`
|
||||||
|
* '' < `~`
|
||||||
|
|
||||||
|
Note: [systemd-analyze](https://www.freedesktop.org/software/systemd/man/systemd-analyze.html)
|
||||||
|
implements this version comparison algorithm as
|
||||||
|
```
|
||||||
|
systemd-analyze compare-versions <version-a> <version-b>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional discussion
|
||||||
|
|
||||||
|
### Why is there a need for this specification?
|
||||||
|
|
||||||
|
This specification brings the following advantages:
|
||||||
|
|
||||||
|
* Installation of new boot entries is more robust, as no explicit rewriting of
|
||||||
|
configuration files is required.
|
||||||
|
|
||||||
|
* It allows an out-of-the-box boot experience on any platform without the need
|
||||||
|
of traditional firmware mechanisms (e.g. BIOS calls, UEFI Boot Services).
|
||||||
|
|
||||||
|
* It improves dual-boot scenarios. Without cooperation, multiple Linux
|
||||||
|
installations tend to fight over which boot loader becomes the primary one in
|
||||||
|
possession of the MBR or the boot partition, and only that one installation
|
||||||
|
can then update the boot loader configuration. Other Linux installs have to
|
||||||
|
be manually configured to never touch the MBR and instead install a
|
||||||
|
chain-loaded boot loader in their own partition headers. In this new scheme
|
||||||
|
all installations share a loader directory and no manual configuration has to
|
||||||
|
take place. All participants implicitly cooperate due to removal of name
|
||||||
|
collisions and can install/remove their own boot menu entries without
|
||||||
|
interfering with the entries of other installed operating systems.
|
||||||
|
|
||||||
|
* Drop-in directories are now pretty ubiquitous on Linux as an easy way to
|
||||||
|
extend configuration without having to edit, regenerate or manipulate
|
||||||
|
configuration files. For the sake of uniformity, we should do the same for
|
||||||
|
the boot menu.
|
||||||
|
|
||||||
|
* Userspace code can sanely parse boot loader configuration which is essential
|
||||||
|
with modern firmware which does not necessarily initialize USB keyboards
|
||||||
|
during boot, which makes boot menus hard to reach for the user. If userspace
|
||||||
|
code can parse the boot loader configuration too, UI can be written that
|
||||||
|
select a boot menu item to boot into before rebooting the machine, thus not
|
||||||
|
requiring interactivity during early boot.
|
||||||
|
|
||||||
|
* To unify and thus simplify configuration of the various boot loaders, which
|
||||||
|
makes configuration of the boot loading process easier for users,
|
||||||
|
administrators, and developers alike.
|
||||||
|
|
||||||
|
* For boot loaders with configuration _scripts_ such as grub2, adopting this
|
||||||
|
spec allows for mostly static scripts that are generated only once at first
|
||||||
|
installation, but then do not need to be updated anymore as that is done via
|
||||||
|
drop-in files exclusively.
|
||||||
|
|
||||||
|
### Why not simply rely on the EFI boot menu logic?
|
||||||
|
|
||||||
|
EFI is not ubiquitous, especially not in embedded systems. But even on systems
|
||||||
|
with EFI, which provides a boot options logic that can offer similar
|
||||||
|
functionality, this specfication is still needed for the following reasons:
|
||||||
|
|
||||||
|
* The various EFI implementations implement the boot order/boot item logic to
|
||||||
|
different levels. Some firmware implementations do not offer a boot menu at
|
||||||
|
all and instead unconditionally follow the EFI boot order, booting the first
|
||||||
|
item that is working.
|
||||||
|
|
||||||
|
* If the firmware setup is used to reset data, usually all EFI boot entries
|
||||||
|
are lost, making the system entirely unbootable, as the firmware setups
|
||||||
|
generally do not offer a UI to define additional boot items. By placing the
|
||||||
|
menu item information on disk, it is always available, even if the firmware
|
||||||
|
configuration is lost.
|
||||||
|
|
||||||
|
* Harddisk images should be movable between machines and be bootable without
|
||||||
|
requiring firmare configuration. This also requires that the list
|
||||||
|
of boot options is defined on disk, and not in EFI variables alone.
|
||||||
|
|
||||||
|
* EFI is not universal yet (especially on non-x86 platforms), this
|
||||||
|
specification is useful both for EFI and non-EFI boot loaders.
|
||||||
|
|
||||||
|
* Many EFI systems disable USB support during early boot to optimize boot
|
||||||
|
times, thus making keyboard input unavailable in the EFI menu. It is thus
|
||||||
|
useful if the OS UI has a standardized way to discover available boot options
|
||||||
|
which can be booted to.
|
||||||
|
|
||||||
|
### Why is the version comparsion logic so complicated?
|
||||||
|
|
||||||
|
The `sort-key` allows us to group entries by "operating system", e.g. all
|
||||||
|
versions of Fedora together, no matter if they identify themselves as "Fedora
|
||||||
|
Workstation" or "Fedora Rawhide (prerelease)". The `sort-key` was introduced
|
||||||
|
only recently, so we need to provide a meaningful order for entries both with
|
||||||
|
and without it. Since it is a new concept, it is assumed that entries with
|
||||||
|
`sort-key` are newer.
|
||||||
|
|
||||||
|
In a traditional menu with entries displayed vertically, we want names to be
|
||||||
|
sorter alpabetically (CentOS, Debian, Fedora, OpenSUSE, …), it would be strange
|
||||||
|
to have them in reverse order. But when multiple kernels are available for the
|
||||||
|
same installation, we want to display the latest kernel with highest priority,
|
||||||
|
i.e. earlier in the list.
|
||||||
|
|
||||||
|
### Out of Focus
|
||||||
|
|
||||||
There are a couple of items that are out of focus for this specification:
|
There are a couple of items that are out of focus for this specification:
|
||||||
|
|
||||||
@ -419,6 +583,7 @@ There are a couple of items that are out of focus for this specification:
|
|||||||
communicate to the boot loader the default boot loader entry temporarily or
|
communicate to the boot loader the default boot loader entry temporarily or
|
||||||
persistently. Defining a common scheme for this is certainly a good idea, but
|
persistently. Defining a common scheme for this is certainly a good idea, but
|
||||||
out of focus for this specification.
|
out of focus for this specification.
|
||||||
|
|
||||||
* This specification is just about "Free" Operating systems. Hooking in other
|
* This specification is just about "Free" Operating systems. Hooking in other
|
||||||
operating systems (like Windows and macOS) into the boot menu is a different
|
operating systems (like Windows and macOS) into the boot menu is a different
|
||||||
story and should probably happen outside of this specification. For example,
|
story and should probably happen outside of this specification. For example,
|
||||||
@ -426,6 +591,7 @@ There are a couple of items that are out of focus for this specification:
|
|||||||
runtime without explicit configuration (like `systemd-boot` does it), or via
|
runtime without explicit configuration (like `systemd-boot` does it), or via
|
||||||
native configuration (for example via explicit Grub2 configuration generated
|
native configuration (for example via explicit Grub2 configuration generated
|
||||||
once at installation).
|
once at installation).
|
||||||
|
|
||||||
* This specification leaves undefined what to do about systems which are
|
* This specification leaves undefined what to do about systems which are
|
||||||
upgraded from an OS that does not implement this specification. As the
|
upgraded from an OS that does not implement this specification. As the
|
||||||
previous boot loader logic was largely handled by in distribution-specific
|
previous boot loader logic was largely handled by in distribution-specific
|
||||||
@ -434,6 +600,13 @@ There are a couple of items that are out of focus for this specification:
|
|||||||
with the old scheme for old installations and use this new scheme only for
|
with the old scheme for old installations and use this new scheme only for
|
||||||
new installations.
|
new installations.
|
||||||
|
|
||||||
|
* Referencing kernels or initrds on other partitions other than the partition
|
||||||
|
containing the Type #1 boot loader entry. This is by design, as specifying
|
||||||
|
other partitions or devices would require a non-trivial language for denoting
|
||||||
|
device paths. In particular this means that on non-EFI systems configuration
|
||||||
|
snippets following this specification cannot be used to spawn other operating
|
||||||
|
systems (such as Windows).
|
||||||
|
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||||||
* (newer) 124-1
|
* (newer) 124-1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (isempty(a) || isempty(b))
|
a = strempty(a);
|
||||||
return CMP(strcmp_ptr(a, b), 0);
|
b = strempty(b);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const sd_char *aa, *bb;
|
const sd_char *aa, *bb;
|
||||||
@ -150,7 +150,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If at least one string reaches the end, then longer is newer.
|
/* If at least one string reaches the end, then longer is newer.
|
||||||
* Note that except for '~' prefixed segments, a string has more segments is newer.
|
* Note that except for '~' prefixed segments, a string which has more segments is newer.
|
||||||
* So, this check must be after the '~' check. */
|
* So, this check must be after the '~' check. */
|
||||||
if (*a == '\0' || *b == '\0')
|
if (*a == '\0' || *b == '\0')
|
||||||
return CMP(*a, *b);
|
return CMP(*a, *b);
|
||||||
@ -187,12 +187,6 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_digit(*a) || is_digit(*b)) {
|
if (is_digit(*a) || is_digit(*b)) {
|
||||||
/* Skip leading '0', to make 00123 equivalent to 123. */
|
|
||||||
while (*a == '0')
|
|
||||||
a++;
|
|
||||||
while (*b == '0')
|
|
||||||
b++;
|
|
||||||
|
|
||||||
/* Find the leading numeric segments. One may be an empty string. So,
|
/* Find the leading numeric segments. One may be an empty string. So,
|
||||||
* numeric segments are always newer than alpha segments. */
|
* numeric segments are always newer than alpha segments. */
|
||||||
for (aa = a; is_digit(*aa); aa++)
|
for (aa = a; is_digit(*aa); aa++)
|
||||||
@ -200,6 +194,17 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||||||
for (bb = b; is_digit(*bb); bb++)
|
for (bb = b; is_digit(*bb); bb++)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Check if one of the strings was empty, but the other not. */
|
||||||
|
r = CMP(a != aa, b != bb);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Skip leading '0', to make 00123 equivalent to 123. */
|
||||||
|
while (*a == '0')
|
||||||
|
a++;
|
||||||
|
while (*b == '0')
|
||||||
|
b++;
|
||||||
|
|
||||||
/* To compare numeric segments without parsing their values, first compare the
|
/* To compare numeric segments without parsing their values, first compare the
|
||||||
* lengths of the segments. Eg. 12345 vs 123, longer is newer. */
|
* lengths of the segments. Eg. 12345 vs 123, longer is newer. */
|
||||||
r = CMP(aa - a, bb - b);
|
r = CMP(aa - a, bb - b);
|
||||||
@ -228,7 +233,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The current segments are equivalent. Let's compare the next one. */
|
/* The current segments are equivalent. Let's move to the next one. */
|
||||||
a = aa;
|
a = aa;
|
||||||
b = bb;
|
b = bb;
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ static int session_device_open(SessionDevice *sd, bool active) {
|
|||||||
assert(sd->type != DEVICE_TYPE_UNKNOWN);
|
assert(sd->type != DEVICE_TYPE_UNKNOWN);
|
||||||
assert(sd->node);
|
assert(sd->node);
|
||||||
|
|
||||||
/* open device and try to get an udev_device from it */
|
/* open device and try to get a udev_device from it */
|
||||||
fd = open(sd->node, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
|
fd = open(sd->node, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -852,8 +852,8 @@ static void test_strverscmp_improved_newer(const char *older, const char *newer)
|
|||||||
|
|
||||||
TEST(strverscmp_improved) {
|
TEST(strverscmp_improved) {
|
||||||
static const char * const versions[] = {
|
static const char * const versions[] = {
|
||||||
"",
|
|
||||||
"~1",
|
"~1",
|
||||||
|
"",
|
||||||
"ab",
|
"ab",
|
||||||
"abb",
|
"abb",
|
||||||
"abc",
|
"abc",
|
||||||
@ -917,6 +917,29 @@ TEST(strverscmp_improved) {
|
|||||||
/* invalid characters */
|
/* invalid characters */
|
||||||
assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0);
|
assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0);
|
||||||
|
|
||||||
|
/* some corner cases */
|
||||||
|
assert_se(strverscmp_improved("123.", "123") > 0); /* One more version segment */
|
||||||
|
assert_se(strverscmp_improved("12_3", "123") < 0); /* 12 < 123 */
|
||||||
|
assert_se(strverscmp_improved("12_3", "12") > 0); /* 3 > '' */
|
||||||
|
assert_se(strverscmp_improved("12_3", "12.3") > 0); /* 3 > '' */
|
||||||
|
assert_se(strverscmp_improved("123.0", "123") > 0); /* 0 > '' */
|
||||||
|
assert_se(strverscmp_improved("123_0", "123") > 0); /* 0 > '' */
|
||||||
|
assert_se(strverscmp_improved("123..0", "123.0") < 0); /* '' < 0 */
|
||||||
|
|
||||||
|
/* empty strings or strings with ignored characters only */
|
||||||
|
assert_se(strverscmp_improved("", NULL) == 0);
|
||||||
|
assert_se(strverscmp_improved(NULL, "") == 0);
|
||||||
|
assert_se(strverscmp_improved("0_", "0") == 0);
|
||||||
|
assert_se(strverscmp_improved("_0_", "0") == 0);
|
||||||
|
assert_se(strverscmp_improved("_0", "0") == 0);
|
||||||
|
assert_se(strverscmp_improved("0", "0___") == 0);
|
||||||
|
assert_se(strverscmp_improved("", "_") == 0);
|
||||||
|
assert_se(strverscmp_improved("_", "") == 0);
|
||||||
|
assert_se(strverscmp_improved("_", "_") == 0);
|
||||||
|
assert_se(strverscmp_improved("", "~") > 0);
|
||||||
|
assert_se(strverscmp_improved("~", "") < 0);
|
||||||
|
assert_se(strverscmp_improved("~", "~") == 0);
|
||||||
|
|
||||||
/* non-ASCII digits */
|
/* non-ASCII digits */
|
||||||
(void) setlocale(LC_NUMERIC, "ar_YE.utf8");
|
(void) setlocale(LC_NUMERIC, "ar_YE.utf8");
|
||||||
assert_se(strverscmp_improved("1٠١٢٣٤٥٦٧٨٩", "1") == 0);
|
assert_se(strverscmp_improved("1٠١٢٣٤٥٦٧٨٩", "1") == 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user