diff --git a/NEWS b/NEWS index f61262fd57..305bdf9f10 100644 --- a/NEWS +++ b/NEWS @@ -1957,12 +1957,14 @@ CHANGES WITH 234: systemd-logind to be safe. See https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101.) - * All kernel install plugins are called with the environment variable + * All kernel-install plugins are called with the environment variable KERNEL_INSTALL_MACHINE_ID which is set to the machine ID given by - /etc/machine-id. If the file is missing or empty, the variable is - empty and BOOT_DIR_ABS is the path of a temporary directory which is - removed after all the plugins exit. So, if KERNEL_INSTALL_MACHINE_ID - is empty, all plugins should not put anything in BOOT_DIR_ABS. + /etc/machine-id. If the machine ID could not be determined, + $KERNEL_INSTALL_MACHINE_ID will be empty. Plugins should not put + anything in the entry directory (passed as the second argument) if + $KERNEL_INSTALL_MACHINE_ID is empty. For backwards compatiblity, a + temporary directory is passed as the entry directory and removed + after all the plugins exit. Contributions from: Adrian Heine né Lang, Aggelos Avgerinos, Alexander Kurtz, Alexandros Frantzis, Alexey Brodkin, Alex Lu, Amir Pakdel, Amir diff --git a/man/kernel-install.xml b/man/kernel-install.xml index 50e1320105..965c43e465 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -6,7 +6,8 @@ SPDX-License-Identifier: LGPL-2.1+ --> - + kernel-install @@ -27,6 +28,7 @@ kernel-install COMMAND + OPTIONS KERNEL-VERSION KERNEL-IMAGE INITRD-FILE @@ -35,9 +37,9 @@ Description - - kernel-install is used to install and remove kernel and - initramfs images to and from /boot. + kernel-install is used to install and remove kernel and initramfs images to and + from the boot loader partition, referred to as $BOOT here. It will usually be one of + /boot, /efi, or /boot/efi, see below. kernel-install will execute the files @@ -65,17 +67,20 @@ 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 creates the directory - /boot/MACHINE-ID/KERNEL-VERSION/ - and calls the executables from /usr/lib/kernel/install.d/*.install and + arguments. kernel-install calls the executables from + /usr/lib/kernel/install.d/*.install and /etc/kernel/install.d/*.install with the following arguments: - add KERNEL-VERSION /boot/MACHINE-ID/KERNEL-VERSION/ KERNEL-IMAGE [INITRD-FILE ...] + add KERNEL-VERSION $BOOT/MACHINE-ID/KERNEL-VERSION/ KERNEL-IMAGE [INITRD-FILE ...] - Two default plugins execute the following operations in this case: + Three default plugins execute the following operations in this case: + 00-entry-directory.install creates the directory + $BOOT/MACHINE-ID/KERNEL-VERSION/ + if $BOOT/MACHINE-ID/ already exists. + 50-depmod.install runs depmod8 for the @@ -83,16 +88,20 @@ 90-loaderentry.install copies KERNEL-IMAGE to - /boot/MACHINE-ID/KERNEL-VERSION/linux. + $BOOT/MACHINE-ID/KERNEL-VERSION/linux. If an INITRD-FILE is provided, it also copies INITRD-FILE to - /boot/MACHINE-ID/KERNEL_VERSION/INITRD-FILE. + $BOOT/MACHINE-ID/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. + $BOOT/loader/entries/MACHINE-ID-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. + missing), or "Linux KERNEL-VERSION", if unset. + + If the entry directory + $BOOT/MACHINE-ID/KERNEL-VERSION/ + does not exist, this plugin does nothing. @@ -103,11 +112,11 @@ /usr/lib/kernel/install.d/*.install and /etc/kernel/install.d/*.install with the following arguments: - remove KERNEL-VERSION /boot/MACHINE-ID/KERNEL-VERSION/ + remove KERNEL-VERSION $BOOT/MACHINE-ID/KERNEL-VERSION/ Afterwards, kernel-install removes the directory - /boot/MACHINE-ID/KERNEL-VERSION/ + $BOOT/MACHINE-ID/KERNEL-VERSION/ and its contents. Two default plugins execute the following operations in this case: @@ -117,14 +126,46 @@ 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. + $BOOT/loader/entries/MACHINE-ID-KERNEL-VERSION.conf. + + + The <varname>$BOOT</varname> partition + 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. + + + + Options + The following options are understood: + + + + + + + Output additional information about operations being performed. + + + + + + + + + Environment variables + If is used, $KERNEL_INSTALL_VERBOSE=1 will be set for + the plugins. They may output additional logs in this case. @@ -162,7 +203,7 @@ Read by 90-loaderentry.install. If this file exists a numeric value is read from it and the naming of the generated entry file is slightly altered to include it as - /boot/loader/entries/MACHINE-ID-KERNEL-VERSION+TRIES.conf. This + $BOOT/loader/entries/MACHINE-ID-KERNEL-VERSION+TRIES.conf. This is useful for boot loaders such as systemd-boot7 which implement boot attempt counting with a counter embedded in the entry file name. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index b5f4b8e5a3..381c234f3b 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -35,6 +35,7 @@ #include "pretty-print.h" #include "rm-rf.h" #include "stat-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "terminal-util.h" @@ -516,9 +517,9 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f } static int mkdir_one(const char *prefix, const char *suffix) { - char *p; + _cleanup_free_ char *p = NULL; - p = strjoina(prefix, "/", suffix); + p = path_join(prefix, suffix); if (mkdir(p, 0700) < 0) { if (errno != EEXIST) return log_error_errno(errno, "Failed to create \"%s\": %m", p); @@ -885,11 +886,10 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) { return 0; } -static int install_loader_config(const char *esp_path) { +static int install_loader_config(const char *esp_path, sd_id128_t machine_id) { char machine_string[SD_ID128_STRING_MAX]; _cleanup_(unlink_and_freep) char *t = NULL; _cleanup_fclose_ FILE *f = NULL; - sd_id128_t machine_id; const char *p; int r, fd; @@ -897,10 +897,6 @@ static int install_loader_config(const char *esp_path) { if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */ return 0; - r = sd_id128_get_machine(&machine_id); - if (r < 0) - return log_error_errno(r, "Failed to get machine id: %m"); - fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t); if (fd < 0) return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p); @@ -929,10 +925,21 @@ static int install_loader_config(const char *esp_path) { return 1; } -static int install_entries_directory(const char *dollar_boot_path) { +static int install_entries_directories(const char *dollar_boot_path, sd_id128_t machine_id) { + int r; + char buf[SD_ID128_STRING_MAX]; + assert(dollar_boot_path); - return mkdir_one(dollar_boot_path, "/loader/entries"); + /* Both /loader/entries and the entry directories themselves should be located on the same + * partition. Also create the parent directory for entry directories, so that kernel-install + * knows where to put them. */ + + r = mkdir_one(dollar_boot_path, "loader/entries"); + if (r < 0) + return r; + + return mkdir_one(dollar_boot_path, sd_id128_to_string(machine_id, buf)); } static int help(int argc, char *argv[], void *userdata) { @@ -1243,6 +1250,7 @@ static int verb_install(int argc, char *argv[], void *userdata) { sd_id128_t uuid = SD_ID128_NULL; uint64_t pstart = 0, psize = 0; uint32_t part = 0; + sd_id128_t machine_id; bool install; int r; @@ -1254,6 +1262,10 @@ static int verb_install(int argc, char *argv[], void *userdata) { if (r < 0) return r; + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return log_error_errno(r, "Failed to get machine id: %m"); + install = streq(argv[0], "install"); RUN_WITH_UMASK(0002) { @@ -1271,11 +1283,11 @@ static int verb_install(int argc, char *argv[], void *userdata) { return r; if (install) { - r = install_loader_config(arg_esp_path); + r = install_loader_config(arg_esp_path, machine_id); if (r < 0) return r; - r = install_entries_directory(arg_dollar_boot_path()); + r = install_entries_directories(arg_dollar_boot_path(), machine_id); if (r < 0) return r; } @@ -1400,7 +1412,7 @@ static int run(int argc, char *argv[]) { log_parse_environment(); log_open(); - /* If we run in a container, automatically turn of EFI file system access */ + /* If we run in a container, automatically turn off EFI file system access */ if (detect_container() > 0) arg_touch_variables = false; diff --git a/src/kernel-install/00-entry-directory.install b/src/kernel-install/00-entry-directory.install new file mode 100644 index 0000000000..2aa8c58319 --- /dev/null +++ b/src/kernel-install/00-entry-directory.install @@ -0,0 +1,32 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +COMMAND="$1" +KERNEL_VERSION="$2" +ENTRY_DIR_ABS="$3" +KERNEL_IMAGE="$4" +INITRD_OPTIONS_START="5" + +if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then + exit 0 +fi + +if [[ $COMMAND != add ]]; then + exit 0 +fi + +# If the boot dir exists (e.g. $ESP/), +# create the entry directory ($ESP//). +# This is the only function of this plugin. +MACHINE_ID_DIR="${ENTRY_DIR_ABS%/*}" +if ! [ -d "$MACHINE_ID_DIR" ]; then + exit 0 +fi + +if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then + echo "+mkdir -v -p $ENTRY_DIR_ABS" + exec mkdir -v -p "$ENTRY_DIR_ABS" +else + exec mkdir -p "$ENTRY_DIR_ABS" +fi diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install index 88f550a486..268b6ce0a5 100644 --- a/src/kernel-install/50-depmod.install +++ b/src/kernel-install/50-depmod.install @@ -2,15 +2,25 @@ # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh -[[ $2 ]] || exit 1 +COMMAND="$1" +KERNEL_VERSION="$2" +ENTRY_DIR_ABS="$3" +KERNEL_IMAGE="$4" +INITRD_OPTIONS_START="5" -case "$1" in +[[ $KERNEL_VERSION ]] || exit 1 + +case "$COMMAND" in add) - [[ -d /lib/modules/"$2"/kernel ]] || exit 0 - exec depmod -a "$2" + [[ -d "/lib/modules/${KERNEL_VERSION}/kernel" ]] || exit 0 + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Running depmod -a ${KERNEL_VERSION}" + exec depmod -a "${KERNEL_VERSION}" ;; remove) - exec rm -f /lib/modules/"$2"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}} + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Removing /lib/modules/${KERNEL_VERSION}/modules.dep and associated files" + exec rm -f /lib/modules/"${KERNEL_VERSION}"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}} ;; *) exit 0 diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 75dd5a1b7d..2fb0f5207b 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -4,7 +4,7 @@ COMMAND="$1" KERNEL_VERSION="$2" -BOOT_DIR_ABS="$3" +ENTRY_DIR_ABS="$3" KERNEL_IMAGE="$4" INITRD_OPTIONS_START="5" @@ -12,14 +12,14 @@ if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then exit 0 fi -if ! [[ -d "$BOOT_DIR_ABS" ]]; then +if ! [[ -d "$ENTRY_DIR_ABS" ]]; then exit 0 fi MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID -BOOT_DIR="/$MACHINE_ID/$KERNEL_VERSION" -BOOT_ROOT=${BOOT_DIR_ABS%$BOOT_DIR} +ENTRY_DIR="/$MACHINE_ID/$KERNEL_VERSION" +BOOT_ROOT=${ENTRY_DIR_ABS%$ENTRY_DIR} if [[ $COMMAND == remove ]]; then rm -f "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" @@ -76,10 +76,10 @@ else LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" fi -cp "$KERNEL_IMAGE" "$BOOT_DIR_ABS/linux" && - chown root:root "$BOOT_DIR_ABS/linux" && - chmod 0644 "$BOOT_DIR_ABS/linux" || { - echo "Could not copy '$KERNEL_IMAGE to '$BOOT_DIR_ABS/linux'." >&2 +cp "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" && + chown root:root "$ENTRY_DIR_ABS/linux" && + chmod 0644 "$ENTRY_DIR_ABS/linux" || { + echo "Could not copy '$KERNEL_IMAGE to '$ENTRY_DIR_ABS/linux'." >&2 exit 1 } @@ -88,10 +88,12 @@ INITRD_OPTIONS=( "${@:${INITRD_OPTIONS_START}}" ) for initrd in "${INITRD_OPTIONS[@]}"; do if [[ -f "${initrd}" ]]; then initrd_basename="$(basename ${initrd})" - cp "${initrd}" "$BOOT_DIR_ABS/${initrd_basename}" && - chown root:root "$BOOT_DIR_ABS/${initrd_basename}" && - chmod 0644 "$BOOT_DIR_ABS/${initrd_basename}" || { - echo "Could not copy '${initrd}' to '$BOOT_DIR_ABS/${initrd_basename}'." >&2 + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Installing $ENTRY_DIR_ABS/${initrd_basename}" + cp "${initrd}" "$ENTRY_DIR_ABS/${initrd_basename}" && + chown root:root "$ENTRY_DIR_ABS/${initrd_basename}" && + chmod 0644 "$ENTRY_DIR_ABS/${initrd_basename}" || { + echo "Could not copy '${initrd}' to '$ENTRY_DIR_ABS/${initrd_basename}'." >&2 exit 1 } fi @@ -106,15 +108,17 @@ mkdir -p "${LOADER_ENTRY%/*}" || { exit 1 } +[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Creating $LOADER_ENTRY" { echo "title $PRETTY_NAME" echo "version $KERNEL_VERSION" echo "machine-id $MACHINE_ID" echo "options ${BOOT_OPTIONS[*]}" - echo "linux $BOOT_DIR/linux" + echo "linux $ENTRY_DIR/linux" for initrd in "${INITRD_OPTIONS[@]}"; do - [[ -f $BOOT_DIR_ABS/$(basename ${initrd}) ]] && \ - echo "initrd $BOOT_DIR/$(basename ${initrd})" + [[ -f $ENTRY_DIR_ABS/$(basename ${initrd}) ]] && \ + echo "initrd $ENTRY_DIR/$(basename ${initrd})" done : } > "$LOADER_ENTRY" || { diff --git a/src/kernel-install/kernel-install b/src/kernel-install/kernel-install index b85c7c557e..610959ba9f 100644 --- a/src/kernel-install/kernel-install +++ b/src/kernel-install/kernel-install @@ -5,7 +5,6 @@ # # This file is part of systemd. # -# # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or @@ -63,6 +62,13 @@ for i in "$@"; do fi done +KERNEL_INSTALL_VERBOSE=0 +if [ "$1" == "--verbose" -o "$1" == "-v" ]; then + shift + KERNEL_INSTALL_VERBOSE=1 +fi +export KERNEL_INSTALL_VERBOSE + if [[ "${0##*/}" == 'installkernel' ]]; then COMMAND='add' # make install doesn't pass any parameter wrt initrd handling @@ -86,20 +92,20 @@ if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then fi if ! [[ $MACHINE_ID ]]; then - BOOT_DIR_ABS=$(mktemp -d /tmp/kernel-install.XXXXX) || exit 1 - trap "rm -rf '$BOOT_DIR_ABS'" EXIT INT QUIT PIPE + ENTRY_DIR_ABS=$(mktemp -d /tmp/kernel-install.XXXXX) || exit 1 + trap "rm -rf '$ENTRY_DIR_ABS'" EXIT INT QUIT PIPE elif [[ -d /efi/loader/entries ]] || [[ -d /efi/$MACHINE_ID ]]; then - BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION" elif [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then - BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]]; then - BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION" elif mountpoint -q /efi; then - BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION" elif mountpoint -q /boot/efi; then - BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION" else - BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" + ENTRY_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION" fi export KERNEL_INSTALL_MACHINE_ID=$MACHINE_ID @@ -119,14 +125,11 @@ case $COMMAND in exit 1 fi - mkdir -p "$BOOT_DIR_ABS" || { - echo "Could not create boot directory '$BOOT_DIR_ABS'." >&2 - exit 1 - } - for f in "${PLUGINS[@]}"; do if [[ -x $f ]]; then - "$f" add "$KERNEL_VERSION" "$BOOT_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}" + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE ${INITRD_OPTIONS[@]}" + "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}" x=$? if [[ $x == $SKIP_REMAINING ]]; then ret=0 @@ -136,11 +139,11 @@ case $COMMAND in fi done - if ! [[ $MACHINE_ID ]] && ! rmdir "$BOOT_DIR_ABS"; then - echo "Warning: In kernel-install plugins, requiring BOOT_DIR_ABS to be preset is deprecated." >&2 - echo " All plugins should not put anything in BOOT_DIR_ABS if the environment" >&2 + if ! [[ $MACHINE_ID ]] && ! rmdir "$ENTRY_DIR_ABS"; then + echo "Warning: In kernel-install plugins, requiring ENTRY_DIR_ABS to be preset is deprecated." >&2 + echo " All plugins should not put anything in ENTRY_DIR_ABS if the environment" >&2 echo " variable KERNEL_INSTALL_MACHINE_ID is empty." >&2 - rm -rf "$BOOT_DIR_ABS" + rm -rf "$ENTRY_DIR_ABS" ((ret+=$?)) fi ;; @@ -148,7 +151,9 @@ case $COMMAND in remove) for f in "${PLUGINS[@]}"; do if [[ -x $f ]]; then - "$f" remove "$KERNEL_VERSION" "$BOOT_DIR_ABS" + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS" + "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS" x=$? if [[ $x == $SKIP_REMAINING ]]; then ret=0 @@ -158,7 +163,10 @@ case $COMMAND in fi done - rm -rf "$BOOT_DIR_ABS" + [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \ + echo "Removing $ENTRY_DIR_ABS" + + rm -rf "$ENTRY_DIR_ABS" ((ret+=$?)) ;; diff --git a/src/kernel-install/meson.build b/src/kernel-install/meson.build index c6e6f816d9..261c3aaae4 100644 --- a/src/kernel-install/meson.build +++ b/src/kernel-install/meson.build @@ -4,7 +4,8 @@ install_data('kernel-install', install_mode : 'rwxr-xr-x', install_dir : bindir) -install_data('50-depmod.install', +install_data('00-entry-directory.install', + '50-depmod.install', '90-loaderentry.install', install_mode : 'rwxr-xr-x', install_dir : kernelinstalldir) diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index ce71a7ef60..c602e036eb 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -244,6 +244,9 @@ static int guess_type(const char **name, bool *is_usr, bool *is_collection, cons if (path_equal(n, "udev/rules.d")) ext = ".rules"; + if (path_equal(n, "kernel/install.d")) + ext = ".install"; + if (PATH_IN_SET(n, "systemd/system-preset", "systemd/user-preset")) { coll = true; ext = ".preset";