dev-python/josepy: 1.1.0 cleanup
[gentoo.git] / eclass / kernel-install.eclass
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 <dist-kernel@gentoo.org>
7 # @AUTHOR:
8 # Michał Górny <mgorny@gentoo.org>
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                 local image_path=$(kernel-install_get_image_path)
273                 if use initramfs; then
274                         # putting it alongside kernel image as 'initrd' makes
275                         # kernel-install happier
276                         kernel-install_build_initramfs \
277                                 "${EROOT}/usr/src/linux-${PV}/${image_path%/*}/initrd" \
278                                 "${PV}"
279                 fi
280
281                 kernel-install_install_kernel "${PV}" \
282                         "${EROOT}/usr/src/linux-${PV}/${image_path}" \
283                         "${EROOT}/usr/src/linux-${PV}/System.map"
284         fi
285
286         kernel-install_update_symlink "${EROOT}/usr/src/linux" "${PV}"
287 }
288
289 # @FUNCTION: kernel-install_pkg_prerm
290 # @DESCRIPTION:
291 # Stub out mount-boot.eclass.
292 kernel-install_pkg_prerm() {
293         debug-print-function ${FUNCNAME} "${@}"
294
295         # (no-op)
296 }
297
298 # @FUNCTION: kernel-install_pkg_postrm
299 # @DESCRIPTION:
300 # No-op at the moment.  Will be used to remove obsolete kernels
301 # in the future.
302 kernel-install_pkg_postrm() {
303         debug-print-function ${FUNCNAME} "${@}"
304
305         if [[ -z ${ROOT} ]] && use initramfs; then
306                 local image_path=$(kernel-install_get_image_path)
307                 ebegin "Removing initramfs"
308                 rm -f "${EROOT}/usr/src/linux-${PV}/${image_path%/*}/initrd" &&
309                         find "${EROOT}/usr/src/linux-${PV}" -depth -type d -empty -delete
310                 eend ${?}
311         fi
312 }
313
314 _KERNEL_INSTALL_ECLASS=1
315 fi
316
317 EXPORT_FUNCTIONS src_test pkg_preinst pkg_postinst pkg_prerm pkg_postrm