From 11ce3ea2f2219ab9c0700bcf7f8ed4312d80e937 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Feb 2022 13:59:36 +0100 Subject: [PATCH 1/8] kernel-install: don't try to persist used machine ID locally 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. --- src/kernel-install/90-loaderentry.install | 6 +++++- src/kernel-install/kernel-install | 16 +++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 3edefdefb4..046771169c 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -68,7 +68,11 @@ elif [ -r /usr/lib/kernel/cmdline ]; then else BOOT_OPTIONS="$(tr -s "$IFS" '\n' >/etc/machine-info -[ -z "$MACHINE_ID" ] && NEW_MACHINE_ID="$(systemd-id128 new)" && echo "KERNEL_INSTALL_MACHINE_ID=$NEW_MACHINE_ID" >>/etc/machine-info -[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" -[ -z "$MACHINE_ID" ] && MACHINE_ID="Default" +# If /etc/machine-id is initialized we'll use it, otherwise we'll use a freshly +# generated one. If the user configured an explicit machine ID to use in +# /etc/machine-info to use for our purpose, we'll use that instead (for +# compatibility). +[ -z "$MACHINE_ID" ] && [ -r /etc/machine-info ] && . /etc/machine-info && MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" +[ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID Date: Wed, 9 Feb 2022 14:29:19 +0100 Subject: [PATCH 2/8] kernel-install: add a new $ENTRY_TOKEN variable for naming boot entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/kernel-install/90-loaderentry.install | 11 ++++++----- src/kernel-install/kernel-install | 21 +++++++++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 046771169c..46261a2c11 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -29,6 +29,7 @@ INITRD_OPTIONS_SHIFT=4 [ "$KERNEL_INSTALL_LAYOUT" = "bls" ] || exit 0 MACHINE_ID="$KERNEL_INSTALL_MACHINE_ID" +ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN" BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT" BOOT_MNT="$(stat -c %m "$BOOT_ROOT")" @@ -41,10 +42,10 @@ fi case "$COMMAND" in remove) [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ - echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf" + echo "Removing $BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION*.conf" exec rm -f \ - "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \ - "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf" + "$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf" \ + "$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+"*".conf" ;; add) ;; @@ -80,9 +81,9 @@ if [ -r /etc/kernel/tries ]; then echo "/etc/kernel/tries does not contain an integer." >&2 exit 1 fi - LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+$TRIES.conf" + LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.conf" else - LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" + LOADER_ENTRY="$BOOT_ROOT/loader/entries/$ENTRY_TOKEN-$KERNEL_VERSION.conf" fi if ! [ -d "$ENTRY_DIR_ABS" ]; then diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index e94aa79bc6..75a31c62d4 100755 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -97,7 +97,19 @@ fi [ -z "$MACHINE_ID" ] && [ -r /etc/machine-id ] && read -r MACHINE_ID Date: Wed, 9 Feb 2022 14:44:48 +0100 Subject: [PATCH 3/8] kernel-install: only generate systemd.boot_id= in kernel command line if used for naming the boot loader spec files/dirs 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. --- src/kernel-install/90-loaderentry.install | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 46261a2c11..c1d69aa824 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -70,10 +70,15 @@ else BOOT_OPTIONS="$(tr -s "$IFS" '\n' Date: Thu, 10 Feb 2022 14:27:22 +0100 Subject: [PATCH 4/8] kernel-install: search harder for kernel image/initrd drop-in dir 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. --- src/kernel-install/kernel-install | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index 75a31c62d4..c42c40592a 100755 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -103,29 +103,50 @@ fi # for naming the .conf boot loader spec entry. Typically this is just the # machine ID, but it can be anything else, too, if we are told so. [ -z "$ENTRY_TOKEN" ] && [ -r /etc/kernel/entry-token ] && read -r ENTRY_TOKEN Date: Thu, 10 Feb 2022 14:37:37 +0100 Subject: [PATCH 5/8] kernel-install: add new "inspect" verb, showing paths and parameters we discovered --- src/kernel-install/kernel-install | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index c42c40592a..b8099bd12c 100755 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -25,6 +25,7 @@ usage() echo "Usage:" echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]" echo " $0 [OPTIONS...] remove KERNEL-VERSION" + echo " $0 [OPTIONS...] inspect" echo "Options:" echo " -h, --help Print this help" echo " -v, --verbose Increase verbosity" @@ -72,13 +73,17 @@ else [ $# -ge 1 ] && shift fi -if [ $# -lt 1 ]; then - echo "Error: not enough arguments" >&2 - exit 1 -fi +if [ "$COMMAND" = "inspect" ]; then + KERNEL_VERSION="" +else + if [ $# -lt 1 ]; then + echo "Error: not enough arguments" >&2 + exit 1 + fi -KERNEL_VERSION="$1" -shift + KERNEL_VERSION="$1" + shift +fi layout= initrd_generator= @@ -237,6 +242,18 @@ case "$COMMAND" in fi ;; + inspect) + echo "KERNEL_INSTALL_MACHINE_ID: $KERNEL_INSTALL_MACHINE_ID" + echo "KERNEL_INSTALL_ENTRY_TOKEN: $KERNEL_INSTALL_ENTRY_TOKEN" + echo "KERNEL_INSTALL_BOOT_ROOT: $KERNEL_INSTALL_BOOT_ROOT" + echo "KERNEL_INSTALL_LAYOUT: $KERNEL_INSTALL_LAYOUT" + echo "KERNEL_INSTALL_INITRD_GENERATOR: $KERNEL_INSTALL_INITRD_GENERATOR" + echo "ENTRY_DIR_ABS: $KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN/\$KERNEL_VERSION" + + # Assert that ENTRY_DIR_ABS actually matches what we are printing here + [ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; } + + ;; *) echo "Error: unknown command '$COMMAND'" >&2 exit 1 From fe81e346c85d622e30e425a0a7d36a485fbd126c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Feb 2022 15:27:45 +0100 Subject: [PATCH 6/8] man: document recent changes This drops documentation of KERNEL_INSTALL_MACHINE_ID as machine-info field (though we'll still read it for compat). This updates the kernel-install man page to always say "ENTRY-TOKEN" instead of "MACHINE-ID" where appropriate, to clear the confusion up between the two. This also tries to fix how we denote env vars (always prefix with $ and without = suffix), and other vars (without $ but with = suffix) Other fixes. --- man/kernel-install.xml | 192 ++++++++++++++++++++++++----------------- man/machine-info.xml | 11 --- 2 files changed, 115 insertions(+), 88 deletions(-) diff --git a/man/kernel-install.xml b/man/kernel-install.xml index 685617863e..5ec76999ad 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -39,21 +39,21 @@ /boot/, /efi/, or /boot/efi/, see below. - kernel-install will execute the files - located in the directory /usr/lib/kernel/install.d/ - and the local administration directory /etc/kernel/install.d/. - All files are collectively sorted and executed in lexical order, regardless of the directory in - which they live. However, files with identical filenames replace each other. - Files in /etc/kernel/install.d/ take precedence over files with the same name - in /usr/lib/kernel/install.d/. This can be used to override a system-supplied - executables with a local file if needed; a symbolic link in /etc/kernel/install.d/ - with the same name as an executable in /usr/lib/kernel/install.d/, - pointing to /dev/null, disables the executable entirely. Executables must have the - extension .install; other extensions are ignored. + kernel-install will run the executable files ("plugins") located in the + directory /usr/lib/kernel/install.d/ and the local administration directory + /etc/kernel/install.d/. All files are collectively sorted and executed in lexical + order, regardless of the directory in which they live. However, files with identical filenames replace + each other. Files in /etc/kernel/install.d/ take precedence over files with the + same name in /usr/lib/kernel/install.d/. This can be used to override a + system-supplied executables with a local file if needed; a symbolic link in + /etc/kernel/install.d/ with the same name as an executable in + /usr/lib/kernel/install.d/, pointing to /dev/null, disables the + executable entirely. Executables must have the extension .install; other extensions + are ignored. - An executable should return 0 on success. It may also - return 77 to cause the whole operation to terminate - (executables later in lexical order will be skipped). + An executable placed in these directories should return 0 on success. It may + also return 77 to cause the whole operation to terminate (executables later in + lexical order will be skipped). @@ -64,37 +64,45 @@ add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...] This command expects a kernel version string and a path to a kernel image file as - arguments. kernel-install calls the executables from - /usr/lib/kernel/install.d/*.install and - /etc/kernel/install.d/*.install with the following arguments: + arguments. Optionally, one or more initial RAM disk images may be specified as well (note that + plugins might generate additional ones). kernel-install calls the executable + files from /usr/lib/kernel/install.d/*.install and + /etc/kernel/install.d/*.install (i.e. the plugins) with the following + arguments: - add KERNEL-VERSION $BOOT/MACHINE-ID/KERNEL-VERSION/ KERNEL-IMAGE [INITRD-FILE ...] - + add KERNEL-VERSION $BOOT/ENTRY-TOKEN/KERNEL-VERSION/ KERNEL-IMAGE [INITRD-FILE ...] + + The third argument directly refers to the path where to place kernel images, initial RAM disk + images and other resources for Boot + Loader Specification Type #1 entries (the "entry directory"). If other boot loader schemes + are used the parameter may be ignored. The ENTRY-TOKEN string is + typically the machine ID and is supposed to identify the local installation on the system. For + details see below. Two default plugins execute the following operations in this case: kernel-install creates - $BOOT/MACHINE-ID/KERNEL-VERSION, - if enabled (see $KERNEL_INSTALL_LAYOUT=). + $BOOT/ENTRY-TOKEN/KERNEL-VERSION, + if enabled (see $KERNEL_INSTALL_LAYOUT). 50-depmod.install runs depmod8 for the KERNEL-VERSION. - 90-loaderentry.install - copies KERNEL-IMAGE to - $BOOT/MACHINE-ID/KERNEL-VERSION/linux. + 90-loaderentry.install copies + KERNEL-IMAGE to + $BOOT/ENTRY-TOKEN/KERNEL-VERSION/linux. If INITRD-FILEs are provided, it also copies them to - $BOOT/MACHINE-ID/KERNEL_VERSION/INITRD-FILE. + $BOOT/ENTRY-TOKEN/KERNEL_VERSION/INITRD-FILE. It also creates a boot loader entry according to the Boot Loader Specification in - $BOOT/loader/entries/MACHINE-ID-KERNEL-VERSION.conf. + url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification (Type #1) in + $BOOT/loader/entries/ENTRY-TOKEN-KERNEL-VERSION.conf. The title of the entry is the PRETTY_NAME parameter specified in - /etc/os-release or /usr/lib/os-release (if the former is - missing), or "Linux KERNEL-VERSION", if unset. + /etc/os-release or /usr/lib/os-release (if the former + is missing), or "Linux KERNEL-VERSION", if unset. - If $KERNEL_INSTALL_LAYOUT= is not "bls", this plugin does nothing. + If $KERNEL_INSTALL_LAYOUT is not "bls", this plugin does nothing. @@ -104,13 +112,13 @@ This command expects a kernel version string as single argument. This calls executables from /usr/lib/kernel/install.d/*.install and /etc/kernel/install.d/*.install with the following arguments: - - remove KERNEL-VERSION $BOOT/MACHINE-ID/KERNEL-VERSION/ - Afterwards, kernel-install removes the directory - $BOOT/MACHINE-ID/KERNEL-VERSION/ - and its contents. + remove KERNEL-VERSION $BOOT/ENTRY-TOKEN/KERNEL-VERSION/ + + Afterwards, kernel-install removes the entry directory + $BOOT/ENTRY-TOKEN/KERNEL-VERSION/ + and its contents, if it exists. Two default plugins execute the following operations in this case: @@ -118,14 +126,18 @@ 50-depmod.install removes the files generated by depmod for this kernel again. 90-loaderentry.install removes the file - $BOOT/loader/entries/MACHINE-ID-KERNEL-VERSION.conf. - - kernel-install removes - $BOOT/MACHINE-ID/KERNEL-VERSION, - if enabled (see $KERNEL_INSTALL_LAYOUT=). + $BOOT/loader/entries/ENTRY-TOKEN-KERNEL-VERSION.conf. + + inspect + + Shows the various paths and parameters configured or auto-detected. In particular shows the + values of the various $KERNEL_INSTALL_* environment variables listed + below. + + @@ -135,9 +147,9 @@ The partition where the kernels and Boot Loader Specification snippets are located is called $BOOT. kernel-install determines the location of this partition by checking - /efi/, /boot/, and /boot/efi/ - in turn. The first location where $BOOT/loader/entries/ or - $BOOT/$MACHINE_ID/ exists is used. + /efi/, /boot/, and /boot/efi/ in turn. The + first location where $BOOT/loader/entries/ or + $BOOT/ENTRY-TOKEN/ exists is used. @@ -163,36 +175,57 @@ If is used, $KERNEL_INSTALL_VERBOSE=1 will be set for the plugins. They may output additional logs in this case. - If MACHINE_ID= is set and not empty, it will be used as MACHINE-ID, - overriding any automatic detection attempts. The value must be a valid machine ID (32 hexadecimal characters). + If $MACHINE_ID is set and not empty when kernel-install is + invoked, it will be used as MACHINE-ID, overriding any automatic detection + attempts. The value must be a valid machine ID (32 hexadecimal characters). - KERNEL_INSTALL_MACHINE_ID= is set for the plugins to the desired MACHINE-ID – - either 32 hexadecimal characters or the special value Default. - KERNEL_INSTALL_BOOT_ROOT= is set for the plugins to the root directory (mount point, usually) of the hierarchy - where boot-loader entries, kernel images, and associated resources should be placed. Can be overridden by setting BOOT_ROOT=. + $KERNEL_INSTALL_MACHINE_ID is set for the plugins to the desired + MACHINE-ID to use. It's always a 128bit ID, and typically the ID from + /etc/machine-id or the one passed in via $MACHINE_ID. (If no + machine ID was specified via these methods it might be generated randomly by + kernel-install, in which case it only applies to this invocation.) - KERNEL_INSTALL_LAYOUT=bls|other|... is set for the plugins to specify the installation layout. - Defaults to if $BOOT/MACHINE-ID exists, or otherwise. - Additional layout names may be defined by convention. If a plugin uses a special layout, - it's encouraged to declare its own layout name and configure layout= in install.conf upon initial installation. + $KERNEL_INSTALL_ENTRY_TOKEN is set for the plugins to the desired entry "token" + to use. It's an identifier that shall be used to identify the local installation, and is often the + machine ID, i.e. same as $KERNEL_INSTALL_MACHINE_ID, but might also be a different + type of identifier, for example a fixed string or the ID=, + IMAGE_ID= values from /etc/os-release. The string passed here + will be used to name Boot Loader Specification entries, or the directories the kernel image and initial + RAM disk images are placed into. Note that while oftentimes + $KERNEL_INSTALL_ENTRY_TOKEN and $KERNEL_INSTALL_MACHINE_ID are set + to the same value, the latter is guaranteed to be a valid 32 character ID in lowercase hexadecimals while + the former can be any short string. The entry token to use is read from + /etc/kernel/entry-token, if it exists. Otherwise a few possible candidates below the + $BOOT are searched for Boot Loader Specification Type 1 entry directories, and if + found the entry token is derived from that. If that is not successful the machine ID is used as + fallback. - KERNEL_INSTALL_INITRD_GENERATOR=... is set for plugins to select the initrd generator. - This should be configured as initrd_generator= in install.conf. - + $KERNEL_INSTALL_BOOT_ROOT is set for the plugins to the absolute path of the + root directory (mount point, usually) of the hierarchy where boot loader entries, kernel images, and + associated resources should be placed. This usually is the path where the XBOOTLDR partition or the ESP + (EFI System Partition) are mounted, and also conceptually referred to as $BOOT. Can be + overridden by setting $BOOT_ROOT. - KERNEL_INSTALL_STAGING_AREA=... is set for plugins to a path to a directory. - Plugins may drop files in that directory, and they will be installed as part of the loader entry, based - on the file name and extension. + $KERNEL_INSTALL_LAYOUT=bls|other|... is set for the plugins to specify the + installation layout. Defaults to if + $BOOT/ENTRY-TOKEN exists, or + otherwise. Additional layout names may be defined by convention. If a plugin uses a special layout, it's + encouraged to declare its own layout name and configure layout= in + install.conf upon initial installation. The following values are currently + understood: bls - Standard Boot Loader Specification layout, - compatible with systemd-boot7: entries in - $BOOT/loader/entries/MACHINE-ID-KERNEL-VERSION[+TRIES].conf, - kernel and initrds under $BOOT/MACHINE-ID/KERNEL-VERSION/ - Provided by 90-loaderentry.install. + Standard Boot Loader + Specification Type #1 layout, compatible with + systemd-boot7: + entries in + $BOOT/loader/entries/ENTRY-TOKEN-KERNEL-VERSION[+TRIES].conf, + kernel and initrds under + $BOOT/ENTRY-TOKEN/KERNEL-VERSION/ + Implemented by 90-loaderentry.install. @@ -202,6 +235,15 @@ + + $KERNEL_INSTALL_INITRD_GENERATOR is set for plugins to select the initrd + generator. This should be configured as initrd_generator= in + install.conf. + + + $KERNEL_INSTALL_STAGING_AREA is set for plugins to a path to a directory. + Plugins may drop files in that directory, and they will be installed as part of the loader entry, based + on the file name and extension. @@ -249,25 +291,21 @@ - /etc/machine-id + /etc/kernel/entry-token - The content of this file specifies the machine identification - MACHINE-ID. If /etc/machine-id - cannot be read or is temporary (backed by a file on tmpfs), - kernel-install will use Default instead. + If this file exists it is read and used as "entry token" for this system, i.e. is used for + naming Boot Loader Specification entries, see + $KERNEL_INSTALL_ENTRY_TOKEN above for details. - /etc/machine-info + /etc/machine-id - If this file contains the KERNEL_INSTALL_MACHINE_ID variable, - kernel-install will use it as MACHINE-ID instead of - the contents of /etc/machine-id. If the variable is not found in - /etc/machine-info, kernel-install will try to save the - machine ID it uses to install to $BOOT to this file. + The content of this file specifies the machine identification + MACHINE-ID. @@ -275,9 +313,9 @@ /etc/os-release /usr/lib/os-release - + Read by 90-loaderentry.install. - If available, PRETTY_NAME is read from these files and used as the title of the boot menu entry. + If available, PRETTY_NAME= is read from these files and used as the title of the boot menu entry. Otherwise, Linux KERNEL-VERSION will be used. diff --git a/man/machine-info.xml b/man/machine-info.xml index 4467c59c94..fddcfb6a6c 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -129,17 +129,6 @@ - - KERNEL_INSTALL_MACHINE_ID= - - Specifies the installation-specific installation directory - kernel-install should use. The value must be a valid machine ID (32 hexadecimal - characters). This would generally be the original machine-id that was used when the boot loader - entries for this installation were first added. When not set, the current value of - machine-id5 - will be used. - - VENDOR= From f337f903df5980a8114e9c4831a171a588e04459 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 10 Feb 2022 18:01:36 +0100 Subject: [PATCH 7/8] bootctl: update to new kernel-install semantics This makes a bunch of closely related changes: 1. The "entry-token" concept already introduced in kernel-install is now made use of. i.e. specifically there's a new option --entry-token= that can be used to explicitly select by which ID to identify boot loader entries: the machine ID, or some OS ID (ID= or IMAGE_ID= from /etc/os-release, or even some completely different string. The selected string is then persisted to /etc/kernel/entry-token, so that kernel-install can find it there. 2. The --make-machine-id-directory= switch is renamed to --make-entry-directory= since after all it's not necessarily the machine ID the dir is named after, but can be any other string as selected by the entry token. 3. This drops all code to make automatic changes to /etc/machine-info. Specifically, the KERNEL_INSTALL_MACHINE_ID= field is now more generically implemented in /etc/kernel/entry-token described above, hence no need to place it at two locations. And the KERNEL_INSTALL_LAYOUT= field is not configurable by user switch or similar anyway in bootctl, but only read from /etc/kernel/install.conf, and hence copying it from one configuration file to another appears unnecessary, the second copy is fully redundant. Note that this just drops writing these fields, they'll still be honoured when already set. --- man/bootctl.xml | 63 +++++++-- src/boot/bootctl.c | 321 ++++++++++++++++++++++++++++----------------- 2 files changed, 248 insertions(+), 136 deletions(-) diff --git a/man/bootctl.xml b/man/bootctl.xml index 16c4985796..ff49a8043c 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -258,23 +258,60 @@ - - Control creation and deletion of the top-level machine ID directory on the file - system containing boot loader entries (i.e. beneath the file system returned by the - option, see above) during and - , respectively. Defaults to no. See + + Controls creation and deletion of the Boot Loader Specification Type #1 entry + directory on the file system containing resources such as kernel images and initial RAM disk images + during and , respectively. The directory is named + after the entry token, as specified with parameter described below, + and is placed immediately below the $BOOT root directory (i.e. beneath the file + system returned by the option, see above). Defaults to + no. + + + + + + Controls how to name and identify boot loader entries for this OS + installation. Accepted during , and takes one of auto, + machine-id, os-id, os-image-id or an + arbitrary string prefixed by literal: as argument. + + If set to the entries are named after the machine ID of the running + system (e.g. b0e793a9baf14b5fa13ecbe84ff637ac). See machine-id5 for details about the machine ID concept and file. - Overriding this may be desirable to hide the machine ID from the (unencrypted) ESP, configure a - kernel-install8 - script, or, conversely, commit a transient machine ID. + If set to the entries are named after the OS ID of the running system, + i.e. the ID= field of + os-release5 + (e.g. fedora). Similar, if set to the entries are + named after the OS image ID of the running system, i.e. the IMAGE_ID= field of + os-release (e.g. vendorx-cashier-system). - The top-level machine ID directory is useful to allow smooth multi-boot installations: each - installed OS instance will have a different machine ID and thus a separate directory to place its - boot-time resources in. If this feature is turned off with this option, care needs to be taken that - multiple OS instances do not place conflicting files on the shared ESP and Extended Boot Loader - Partitions, or that multiple OS instances are not possible. + If set to (the default), the /etc/kernel/entry-token + file will be read if it exists, and the stored value used. Otherwise if the local machine ID is + initialized it is used. Otherwise IMAGE_ID= from os-release + will be used, if set. Otherwise, ID= from os-release will be + used, if set. + + Unless set to machine-id, or when + is used the selected token string is written to a file + /etc/kernel/entry-token, to ensure it will be used for future entries. This file + is also read by + kernel-install8, + in order to identify under which name to generate boot loader entries for newly installed kernels, or + to determine the entry names for removing old ones. + + Using the machine ID for naming the entries is generally preferable, however there are cases + where using the other identifiers is a good option. Specifically: if the identification data that the + machine ID entails shall not be stored on the (unencrypted) $BOOT partition, or if + the ID shall be generated on first boot and is not known when the entries are prepared. Note that + using the machine ID has the benefit that multiple parallel installations of the same OS can coexist + on the same medium, and they can update their boot loader entries independently. When using another + identifier (such as the OS ID or the OS image ID), parallel installations of the same OS would try to + use the same entry name. To support parallel installations, the installer must use a different entry + token when adding a second installation. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 1f4dd69d08..2035fa0d25 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -28,6 +28,7 @@ #include "glyph-util.h" #include "main-func.h" #include "mkdir.h" +#include "os-util.h" #include "pager.h" #include "parse-argument.h" #include "parse-util.h" @@ -56,13 +57,22 @@ static bool arg_print_dollar_boot_path = false; static bool arg_touch_variables = true; static PagerFlags arg_pager_flags = 0; static bool arg_graceful = false; -static int arg_make_machine_id_directory = 0; +static int arg_make_entry_directory = false; /* tri-state: < 0 for automatic logic */ static sd_id128_t arg_machine_id = SD_ID128_NULL; static char *arg_install_layout = NULL; +static enum { + ARG_ENTRY_TOKEN_MACHINE_ID, + ARG_ENTRY_TOKEN_OS_IMAGE_ID, + ARG_ENTRY_TOKEN_OS_ID, + ARG_ENTRY_TOKEN_LITERAL, + ARG_ENTRY_TOKEN_AUTO, +} arg_entry_token_type = ARG_ENTRY_TOKEN_AUTO; +static char *arg_entry_token = NULL; STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep); STATIC_DESTRUCTOR_REGISTER(arg_install_layout, freep); +STATIC_DESTRUCTOR_REGISTER(arg_entry_token, freep); static const char *arg_dollar_boot_path(void) { /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */ @@ -170,32 +180,133 @@ static int load_install_machine_id_and_layout(void) { return 0; } -static int settle_install_machine_id(void) { +static int settle_entry_token(void) { + int r; + + switch (arg_entry_token_type) { + + case ARG_ENTRY_TOKEN_AUTO: { + _cleanup_free_ char *buf = NULL; + r = read_one_line_file("/etc/kernel/entry-token", &buf); + if (r < 0 && r != -ENOENT) + return log_error_errno(r, "Failed to read /etc/kernel/entry-token: %m"); + + if (!isempty(buf)) { + free_and_replace(arg_entry_token, buf); + arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL; + } else if (sd_id128_is_null(arg_machine_id)) { + _cleanup_free_ char *id = NULL, *image_id = NULL; + + r = parse_os_release(NULL, + "IMAGE_ID", &image_id, + "ID", &id); + if (r < 0) + return log_error_errno(r, "Failed to load /etc/os-release: %m"); + + if (!isempty(image_id)) { + free_and_replace(arg_entry_token, image_id); + arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID; + } else if (!isempty(id)) { + free_and_replace(arg_entry_token, id); + arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID; + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields."); + } else { + r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id)); + if (r < 0) + return r; + + arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID; + } + + break; + } + + case ARG_ENTRY_TOKEN_MACHINE_ID: + if (sd_id128_is_null(arg_machine_id)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set."); + + r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id)); + if (r < 0) + return r; + + break; + + case ARG_ENTRY_TOKEN_OS_IMAGE_ID: { + _cleanup_free_ char *buf = NULL; + + r = parse_os_release(NULL, "IMAGE_ID", &buf); + if (r < 0) + return log_error_errno(r, "Failed to load /etc/os-release: %m"); + + if (isempty(buf)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "IMAGE_ID= field not set in /etc/os-release."); + + free_and_replace(arg_entry_token, buf); + break; + } + + case ARG_ENTRY_TOKEN_OS_ID: { + _cleanup_free_ char *buf = NULL; + + r = parse_os_release(NULL, "ID", &buf); + if (r < 0) + return log_error_errno(r, "Failed to load /etc/os-release: %m"); + + if (isempty(buf)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "ID= field not set in /etc/os-release."); + + free_and_replace(arg_entry_token, buf); + break; + } + + case ARG_ENTRY_TOKEN_LITERAL: + assert(!isempty(arg_entry_token)); /* already filled in by command line parser */ + break; + } + + if (isempty(arg_entry_token) || !string_is_safe(arg_entry_token)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token); + + log_debug("Using entry token: %s", arg_entry_token); + return 0; +} + +static bool use_boot_loader_spec_type1(void) { + /* If the layout is not specified, or if it is set explicitly to "bls" we assume Boot Loader + * Specification Type #1 is the chosen format for our boot loader entries */ + return !arg_install_layout || streq(arg_install_layout, "bls"); +} + +static int settle_make_entry_directory(void) { int r; r = load_install_machine_id_and_layout(); if (r < 0) return r; - bool layout_non_bls = arg_install_layout && !streq(arg_install_layout, "bls"); - if (arg_make_machine_id_directory < 0) { - if (layout_non_bls || sd_id128_is_null(arg_machine_id)) - arg_make_machine_id_directory = 0; - else { - r = path_is_temporary_fs("/etc/machine-id"); - if (r < 0) - return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m"); - arg_make_machine_id_directory = r == 0; - } + r = settle_entry_token(); + if (r < 0) + return r; + + bool layout_type1 = use_boot_loader_spec_type1(); + if (arg_make_entry_directory < 0) { /* Automatic mode */ + if (layout_type1) { + if (arg_entry_token == ARG_ENTRY_TOKEN_MACHINE_ID) { + r = path_is_temporary_fs("/etc/machine-id"); + if (r < 0) + return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m"); + + arg_make_entry_directory = r == 0; + } else + arg_make_entry_directory = true; + } else + arg_make_entry_directory = false; } - if (arg_make_machine_id_directory > 0 && sd_id128_is_null(arg_machine_id)) + if (arg_make_entry_directory > 0 && !layout_type1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Machine ID not found, but bls directory creation was requested."); - - if (arg_make_machine_id_directory > 0 && layout_non_bls) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "KERNEL_INSTALL_LAYOUT=%s is configured, but bls directory creation was requested.", + "KERNEL_INSTALL_LAYOUT=%s is configured, but Boot Loader Specification Type #1 entry directory creation was requested.", arg_install_layout); return 0; @@ -1039,14 +1150,14 @@ static int remove_subdirs(const char *root, const char *const *subdirs) { return r < 0 ? r : q; } -static int remove_machine_id_directory(const char *root) { +static int remove_entry_directory(const char *root) { assert(root); - assert(arg_make_machine_id_directory >= 0); + assert(arg_make_entry_directory >= 0); - if (!arg_make_machine_id_directory || sd_id128_is_null(arg_machine_id)) + if (!arg_make_entry_directory || !arg_entry_token) return 0; - return rmdir_one(root, SD_ID128_TO_STRING(arg_machine_id)); + return rmdir_one(root, arg_entry_token); } static int remove_binaries(const char *esp_path) { @@ -1138,7 +1249,7 @@ static int install_loader_config(const char *esp_path) { const char *p; int r; - assert(arg_make_machine_id_directory >= 0); + assert(arg_make_entry_directory >= 0); p = prefix_roota(esp_path, "/loader/loader.conf"); if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */ @@ -1155,9 +1266,9 @@ static int install_loader_config(const char *esp_path) { fprintf(f, "#timeout 3\n" "#console-mode keep\n"); - if (arg_make_machine_id_directory) { - assert(!sd_id128_is_null(arg_machine_id)); - fprintf(f, "default %s-*\n", SD_ID128_TO_STRING(arg_machine_id)); + if (arg_make_entry_directory) { + assert(arg_entry_token); + fprintf(f, "default %s-*\n", arg_entry_token); } r = fflush_sync_and_check(f); @@ -1174,100 +1285,33 @@ static int install_loader_config(const char *esp_path) { return 1; } -static int install_machine_id_directory(const char *root) { +static int install_entry_directory(const char *root) { assert(root); - assert(arg_make_machine_id_directory >= 0); + assert(arg_make_entry_directory >= 0); - if (!arg_make_machine_id_directory) + if (!arg_make_entry_directory) return 0; - assert(!sd_id128_is_null(arg_machine_id)); - return mkdir_one(root, SD_ID128_TO_STRING(arg_machine_id)); + assert(arg_entry_token); + return mkdir_one(root, arg_entry_token); } -static int install_machine_info_config(void) { - _cleanup_free_ char *contents = NULL; - size_t length; - bool need_install_layout = true, need_machine_id; +static int install_entry_token(void) { int r; - assert(arg_make_machine_id_directory >= 0); + assert(arg_make_entry_directory >= 0); + assert(arg_entry_token); - /* We only want to save the machine-id if we created any directories using it. */ - need_machine_id = arg_make_machine_id_directory; + /* Let's save the used entry token in /etc/kernel/entry-token if we used it to create the entry + * directory, or if anything else but the machine ID */ - _cleanup_fclose_ FILE *orig = fopen("/etc/machine-info", "re"); - if (!orig && errno != ENOENT) - return log_error_errno(errno, "Failed to open /etc/machine-info: %m"); + if (!arg_make_entry_directory && arg_entry_token_type == ARG_ENTRY_TOKEN_MACHINE_ID) + return 0; - if (orig) { - _cleanup_free_ char *install_layout = NULL, *machine_id = NULL; - - r = parse_env_file(orig, "/etc/machine-info", - "KERNEL_INSTALL_LAYOUT", &install_layout, - "KERNEL_INSTALL_MACHINE_ID", &machine_id); - if (r < 0) - return log_error_errno(r, "Failed to parse /etc/machine-info: %m"); - - rewind(orig); - - if (!isempty(install_layout)) - need_install_layout = false; - - if (!isempty(machine_id)) - need_machine_id = false; - - if (!need_install_layout && !need_machine_id) { - log_debug("/etc/machine-info already has KERNEL_INSTALL_MACHINE_ID=%s and KERNEL_INSTALL_LAYOUT=%s.", - machine_id, install_layout); - return 0; - } - - r = read_full_stream(orig, &contents, &length); - if (r < 0) - return log_error_errno(r, "Failed to read /etc/machine-info: %m"); - } - - _cleanup_(unlink_and_freep) char *dst_tmp = NULL; - _cleanup_fclose_ FILE *dst = NULL; - r = fopen_temporary_label("/etc/machine-info", /* The path for which to the look up the label */ - "/etc/machine-info", /* Where we want the file actually to end up */ - &dst, /* The temporary file we write to */ - &dst_tmp); + r = write_string_file("/etc/kernel/entry-token", arg_entry_token, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755); if (r < 0) - return log_debug_errno(r, "Failed to open temporary copy of /etc/machine-info: %m"); + return log_error_errno(r, "Failed to write entry token '%s' to /etc/kernel/entry-token", arg_entry_token); - if (contents) - fwrite_unlocked(contents, 1, length, dst); - - bool no_newline = !contents || contents[length - 1] == '\n'; - - if (need_install_layout) { - const char *line = "\nKERNEL_INSTALL_LAYOUT=bls\n" + no_newline; - fwrite_unlocked(line, 1, strlen(line), dst); - no_newline = false; - } - - const char *mid_string = SD_ID128_TO_STRING(arg_machine_id); - if (need_machine_id) - fprintf(dst, "%sKERNEL_INSTALL_MACHINE_ID=%s\n", - no_newline ? "" : "\n", - mid_string); - - r = fflush_and_check(dst); - if (r < 0) - return log_error_errno(r, "Failed to write temporary copy of /etc/machine-info: %m"); - if (fchmod(fileno(dst), 0644) < 0) - return log_debug_errno(errno, "Failed to fchmod %s: %m", dst_tmp); - - if (rename(dst_tmp, "/etc/machine-info") < 0) - return log_error_errno(errno, "Failed to replace /etc/machine-info: %m"); - - log_info("%s /etc/machine-info with%s%s%s", - orig ? "Updated" : "Created", - need_install_layout ? " KERNEL_INSTALL_LAYOUT=bls" : "", - need_machine_id ? " KERNEL_INSTALL_MACHINE_ID=" : "", - need_machine_id ? mid_string : ""); return 0; } @@ -1311,8 +1355,10 @@ static int help(int argc, char *argv[], void *userdata) { " --no-pager Do not pipe output into a pager\n" " --graceful Don't fail when the ESP cannot be found or EFI\n" " variables cannot be written\n" - " --make-machine-id-directory=yes|no|auto\n" - " Create $BOOT/$MACHINE_ID\n" + " --make-entry-directory=yes|no|auto\n" + " Create $BOOT/ENTRY-TOKEN/ directory\n" + " --entry-token=machine-id|os-id|os-image-id|auto|literal:…\n" + " Entry token to use for this installation\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -1332,7 +1378,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_VARIABLES, ARG_NO_PAGER, ARG_GRACEFUL, - ARG_MAKE_MACHINE_ID_DIRECTORY, + ARG_MAKE_ENTRY_DIRECTORY, + ARG_ENTRY_TOKEN, }; static const struct option options[] = { @@ -1347,7 +1394,9 @@ static int parse_argv(int argc, char *argv[]) { { "no-variables", no_argument, NULL, ARG_NO_VARIABLES }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "graceful", no_argument, NULL, ARG_GRACEFUL }, - { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_MACHINE_ID_DIRECTORY }, + { "make-entry-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, + { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_ENTRY_DIRECTORY }, /* Compatibility alias */ + { "entry-token", required_argument, NULL, ARG_ENTRY_TOKEN }, {} }; @@ -1405,14 +1454,40 @@ static int parse_argv(int argc, char *argv[]) { arg_graceful = true; break; - case ARG_MAKE_MACHINE_ID_DIRECTORY: - if (streq(optarg, "auto")) /* retained for backwards compatibility */ - arg_make_machine_id_directory = -1; /* yes if machine-id is permanent */ - else { - r = parse_boolean_argument("--make-machine-id-directory=", optarg, &b); + case ARG_ENTRY_TOKEN: { + const char *e; + + if (streq(optarg, "machine-id")) { + arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID; + arg_entry_token = mfree(arg_entry_token); + } else if (streq(optarg, "os-image-id")) { + arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID; + arg_entry_token = mfree(arg_entry_token); + } else if (streq(optarg, "os-id")) { + arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID; + arg_entry_token = mfree(arg_entry_token); + } else if ((e = startswith(optarg, "literal:"))) { + arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL; + + r = free_and_strdup_warn(&arg_entry_token, e); if (r < 0) return r; - arg_make_machine_id_directory = b; + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Unexpected parameter for --entry-token=: %s", optarg); + + break; + } + + case ARG_MAKE_ENTRY_DIRECTORY: + if (streq(optarg, "auto")) /* retained for backwards compatibility */ + arg_make_entry_directory = -1; /* yes if machine-id is permanent */ + else { + r = parse_boolean_argument("--make-entry-directory=", optarg, &b); + if (r < 0) + return r; + + arg_make_entry_directory = b; } break; @@ -1881,7 +1956,7 @@ static int verb_install(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = settle_install_machine_id(); + r = settle_make_entry_directory(); if (r < 0) return r; @@ -1908,11 +1983,11 @@ static int verb_install(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = install_machine_id_directory(arg_dollar_boot_path()); + r = install_entry_directory(arg_dollar_boot_path()); if (r < 0) return r; - r = install_machine_info_config(); + r = install_entry_token(); if (r < 0) return r; @@ -1945,7 +2020,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = settle_install_machine_id(); + r = settle_make_entry_directory(); if (r < 0) return r; @@ -1967,7 +2042,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) { if (q < 0 && r >= 0) r = q; - q = remove_machine_id_directory(arg_esp_path); + q = remove_entry_directory(arg_esp_path); if (q < 0 && r >= 0) r = 1; @@ -1977,7 +2052,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) { if (q < 0 && r >= 0) r = q; - q = remove_machine_id_directory(arg_xbootldr_path); + q = remove_entry_directory(arg_xbootldr_path); if (q < 0 && r >= 0) r = q; } From 5e9c57d2e23f82ea9c6acdbd698d99b8914a6f0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Feb 2022 17:59:36 +0100 Subject: [PATCH 8/8] NEWS: add NEWS entry highlighting what the "entry-token" logic means for "gold image" builders --- NEWS | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 77f0e76ba3..1dfa06a0d7 100644 --- a/NEWS +++ b/NEWS @@ -21,13 +21,42 @@ CHANGES WITH 251: for breaking backward compatibility instead, as nobody should be affected, given the state of the current interface. - * Service monitor environment variables will only be passed to OnFailure=/OnSuccess= - handlers if exactly one unit lists the handler unit as OnFailure=/OnSuccess=. - Therefore, $MONITOR_METADATA is no longer used, and instead separate - variables are used: $MONITOR_SERVICE_RESULT, $MONITOR_EXIT_CODE, - $MONITOR_EXIT_STATUS, $MONITOR_INVOCATION_ID and $MONITOR_UNIT. - For cases when a single handler needs to watch multiple units, use a - templated handler. + * Service monitor environment variables will only be passed to + OnFailure=/OnSuccess= handlers if exactly one unit lists the handler + unit as OnFailure=/OnSuccess=. Therefore, $MONITOR_METADATA is no + longer used, and instead separate variables are used: + $MONITOR_SERVICE_RESULT, $MONITOR_EXIT_CODE, $MONITOR_EXIT_STATUS, + $MONITOR_INVOCATION_ID and $MONITOR_UNIT. For cases when a single + handler needs to watch multiple units, use a templated handler. + + * kernel-install's and bootctl's Boot Loader Specification Type #1 + entry generation logic has been reworked. The user may now pick + explicitly by which "token" string to name the installation's boot + entries, through the new /etc/kernel/entry-token file or the new + --entry-token= switch to bootctl. By default — as before — the + entries are named after the local machine ID. However, in "golden + image" environments, where the machine ID shall be initialized on + first boot (as opposed to at installation time before first boot) the + machine ID is not be available at build time to name the entry + after. In this case the the --entry-token= switch to bootctl (or the + /etc/kernel/entry-token file) may be used to override the "token" to + identify the entry by, and use another ID, for example the IMAGE_ID= + or ID= fields from /etc/os-release. This will make the OS images + independent of any machine ID, and ensure that the images will not + carry any identifiable information before first boot, but on the + other hand means that multiple parallel installations of the very + same image on the same disk cannot be supported. Summary: if you are + building golden images that shall acquire identity information + exclusively on first boot, make sure to both remove /etc/machine-id + *and* to write /etc/kernel/entry-token to the value of the IMAGE_ID + or ID field of /etc/os-release or another suitable identifier before + deploying the image. + + * The --make-machine-id-directory= switch to bootctl has been replaced + by --make-entry-directory=, given that the entry directory is not + necessarily named after the machine ID, but after some other suitable + ID as selected via --entry-token= described above. The old name of + the option is still understood to maximize compatibility. * Services with Restart=always and a failing ExecCondition= will no longer be restarted, to bring ExecCondition= in line with Condition*= settings.