|
| 1 | +# Copyright 2020 Gentoo Authors |
| 2 | +# Distributed under the terms of the GNU General Public License v2 |
| 3 | + |
| 4 | +# @ECLASS: kernel-install.eclass |
| 5 | +# @MAINTAINER: |
| 6 | +# Distribution Kernel Project <[email protected]> |
| 7 | +# @AUTHOR: |
| 8 | +# Michał Górny <[email protected]> |
| 9 | +# @SUPPORTED_EAPIS: 7 |
| 10 | +# @BLURB: Installation mechanics for Distribution Kernels |
| 11 | +# @DESCRIPTION: |
| 12 | +# This eclass provides the logic needed to test and install different |
| 13 | +# kinds of Distribution Kernel packages, including both kernels built |
| 14 | +# from source and distributed as binaries. The eclass relies on the |
| 15 | +# ebuild installing a subset of built kernel tree into |
| 16 | +# /usr/src/linux-${PV} containing the kernel image in its standard |
| 17 | +# location and System.map. |
| 18 | +# |
| 19 | +# The eclass exports src_test, pkg_postinst and pkg_postrm. |
| 20 | +# Additionally, the inherited mount-boot eclass exports pkg_pretend. |
| 21 | +# It also stubs out pkg_preinst and pkg_prerm defined by mount-boot. |
| 22 | + |
| 23 | +if [[ ! ${_KERNEL_INSTALL_ECLASS} ]]; then |
| 24 | + |
| 25 | +case "${EAPI:-0}" in |
| 26 | + 0|1|2|3|4|5|6) |
| 27 | + die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" |
| 28 | + ;; |
| 29 | + 7) |
| 30 | + ;; |
| 31 | + *) |
| 32 | + die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" |
| 33 | + ;; |
| 34 | +esac |
| 35 | + |
| 36 | +inherit mount-boot |
| 37 | + |
| 38 | +TCL_VER=10.1 |
| 39 | +SRC_URI+=" |
| 40 | + test? ( |
| 41 | + amd64? ( |
| 42 | + https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-amd64.qcow2 |
| 43 | + ) |
| 44 | + x86? ( |
| 45 | + https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-x86.qcow2 |
| 46 | + ) |
| 47 | + )" |
| 48 | + |
| 49 | +SLOT="${PV}" |
| 50 | +IUSE="+initramfs test" |
| 51 | +RESTRICT+=" !test? ( test ) test? ( userpriv )" |
| 52 | + |
| 53 | +# install-DEPEND actually |
| 54 | +# note: we need installkernel with initramfs support! |
| 55 | +RDEPEND=" |
| 56 | + || ( |
| 57 | + sys-kernel/installkernel-gentoo |
| 58 | + sys-kernel/installkernel-systemd-boot |
| 59 | + ) |
| 60 | + initramfs? ( >=sys-kernel/dracut-049-r3 )" |
| 61 | +BDEPEND=" |
| 62 | + test? ( |
| 63 | + dev-tcltk/expect |
| 64 | + sys-kernel/dracut |
| 65 | + amd64? ( app-emulation/qemu[qemu_softmmu_targets_x86_64] ) |
| 66 | + x86? ( app-emulation/qemu[qemu_softmmu_targets_i386] ) |
| 67 | + )" |
| 68 | + |
| 69 | +# @FUNCTION: kernel-install_build_initramfs |
| 70 | +# @USAGE: <output> <version> |
| 71 | +# @DESCRIPTION: |
| 72 | +# Build an initramfs for the kernel. <output> specifies the absolute |
| 73 | +# path where initramfs will be created, while <version> specifies |
| 74 | +# the kernel version, used to find modules. |
| 75 | +kernel-install_build_initramfs() { |
| 76 | + debug-print-function ${FUNCNAME} "${@}" |
| 77 | + |
| 78 | + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" |
| 79 | + local output=${1} |
| 80 | + local version=${2} |
| 81 | + |
| 82 | + ebegin "Building initramfs via dracut" |
| 83 | + dracut --force "${output}" "${version}" |
| 84 | + eend ${?} || die "Building initramfs failed" |
| 85 | +} |
| 86 | + |
| 87 | +# @FUNCTION: kernel-install_get_image_path |
| 88 | +# @DESCRIPTION: |
| 89 | +# Get relative kernel image path specific to the current ${ARCH}. |
| 90 | +kernel-install_get_image_path() { |
| 91 | + case ${ARCH} in |
| 92 | + amd64|x86) |
| 93 | + echo arch/x86/boot/bzImage |
| 94 | + ;; |
| 95 | + *) |
| 96 | + die "${FUNCNAME}: unsupported ARCH=${ARCH}" |
| 97 | + ;; |
| 98 | + esac |
| 99 | +} |
| 100 | + |
| 101 | +# @FUNCTION: kernel-install_install_kernel |
| 102 | +# @USAGE: <version> <image> <system.map> |
| 103 | +# @DESCRIPTION: |
| 104 | +# Install kernel using installkernel tool. <version> specifies |
| 105 | +# the kernel version, <image> full path to the image, <system.map> |
| 106 | +# full path to System.map. |
| 107 | +kernel-install_install_kernel() { |
| 108 | + debug-print-function ${FUNCNAME} "${@}" |
| 109 | + |
| 110 | + [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments" |
| 111 | + local version=${1} |
| 112 | + local image=${2} |
| 113 | + local map=${3} |
| 114 | + |
| 115 | + ebegin "Installing the kernel via installkernel" |
| 116 | + # note: .config is taken relatively to System.map; |
| 117 | + # initrd relatively to bzImage |
| 118 | + installkernel "${version}" "${image}" "${map}" |
| 119 | + eend ${?} || die "Installing the kernel failed" |
| 120 | +} |
| 121 | + |
| 122 | +# @FUNCTION: kernel-install_update_symlink |
| 123 | +# @USAGE: <target> <version> |
| 124 | +# @DESCRIPTION: |
| 125 | +# Update the kernel source symlink at <target> (full path) with a link |
| 126 | +# to <target>-<version> if it's either missing or pointing out to |
| 127 | +# an older version of this package. |
| 128 | +kernel-install_update_symlink() { |
| 129 | + debug-print-function ${FUNCNAME} "${@}" |
| 130 | + |
| 131 | + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" |
| 132 | + local target=${1} |
| 133 | + local version=${2} |
| 134 | + |
| 135 | + if [[ ! -e ${target} ]]; then |
| 136 | + ebegin "Creating ${target} symlink" |
| 137 | + ln -f -n -s "${target##*/}-${version}" "${target}" |
| 138 | + eend ${?} |
| 139 | + else |
| 140 | + local symlink_target=$(readlink "${target}") |
| 141 | + local symlink_ver=${symlink_target#${target##*/}-} |
| 142 | + if [[ ${symlink_target} == ${target##*/}-* && \ |
| 143 | + -z ${symlink_ver//[0-9.]/} ]] |
| 144 | + then |
| 145 | + local symlink_pkg=${CATEGORY}/${PN}-${symlink_ver} |
| 146 | + # if the current target is either being replaced, or still |
| 147 | + # installed (probably depclean candidate), update the symlink |
| 148 | + if has "${symlink_ver}" ${REPLACING_VERSIONS} || |
| 149 | + has_version -r "~${symlink_pkg}" |
| 150 | + then |
| 151 | + ebegin "Updating ${target} symlink" |
| 152 | + ln -f -n -s "${target##*/}-${version}" "${target}" |
| 153 | + eend ${?} |
| 154 | + fi |
| 155 | + fi |
| 156 | + fi |
| 157 | +} |
| 158 | + |
| 159 | +# @FUNCTION: kernel-install_get_qemu_arch |
| 160 | +# @DESCRIPTION: |
| 161 | +# Get appropriate qemu suffix for the current ${ARCH}. |
| 162 | +kernel-install_get_qemu_arch() { |
| 163 | + debug-print-function ${FUNCNAME} "${@}" |
| 164 | + |
| 165 | + case ${ARCH} in |
| 166 | + amd64) |
| 167 | + echo x86_64 |
| 168 | + ;; |
| 169 | + x86) |
| 170 | + echo i386 |
| 171 | + ;; |
| 172 | + *) |
| 173 | + die "${FUNCNAME}: unsupported ARCH=${ARCH}" |
| 174 | + ;; |
| 175 | + esac |
| 176 | +} |
| 177 | + |
| 178 | +# @FUNCTION: kernel-install_test |
| 179 | +# @USAGE: <version> <image> <modules> |
| 180 | +# @DESCRIPTION: |
| 181 | +# Test that the kernel can successfully boot a minimal system image |
| 182 | +# in qemu. <version> is the kernel version, <image> path to the image, |
| 183 | +# <modules> path to module tree. |
| 184 | +kernel-install_test() { |
| 185 | + debug-print-function ${FUNCNAME} "${@}" |
| 186 | + |
| 187 | + [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments" |
| 188 | + local version=${1} |
| 189 | + local image=${2} |
| 190 | + local modules=${3} |
| 191 | + |
| 192 | + local qemu_arch=$(kernel-install_get_qemu_arch) |
| 193 | + |
| 194 | + dracut \ |
| 195 | + --conf /dev/null \ |
| 196 | + --confdir /dev/null \ |
| 197 | + --no-hostonly \ |
| 198 | + --kmoddir "${modules}" \ |
| 199 | + "${T}/initrd" "${version}" || die |
| 200 | + # get a read-write copy of the disk image |
| 201 | + cp "${DISTDIR}/tinycorelinux-${TCL_VER}-${ARCH}.qcow2" \ |
| 202 | + "${T}/fs.qcow2" || die |
| 203 | + |
| 204 | + cd "${T}" || die |
| 205 | + cat > run.sh <<-EOF || die |
| 206 | + #!/bin/sh |
| 207 | + exec qemu-system-${qemu_arch} \ |
| 208 | + -m 256M \ |
| 209 | + -display none \ |
| 210 | + -no-reboot \ |
| 211 | + -kernel '${image}' \ |
| 212 | + -initrd '${T}/initrd' \ |
| 213 | + -serial mon:stdio \ |
| 214 | + -hda '${T}/fs.qcow2' \ |
| 215 | + -append 'root=/dev/sda console=ttyS0,115200n8' |
| 216 | + EOF |
| 217 | + chmod +x run.sh || die |
| 218 | + # TODO: initramfs does not let core finish starting on some systems, |
| 219 | + # figure out how to make it better at that |
| 220 | + expect - <<-EOF || die "Booting kernel failed" |
| 221 | + set timeout 900 |
| 222 | + spawn ./run.sh |
| 223 | + expect { |
| 224 | + "Kernel panic" { |
| 225 | + send_error "\n* Kernel panic" |
| 226 | + exit 1 |
| 227 | + } |
| 228 | + "Entering emergency mode" { |
| 229 | + send_error "\n* Initramfs failed to start the system" |
| 230 | + exit 1 |
| 231 | + } |
| 232 | + "Core 10.1" { |
| 233 | + send_error "\n* Booted successfully" |
| 234 | + exit 0 |
| 235 | + } |
| 236 | + timeout { |
| 237 | + send_error "\n* Kernel boot timed out" |
| 238 | + exit 2 |
| 239 | + } |
| 240 | + } |
| 241 | + EOF |
| 242 | +} |
| 243 | + |
| 244 | +# @FUNCTION: kernel-install_src_test |
| 245 | +# @DESCRIPTION: |
| 246 | +# Boilerplate function to remind people to call the tests. |
| 247 | +kernel-install_src_test() { |
| 248 | + debug-print-function ${FUNCNAME} "${@}" |
| 249 | + |
| 250 | + die "Please redefine src_test() and call kernel-install_test()." |
| 251 | +} |
| 252 | + |
| 253 | +# @FUNCTION: kernel-install_pkg_preinst |
| 254 | +# @DESCRIPTION: |
| 255 | +# Stub out mount-boot.eclass. |
| 256 | +kernel-install_pkg_preinst() { |
| 257 | + debug-print-function ${FUNCNAME} "${@}" |
| 258 | + |
| 259 | + # (no-op) |
| 260 | +} |
| 261 | + |
| 262 | +# @FUNCTION: kernel-install_pkg_postinst |
| 263 | +# @DESCRIPTION: |
| 264 | +# Build an initramfs for the kernel, install it and update |
| 265 | +# the /usr/src/linux symlink. |
| 266 | +kernel-install_pkg_postinst() { |
| 267 | + debug-print-function ${FUNCNAME} "${@}" |
| 268 | + |
| 269 | + if [[ -z ${ROOT} ]]; then |
| 270 | + mount-boot_pkg_preinst |
| 271 | + |
| 272 | + if use initramfs; then |
| 273 | + # putting it alongside kernel image as 'initrd' makes |
| 274 | + # kernel-install happier |
| 275 | + kernel-install_build_initramfs \ |
| 276 | + "${EROOT}/usr/src/linux-${PV}/initrd" "${PV}" |
| 277 | + fi |
| 278 | + |
| 279 | + kernel-install_install_kernel "${PV}" \ |
| 280 | + "${EROOT}/usr/src/linux-${PV}/$(kernel-install_get_image_path)" \ |
| 281 | + "${EROOT}/usr/src/linux-${PV}/System.map" |
| 282 | + fi |
| 283 | + |
| 284 | + kernel-install_update_symlink "${EROOT}/usr/src/linux" "${PV}" |
| 285 | +} |
| 286 | + |
| 287 | +# @FUNCTION: kernel-install_pkg_prerm |
| 288 | +# @DESCRIPTION: |
| 289 | +# Stub out mount-boot.eclass. |
| 290 | +kernel-install_pkg_prerm() { |
| 291 | + debug-print-function ${FUNCNAME} "${@}" |
| 292 | + |
| 293 | + # (no-op) |
| 294 | +} |
| 295 | + |
| 296 | +# @FUNCTION: kernel-install_pkg_postrm |
| 297 | +# @DESCRIPTION: |
| 298 | +# No-op at the moment. Will be used to remove obsolete kernels |
| 299 | +# in the future. |
| 300 | +kernel-install_pkg_postrm() { |
| 301 | + debug-print-function ${FUNCNAME} "${@}" |
| 302 | + |
| 303 | + # (no-op at the moment) |
| 304 | +} |
| 305 | + |
| 306 | +_KERNEL_INSTALL_ECLASS=1 |
| 307 | +fi |
| 308 | + |
| 309 | +EXPORT_FUNCTIONS src_test pkg_preinst pkg_postinst pkg_prerm pkg_postrm |
0 commit comments