xref: /freebsd/sys/contrib/openzfs/scripts/kmodtool (revision 34f9f5680c9d5d5138e427ba3aeab0138cec3882)
1#!/usr/bin/env bash
2# SPDX-License-Identifier: MIT
3# shellcheck disable=SC2086,SC2295
4
5# kmodtool - Helper script for building kernel module RPMs
6# Copyright (c) 2003-2012 Ville Skyttä <ville.skytta@iki.fi>,
7#                         Thorsten Leemhuis <fedora@leemhuis.info>
8#                         Nicolas Chauvet <kwizart@gmail.com>
9#
10# Permission is hereby granted, free of charge, to any person obtaining
11# a copy of this software and associated documentation files (the
12# "Software"), to deal in the Software without restriction, including
13# without limitation the rights to use, copy, modify, merge, publish,
14# distribute, sublicense, and/or sell copies of the Software, and to
15# permit persons to whom the Software is furnished to do so, subject to
16# the following conditions:
17#
18# The above copyright notice and this permission notice shall be
19# included in all copies or substantial portions of the Software.
20#
21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29shopt -s extglob
30
31myprog="kmodtool-${repo}"
32myver="0.12.1"
33
34kmodname=
35build_kernels="current"
36kernels_known_variants=
37kernel_versions=
38kernel_versions_to_build_for=
39prefix=
40filterfile=
41target=
42buildroot=
43dashvariant=
44
45error_out()
46{
47	local errorlevel=${1}
48	shift
49	echo "Error: $*" >&2
50	# the next line is not multi-line safe -- not needed *yet*
51	echo "%global kmodtool_check echo \"kmodtool error: $*\"; exit ${errorlevel};"
52	exit "${errorlevel}"
53}
54
55print_rpmtemplate_header()
56{
57	echo
58	echo "%global kmodinstdir_prefix  ${prefix}/lib/modules/"
59	echo "%global kmodinstdir_postfix /extra/${kmodname}/"
60	echo "%global kernel_versions     ${kernel_versions}"
61	echo
62}
63
64print_akmodtemplate ()
65{
66	echo
67	cat <<EOF
68
69%global akmod_install mkdir -p \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/; \\\
70LANG=C rpmbuild --define "_sourcedir %{_sourcedir}" \\\
71--define "_srcrpmdir \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/" \\\
72-bs --nodeps %{_specdir}/%{name}.spec ; \\\
73ln -s \$(ls \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/) \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/${kmodname}-kmod.latest
74
75%package -n akmod-${kmodname}
76Summary:	Akmod package for ${kmodname} kernel module(s)
77Group: 		System Environment/Kernel
78Requires:   kmodtool
79Requires: 	akmods
80%{?AkmodsBuildRequires:Requires: %{AkmodsBuildRequires}}
81# same requires and provides as a kmods package would have
82Requires: 	${kmodname}-kmod-common >= %{?epoch:%{epoch}:}%{version}
83Provides: 	${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
84EOF
85
86	cat <<EOF
87
88%description -n akmod-${kmodname}
89This package provides the akmod package for the ${kmodname} kernel modules.
90
91%posttrans -n akmod-${kmodname}
92nohup ${prefix}/sbin/akmods --from-akmod-posttrans --akmod ${kmodname} &> /dev/null &
93
94%files -n akmod-${kmodname}
95%defattr(-,root,root,-)
96%{_usrsrc}/akmods/*
97
98EOF
99}
100
101print_akmodmeta ()
102{
103		cat <<EOF
104%package      -n kmod-${kmodname}
105Summary:         Metapackage which tracks in ${kmodname} kernel module for newest kernel${dashvariant}
106Group:           System Environment/Kernel
107
108Provides:        ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
109Provides:        kmod-${kmodname}-xen = %{?epoch:%{epoch}:}%{version}-%{release}
110Provides:        kmod-${kmodname}-smp = %{?epoch:%{epoch}:}%{version}-%{release}
111Provides:        kmod-${kmodname}-PAE = %{?epoch:%{epoch}:}%{version}-%{release}
112Requires:        akmod-${kmodname} = %{?epoch:%{epoch}:}%{version}-%{release}
113EOF
114
115cat <<EOF
116
117%description  -n kmod-${kmodname}${dashvariant}
118This is a meta-package without payload which sole purpose is to require the
119${kmodname} kernel module(s) for the newest kernel${dashvariant},
120to make sure you get it together with a new kernel.
121
122%files        -n kmod-${kmodname}${dashvariant}
123%defattr(644,root,root,755)
124EOF
125}
126
127print_rpmtemplate_per_kmodpkg ()
128{
129	if [[ "${1}" = "--custom" ]]; then
130		shift
131		local customkernel=true
132	elif [[ "${1}" = "--redhat" ]]; then
133		# this is needed for akmods
134		shift
135		local redhatkernel=true
136	fi
137
138	local kernel_uname_r=${1}
139	local kernel_variant="${2:+-${2}}"
140
141	# Detect depmod install location
142	local depmod_path=/sbin/depmod
143	if [[ ! -f "${depmod_path}" ]]; then
144		depmod_path=/usr/sbin/depmod
145	fi
146
147	# first part
148	cat <<EOF
149%package       -n kmod-${kmodname}-${kernel_uname_r}
150Summary:          ${kmodname} kernel module(s) for ${kernel_uname_r}
151Group:            System Environment/Kernel
152Provides:         kernel-modules-for-kernel = ${kernel_uname_r}
153Provides:         kmod-${kmodname}-uname-r = ${kernel_uname_r}
154Provides:         ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
155Requires:         ${kmodname}-kmod-common >= %{?epoch:%{epoch}:}%{version}
156
157%if 0%{?rhel} == 6 || 0%{?centos} == 6
158Requires(post):   module-init-tools
159Requires(postun): module-init-tools
160%else
161Requires(post):   kmod
162Requires(postun): kmod
163%endif
164EOF
165
166	# second part
167	if [[ -z "${customkernel}" ]]; then
168	     cat <<EOF
169Requires:         kernel-uname-r = ${kernel_uname_r}
170BuildRequires:	  kernel-devel-uname-r = ${kernel_uname_r}
171%{?KmodsRequires:Requires: %{KmodsRequires}-uname-r = ${kernel_uname_r}}
172%{?KmodsRequires:BuildRequires: %{KmodsRequires}-uname-r = ${kernel_uname_r}}
173%post          -n kmod-${kmodname}-${kernel_uname_r}
174if [[ -f "/boot/System.map-${kernel_uname_r}" ]]; then
175	${prefix}${depmod_path} -aeF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} > /dev/null || :
176elif [[ -f "/lib/modules/${kernel_uname_r}/System.map" ]]; then
177	${prefix}${depmod_path} -aeF /lib/modules/${kernel_uname_r}/System.map ${kernel_uname_r} > /dev/null || :
178else
179	${prefix}${depmod_path} -ae ${kernel_uname_r} &> /dev/null || :
180fi
181%postun        -n kmod-${kmodname}-${kernel_uname_r}
182if [[ -f "/boot/System.map-${kernel_uname_r}" ]]; then
183	${prefix}${depmod_path} -aF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} &> /dev/null || :
184elif [[ -f "/lib/modules/${kernel_uname_r}/System.map" ]]; then
185	${prefix}${depmod_path} -aF /lib/modules/${kernel_uname_r}/System.map ${kernel_uname_r} &> /dev/null || :
186else
187	${prefix}${depmod_path} -a ${kernel_uname_r} &> /dev/null || :
188fi
189
190EOF
191	else
192	  cat <<EOF
193%post          -n kmod-${kmodname}-${kernel_uname_r}
194[ "\$(uname -r)" = "${kernel_uname_r}"  ] && ${prefix}${depmod_path} -a > /dev/null || :
195%postun        -n kmod-${kmodname}-${kernel_uname_r}
196[ "\$(uname -r)" = "${kernel_uname_r}"  ] && ${prefix}${depmod_path} -a > /dev/null || :
197
198EOF
199	fi
200
201  # third part
202	cat <<EOF
203%description  -n kmod-${kmodname}-${kernel_uname_r}
204This package provides the ${kmodname} kernel modules built for the Linux
205kernel ${kernel_uname_r} for the %{_target_cpu} family of processors.
206%files        -n kmod-${kmodname}-${kernel_uname_r}
207%defattr(644,root,root,755)
208%dir $prefix/lib/modules/${kernel_uname_r}/extra
209${prefix}/lib/modules/${kernel_uname_r}/extra/${kmodname}/
210
211
212EOF
213}
214
215print_rpmtemplate_kmoddevelpkg ()
216{
217	if [[ "${1}" = "--custom" ]]; then
218		shift
219		local customkernel=true
220	elif [[ "${1}" = "--redhat" ]]; then
221		shift
222		local redhatkernel=true
223	fi
224
225	local kernel_uname_r=${1}
226
227	cat <<EOF
228%package       -n kmod-${kmodname}-devel
229Summary:          ${kmodname} kernel module(s) devel common
230Group:            System Environment/Kernel
231Provides:         ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
232EOF
233
234	if [[ -z "${customkernel}" ]] && [[ -z "${redhatkernel}" ]]; then
235		echo "Requires:        kmod-${kmodname}-devel-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release}"
236	fi
237
238	cat <<EOF
239%description  -n kmod-${kmodname}-devel
240This package provides the common header files to build kernel modules
241which depend on the ${kmodname} kernel module.  It may optionally require
242the ${kmodname}-devel-<kernel> objects for the newest kernel.
243
244%files        -n kmod-${kmodname}-devel
245%defattr(644,root,root,755)
246%{_usrsrc}/${kmodname}-%{version}
247EOF
248
249	for kernel in ${1}; do
250		local kernel_uname_r=${kernel}
251		echo "%exclude %{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r}"
252	done
253
254	echo
255	echo
256}
257
258print_rpmtemplate_per_kmoddevelpkg ()
259{
260	if [[ "${1}" = "--custom" ]]; then
261		shift
262		local customkernel=true
263	elif [[ "${1}" = "--redhat" ]]; then
264		# this is needed for akmods
265		shift
266		local redhatkernel=true
267	fi
268
269	local kernel_uname_r=${1}
270	local kernel_variant="${2:+-${2}}"
271
272	# first part
273	cat <<EOF
274%package       -n kmod-${kmodname}-devel-${kernel_uname_r}
275Summary:          ${kmodname} kernel module(s) devel for ${kernel_uname_r}
276Group:            System Environment/Kernel
277Provides:         kernel-objects-for-kernel = ${kernel_uname_r}
278Provides:         ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
279Provides:         kmod-${kmodname}-devel-uname-r = ${kernel_uname_r}
280EOF
281
282	# second part
283	if [[ -z "${customkernel}" ]]; then
284		cat <<EOF
285Requires:         kernel-devel-uname-r = ${kernel_uname_r}
286BuildRequires:    kernel-devel-uname-r = ${kernel_uname_r}
287%{?KmodsDevelRequires:Requires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}}
288%{?KmodsDevelRequires:BuildRequires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}}
289EOF
290	fi
291
292	# third part
293	cat <<EOF
294%description  -n kmod-${kmodname}-devel-${kernel_uname_r}
295This package provides objects and symbols required to build kernel modules
296which depend on the ${kmodname} kernel modules built for the Linux
297kernel ${kernel_uname_r} for the %{_target_cpu} family of processors.
298%files        -n kmod-${kmodname}-devel-${kernel_uname_r}
299%defattr(644,root,root,755)
300%{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r}
301EOF
302}
303
304print_rpmtemplate_kmodmetapkg ()
305{
306		local kernel_uname_r=${1}
307		local kernel_variant="${2:+-${2}}"
308
309		cat <<EOF
310%package      -n kmod-${kmodname}${kernel_variant}
311Summary:         Metapackage which tracks in ${kmodname} kernel module for newest kernel${kernel_variant}
312Group:           System Environment/Kernel
313
314Provides:        ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
315Requires:        kmod-${kmodname}-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release}
316%{?KmodsMetaRequires:Requires: %{?KmodsMetaRequires}}
317EOF
318
319		cat <<EOF
320
321%description  -n kmod-${kmodname}${kernel_variant}
322This is a meta-package without payload which sole purpose is to require the
323${kmodname} kernel module(s) for the newest kernel${kernel_variant}.
324to make sure you get it together with a new kernel.
325
326%files        -n kmod-${kmodname}${kernel_variant}
327%defattr(644,root,root,755)
328
329
330EOF
331}
332
333print_customrpmtemplate ()
334{
335	local first_kernel_custom=""
336	local first_kernel_redhat=""
337	local first_kernel_redhat_variant=""
338
339	for kernel in ${1}
340	do
341		if [[ -e "${prefix}/lib/modules/${kernel}/build/Makefile" ]]; then
342			kernel_versions="${kernel_versions}${kernel}___${prefix}/lib/modules/${kernel}/build/ "
343			print_rpmtemplate_per_kmodpkg --custom "${kernel}"
344
345			if [[ -n "${devel}" ]]; then
346				print_rpmtemplate_per_kmoddevelpkg --custom "${kernel}"
347			fi
348			[[ -z "${first_kernel_custom}" ]] && first_kernel_custom="${kernel}"
349		elif [[ -e "${buildroot}/usr/src/kernels/${kernel}" ]]; then
350			kernel_versions="${kernel_versions}${kernel}___${buildroot}%{_usrsrc}/kernels/${kernel} "
351
352			local kernel_verrelarch=${kernel%%${kernels_known_variants}}
353			print_rpmtemplate_per_kmodpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
354
355			if [[ -n "${devel}" ]]; then
356				print_rpmtemplate_per_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
357			fi
358			if [[ -z "${first_kernel_redhat}" ]]; then
359				first_kernel_redhat="${kernel}"
360				first_kernel_redhat_variant="${kernel##${kernel_verrelarch}}"
361			fi
362		else
363			error_out 2 "Don't know how to handle ${kernel} -- ${prefix}/lib/modules/${kernel}/build/Makefile not found"
364		fi
365	done
366
367	# Common devel package (only once, outside the per-kernel loop)
368	if [[ -n "${devel}" ]]; then
369		if [[ -n "${first_kernel_custom}" ]]; then
370			print_rpmtemplate_kmoddevelpkg --custom "${first_kernel_custom}"
371		elif [[ -n "${first_kernel_redhat}" ]]; then
372			print_rpmtemplate_kmoddevelpkg --redhat ${first_kernel_redhat} ${first_kernel_redhat_variant}
373		fi
374	fi
375
376	# well, it's no header anymore, but who cares ;-)
377	print_rpmtemplate_header
378}
379
380
381print_rpmtemplate ()
382{
383	# create kernel_versions var
384	for kernel_version in ${kernel_versions_to_build_for}
385	do
386		kernel_versions="${kernel_versions}${kernel_version}___%{_usrsrc}/kernels/${kernel_version} "
387	done
388
389	# and print it and some other required stuff as macro
390	print_rpmtemplate_header
391
392	local first_kernel=""
393	local first_kernel_variant=""
394
395	# now print the packages
396	for kernel in ${kernel_versions_to_build_for} ; do
397
398		local kernel_verrelarch=${kernel%%${kernels_known_variants}}
399
400		# create metapackage
401		print_rpmtemplate_kmodmetapkg "${kernel}" "${kernel##${kernel_verrelarch}}"
402
403		# create package
404		print_rpmtemplate_per_kmodpkg "${kernel}" "${kernel##${kernel_verrelarch}}"
405
406		if [[ -n "${devel}" ]]; then
407			# create per-kernel devel package
408			print_rpmtemplate_per_kmoddevelpkg "${kernel}" "${kernel##${kernel_verrelarch}}"
409		fi
410
411		if [[ -z "${first_kernel}" ]]; then
412			first_kernel="${kernel}"
413			first_kernel_variant="${kernel##${kernel_verrelarch}}"
414		fi
415	done
416
417	# Common devel package (only once, outside the per-kernel loop)
418	if [[ -n "${devel}" && -n "${first_kernel}" ]]; then
419		print_rpmtemplate_kmoddevelpkg "${first_kernel}" "${first_kernel_variant}"
420	fi
421}
422
423myprog_help ()
424{
425	echo "Usage: ${0##*/} [OPTIONS]"
426	echo
427	echo "Creates a template to be used during kmod building"
428	echo
429	echo "Available options:"
430	echo " --filterfile <file>  -- filter the results with grep --file <file>"
431	echo " --for-kernels <list> -- created templates only for these kernels"
432	echo " --kmodname <file>    -- name of the kmod (required)"
433	echo " --devel              -- make kmod-devel package"
434	echo " --noakmod            -- no akmod package"
435	echo " --repo <name>        -- use buildsys-build-<name>-kerneldevpkgs"
436	echo " --target <arch>      -- target-arch (required)"
437	echo " --buildroot <dir>    -- Build root (place to look for build files)"
438}
439
440while [[ -n "${1}" ]] ; do
441	case "${1}" in
442		--filterfile)
443			shift
444			if [[ -z "${1}" ]] ; then
445				error_out 2 "Please provide path to a filter-file together with --filterfile" >&2
446			elif [[ ! -e "${1}" ]]; then
447				error_out 2 "Filterfile ${1} not found" >&2
448			fi
449			filterfile="${1}"
450			shift
451			;;
452		--kmodname)
453			shift
454			if [[ -z "${1}" ]] ; then
455				error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
456	 	    fi
457			# strip pending -kmod
458			kmodname="${1%%-kmod}"
459			shift
460			;;
461		--devel)
462			shift
463			devel="true"
464			;;
465		--prefix)
466			shift
467			if [[ -z "${1}" ]] ; then
468				error_out 2 "Please provide a prefix with --prefix" >&2
469		    fi
470			prefix="${1}"
471			shift
472			;;
473		--repo)
474			shift
475			if [[ -z "${1}" ]] ; then
476				error_out 2 "Please provide the name of the repo together with --repo" >&2
477	 	    fi
478			repo=${1}
479			shift
480			;;
481		--for-kernels)
482			shift
483			if [[ -z "${1}" ]] ; then
484				error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
485	 		fi
486			for_kernels="${1}"
487			shift
488			;;
489		--noakmod)
490			shift
491			noakmod="true"
492			;;
493		--target)
494			shift
495			target="${1}"
496			shift
497			;;
498		--akmod)
499			shift
500			build_kernels="akmod"
501			;;
502		--newest)
503			shift
504			build_kernels="newest"
505			;;
506		--current)
507			shift
508			build_kernels="current"
509			;;
510		--buildroot)
511			shift
512			buildroot="${1}"
513			shift
514			;;
515		--help)
516			myprog_help
517			exit 0
518			;;
519		--version)
520			echo "${myprog} ${myver}"
521			exit 0
522			;;
523		*)
524			echo "Error: Unknown option '${1}'." >&2
525			usage >&2
526			exit 2
527			;;
528	esac
529done
530
531if [[ -e ./kmodtool-kernel-variants ]]; then
532	kernels_known_variants="$(cat ./kmodtool-kernel-variants)"
533elif [[ -e /usr/share/kmodtool/kernel-variants ]] ; then
534	kernels_known_variants="$(cat /usr/share/kmodtool/kernel-variants)"
535else
536	kernels_known_variants="@(smp?(-debug)|PAE?(-debug)|debug|kdump|xen|kirkwood|highbank|imx|omap|tegra)"
537fi
538
539# general sanity checks
540if [[ -z "${target}" ]]; then
541		error_out 2 "please pass target arch with --target"
542elif [[ -z "${kmodname}" ]]; then
543		error_out 2 "please pass kmodname with --kmodname"
544elif [[ -z "${kernels_known_variants}" ]] ; then
545		error_out 2 "could not determine known variants"
546fi
547
548# go
549if [[ -n "${for_kernels}" ]]; then
550	# this is easy:
551	print_customrpmtemplate "${for_kernels}"
552elif [[ "${build_kernels}" = "akmod" ]]; then
553	# do only a akmod package
554	print_akmodtemplate
555	print_akmodmeta
556else
557	# seems we are on out own to decide for which kernels to build
558
559	# we need more sanity checks in this case
560	if [[ -z "${repo}" ]]; then
561		error_out 2 "please provide repo name with --repo"
562	elif ! command -v "buildsys-build-${repo}-kerneldevpkgs" > /dev/null 2>&1; then
563		error_out 2 "buildsys-build-${repo}-kerneldevpkgs not found"
564	fi
565
566	# call buildsys-build-${repo}-kerneldevpkgs to get the list of kernels
567	cmdoptions="--target ${target}"
568
569	# filterfile to filter list of kernels?
570	if [[ -n "${filterfile}" ]] ; then
571		 cmdoptions="${cmdoptions} --filterfile ${filterfile}"
572	fi
573
574	kernel_versions_to_build_for=$(buildsys-build-${repo}-kerneldevpkgs "--${build_kernels}" ${cmdoptions}) ||
575		error_out 2 "buildsys-build-${repo}-kerneldevpkgs failed: ${kernel_versions_to_build_for}"
576
577	if [[ "${build_kernels}" = "current" ]] && [[ -z "${noakmod}" ]]; then
578		print_akmodtemplate
579	fi
580
581	print_rpmtemplate
582fi
583