#!/bin/sh # # Copyright (C) 1995 - 1998, Ian A. Murdock # Copyright (C) 1998, 1999, Guy Maor # Copyright (C) 2002, Matthew Wilcox # Copyright (C) 2002, 2004, 2005, 2007, 2009 Clint Adams # Copyright (C) 2009 Manoj Srivasta # Copyright 2020-2024 Gentoo Authors # # Install the kernel on a Linux system. # # This script is called by the kernel's "make install" if it is installed as # /sbin/installkernel. It is also called by kernel-install.eclass. SYSTEMD_KERNEL_INSTALL="${SYSTEMD_KERNEL_INSTALL:=0}" if [ "${SYSTEMD_KERNEL_INSTALL}" = "1" ] && command -v kernel-install >/dev/null; then # If the ${0} of kernel-install is installkernel it takes its arguments # in the same way we do here. We could use "exec -a ${0} .. ${@}" for this, # but the -a argument is not POSIX, only bash. # TODO: maybe revisit this if we ever bashify the script. if [ ${#} -le 3 ] || [ "${4}" = "/boot" ]; then # kernel-install does not support relocation (ignores $4, see manual) exec kernel-install add --verbose "${1}" "${2}" else echo "WARNING: A custom installation directory is specified as fourth argument." echo "WARNING: Systemd kernel-install does not support this. Falling back" echo "WARNING: to legacy installkernel. SYSTEMD_KERNEL_INSTALL is ignored." fi fi set -e # Parse the command line options. Of course, powerpc has to be all # different, and passes in a fifth argument, just because it is # "special". We ignore the fifth argument, and do not flag is as an # error, which it would be for any arch apart from powerpc if [ ${#} -eq 3 ] || [ ${#} -eq 4 ] || [ ${#} -eq 5 ]; then ver="${1}" img="${2}" map="${3}" if [ ${#} -ge 4 ] && [ -n "${4}" ]; then dir="${4}" else dir="/boot" fi else echo "Usage: installkernel " exit 1 fi dropindirs_sort() { for d; do for i in "${d}/"*; do [ -e "${i}" ] && echo "${i##*/}" done done | sort -Vu | while read -r f; do for d; do if [ -e "${d}/${f}" ]; then [ -x "${d}/${f}" ] && echo "${d}/${f}" continue 2 fi done done } # Create backups of older versions before installing updatever() { oldsuffix="${3}.old" if [ "${3%.efi}" != "${3}" ]; then # Some UEFIs enforce .efi suffix, so if using efi files retain suffix oldsuffix="-old${3}" fi if [ -f "${dir}/${1}-${ver}${3}" ]; then # If they are hardlinked together, mv will fail. rm -f "${dir}/${1}-${ver}${oldsuffix}" mv "${dir}/${1}-${ver}${3}" "${dir}/${1}-${ver}${oldsuffix}" fi cat "${2}" >"${dir}/${1}-${ver}${3}" # Update static version-less symlink/copy if [ -f "${dir}/${1}${3}" ] || [ -L "${dir}/${1}${3}" ]; then # The presence of "${dir}/${1}${3}" is unusual in modern installations, and # the results are mostly unused. So only recreate them if they # already existed. if [ -L "${dir}/${1}${3}" ]; then # If we were using links, continue to use links, updating if # we need to. if [ "$(readlink -f "${dir}/${1}${3}")" = "${dir}/${1}-${ver}${3}" ]; then # Yup, we need to change ln -sf "${1}-${ver}${oldsuffix}" "${dir}/${1}${oldsuffix}" else # If they are hardlinked together, mv will fail. rm -f "${dir}/${1}${oldsuffix}" mv "${dir}/${1}${3}" "${dir}/${1}${oldsuffix}" fi ln -sf "${1}-${ver}${3}" "${dir}/${1}${3}" else # No links # If they are hardlinked together, mv will fail. rm -f "${dir}/${1}${oldsuffix}" mv "${dir}/${1}${3}" "${dir}/${1}${oldsuffix}" cat "${2}" >"${dir}/${1}${3}" fi fi } if [ -n "${INSTALLKERNEL_CONF_ROOT}" ]; then install_conf="${INSTALLKERNEL_CONF_ROOT}/install.conf" elif [ -f "/etc/kernel/install.conf" ]; then install_conf="/etc/kernel/install.conf" elif [ -f "/usr/lib/kernel/install.conf" ]; then install_conf="/usr/lib/kernel/install.conf" else install_conf= fi if [ -f "${install_conf}" ]; then echo "Reading ${install_conf}..." # shellcheck source=/dev/null . "${install_conf}" if [ -n "${layout}" ]; then echo "${install_conf} configures layout=${layout}" if [ -z "${INSTALLKERNEL_LAYOUT}" ]; then INSTALLKERNEL_LAYOUT="${layout}" fi fi if [ -n "${initrd_generator}" ]; then echo "${install_conf} configures initrd_generator=${initrd_generator}" if [ -z "${INSTALLKERNEL_INITRD_GENERATOR}" ]; then INSTALLKERNEL_INITRD_GENERATOR="${initrd_generator}" fi fi if [ -n "${uki_generator}" ]; then echo "${install_conf} configures uki_generator=${uki_generator}" if [ -z "${INSTALLKERNEL_UKI_GENERATOR}" ]; then INSTALLKERNEL_UKI_GENERATOR="${uki_generator}" fi fi fi export INSTALLKERNEL_LAYOUT export INSTALLKERNEL_INITRD_GENERATOR export INSTALLKERNEL_UKI_GENERATOR if [ -f /etc/os-release ]; then # shellcheck source=/dev/null . /etc/os-release elif [ -f /usr/lib/os-release ]; then # shellcheck source=/dev/null . /usr/lib/os-release fi # Set sane default if no or broken os-release export NAME="${NAME:=Linux}" export ID="${ID:=linux}" export PRETTY_NAME="${PRETTY_NAME:=Linux}" suffix= if [ "${INSTALLKERNEL_LAYOUT}" = efistub ]; then if [ ${#} -le 3 ] || [ "${4%/boot}" != "${4}" ]; then # Relocate to ESP for candidate in "${dir}/EFI" "${dir}/efi" "${dir}" "${dir%/boot}/efi"; do if [ -d "${candidate}/EFI/${NAME}" ]; then echo "Found vendor directory on ESP" dir=${candidate}/EFI/${NAME} suffix=.efi # backwards compatibility if [ -f "/boot/intel-uc.img" ]; then cp "/boot/intel-uc.img" "${dir}/intel-uc.img" fi if [ -f "/boot/amd-uc.img" ]; then cp "/boot/amd-uc.img" "${dir}/amd-uc.img" fi else continue fi done if [ "${dir}" = "/boot" ] || [ "${dir}" = "${4}" ]; then echo "layout=efistub set, but did not find vendor directory on ESP" echo "Please create the EFI/${NAME} directory on the EFI System partition manually" fi fi fi # If installing in the usual directory, run the same scripts that hook # into kernel package installation. Also make sure the PATH includes # /usr/sbin and /sbin, just as dpkg would. if [ ${#} -le 3 ] || [ "${4}" = "/boot" ]; then ( #shellcheck disable=SC2030 export LC_ALL=C PATH="${PATH}:/usr/sbin:/sbin" if [ -z "${INSTALLKERNEL_PREINST_PLUGINS}" ]; then INSTALLKERNEL_PREINST_PLUGINS="$( dropindirs_sort \ "/etc/kernel/preinst.d" \ "/usr/lib/kernel/preinst.d" )" fi for plugin in ${INSTALLKERNEL_PREINST_PLUGINS}; do echo "" echo "Running ${plugin} ${ver} ${img}..." echo "" "${plugin}" "${ver}" "${img}" echo "" echo "Hook ${plugin} finished successfully" echo "" done ) else echo "WARNING: A custom installation directory is specified as fourth argument." echo "WARNING: In this configuration running installation hooks is not supported." echo "WARNING: All pre-installation hooks are ignored." fi # use the same input path as /usr/lib/kernel/install.d/50-dracut.install # and the same output path as dracut and genkernel-4 for best interop base_dir=$(dirname "${img}") initrd=${base_dir}/initrd uki=${base_dir}/uki.efi if [ "${img%vmlinux*}" != "${img}" ]; then img_dest=vmlinux else img_dest=vmlinuz fi # If we found a uki.efi, install it instead of kernel+initrd if [ -f "${uki}" ] && [ "${INSTALLKERNEL_LAYOUT}" = uki ]; then suffix=.efi if [ ${#} -le 3 ] || [ "${4%/boot}" != "${4}" ]; then # Relocate to ESP for candidate in "${dir}/EFI" "${dir}/efi" "${dir}" "${dir%/boot}/efi"; do if [ -d "${candidate}/EFI/Linux" ]; then echo "Found UKI directory on ESP" dir=${candidate}/EFI/Linux img_dest=${ID} else continue fi done if [ "${dir}" = "/boot" ] || [ "${dir}" = "${4}" ]; then echo "layout=uki set, but did not find the UKI directory on ESP" echo "Please create the EFI/Linux directory on the EFI System partition manually" fi fi echo "Installing Unified Kernel Image for ${ver}..." updatever "${img_dest}" "${uki}" "${suffix}" else echo "Installing kernel image for ${ver}..." updatever "${img_dest}" "${img}" "${suffix}" if [ -f "${initrd}" ]; then echo "Installing initramfs image for ${ver}..." updatever initramfs "${initrd}" .img fi echo "Installing System.map for ${ver}..." updatever System.map "${map}" config=$(dirname "${map}") config="${config}/.config" if [ -f "${config}" ]; then echo "Installing config for ${ver}..." updatever config "${config}" fi fi # If installing in the usual directory, run the same scripts that hook # into kernel package installation. Also make sure the PATH includes # /usr/sbin and /sbin, just as dpkg would. if [ ${#} -le 3 ] || [ "${4}" = "/boot" ]; then ( #shellcheck disable=SC2031 export LC_ALL=C PATH="${PATH}:/usr/sbin:/sbin" if [ -z "${INSTALLKERNEL_POSTINST_PLUGINS}" ]; then INSTALLKERNEL_POSTINST_PLUGINS="$( dropindirs_sort \ "/etc/kernel/postinst.d" \ "/usr/lib/kernel/postinst.d" )" fi for plugin in ${INSTALLKERNEL_POSTINST_PLUGINS}; do echo "" echo "Running ${plugin} ${ver} ${dir}/${img_dest}-${ver}${suffix}..." echo "" "${plugin}" "${ver}" "${dir}/${img_dest}-${ver}${suffix}" echo "" echo "Hook ${plugin} finished successfully" echo "" done ) else echo "WARNING: A custom installation directory is specified as fourth argument." echo "WARNING: In this configuration running installation hooks is not supported." echo "WARNING: All post-installation hooks are ignored." fi exit 0