xref: /freebsd/sys/contrib/openzfs/scripts/kmodtool (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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	for kernel in ${1}
336	do
337		if [[ -e "${prefix}/lib/modules/${kernel}/build/Makefile" ]]; then
338			# likely a user-build-kernel with available buildfiles
339			# fixme: we should check if uname from Makefile is the same as ${kernel}
340
341			kernel_versions="${kernel_versions}${kernel}___${prefix}/lib/modules/${kernel}/build/ "
342			print_rpmtemplate_per_kmodpkg --custom "${kernel}"
343
344			# create development package
345			if [[ -n "${devel}" ]]; then
346				# create devel package including common headers
347				print_rpmtemplate_kmoddevelpkg --custom "${kernel}"
348
349				# create devel package
350				print_rpmtemplate_per_kmoddevelpkg --custom "${kernel}"
351			fi
352		elif [[ -e "${buildroot}/usr/src/kernels/${kernel}" ]]; then
353			# this looks like a Fedora/RH kernel -- print a normal template (which includes the proper BR) and be happy :)
354			kernel_versions="${kernel_versions}${kernel}___${buildroot}%{_usrsrc}/kernels/${kernel} "
355
356			# parse kernel versions string and print template
357			local kernel_verrelarch=${kernel%%${kernels_known_variants}}
358			print_rpmtemplate_per_kmodpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
359
360			# create development package
361			if [[ -n "${devel}" ]]; then
362				# create devel package including common headers
363				print_rpmtemplate_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
364
365				# create devel package
366				print_rpmtemplate_per_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
367			fi
368		else
369			error_out 2 "Don't know how to handle ${kernel} -- ${prefix}/lib/modules/${kernel}/build/Makefile not found"
370		fi
371	done
372
373	# well, it's no header anymore, but who cares ;-)
374	print_rpmtemplate_header
375}
376
377
378print_rpmtemplate ()
379{
380	# create kernel_versions var
381	for kernel_version in ${kernel_versions_to_build_for}
382	do
383		kernel_versions="${kernel_versions}${kernel_version}___%{_usrsrc}/kernels/${kernel_version} "
384	done
385
386	# and print it and some other required stuff as macro
387	print_rpmtemplate_header
388
389	# now print the packages
390	for kernel in ${kernel_versions_to_build_for} ; do
391
392		local kernel_verrelarch=${kernel%%${kernels_known_variants}}
393
394		# create metapackage
395		print_rpmtemplate_kmodmetapkg "${kernel}" "${kernel##${kernel_verrelarch}}"
396
397		# create package
398		print_rpmtemplate_per_kmodpkg "${kernel}" "${kernel##${kernel_verrelarch}}"
399
400		if [[ -n "${devel}" ]]; then
401			# create devel package including common headers
402			print_rpmtemplate_kmoddevelpkg "${kernel}" "${kernel##${kernel_verrelarch}}"
403
404			# create devel package
405			print_rpmtemplate_per_kmoddevelpkg "${kernel}" "${kernel##${kernel_verrelarch}}"
406		fi
407	done
408}
409
410myprog_help ()
411{
412	echo "Usage: ${0##*/} [OPTIONS]"
413	echo
414	echo "Creates a template to be used during kmod building"
415	echo
416	echo "Available options:"
417	echo " --filterfile <file>  -- filter the results with grep --file <file>"
418	echo " --for-kernels <list> -- created templates only for these kernels"
419	echo " --kmodname <file>    -- name of the kmod (required)"
420	echo " --devel              -- make kmod-devel package"
421	echo " --noakmod            -- no akmod package"
422	echo " --repo <name>        -- use buildsys-build-<name>-kerneldevpkgs"
423	echo " --target <arch>      -- target-arch (required)"
424	echo " --buildroot <dir>    -- Build root (place to look for build files)"
425}
426
427while [[ -n "${1}" ]] ; do
428	case "${1}" in
429		--filterfile)
430			shift
431			if [[ -z "${1}" ]] ; then
432				error_out 2 "Please provide path to a filter-file together with --filterfile" >&2
433			elif [[ ! -e "${1}" ]]; then
434				error_out 2 "Filterfile ${1} not found" >&2
435			fi
436			filterfile="${1}"
437			shift
438			;;
439		--kmodname)
440			shift
441			if [[ -z "${1}" ]] ; then
442				error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
443	 	    fi
444			# strip pending -kmod
445			kmodname="${1%%-kmod}"
446			shift
447			;;
448		--devel)
449			shift
450			devel="true"
451			;;
452		--prefix)
453			shift
454			if [[ -z "${1}" ]] ; then
455				error_out 2 "Please provide a prefix with --prefix" >&2
456		    fi
457			prefix="${1}"
458			shift
459			;;
460		--repo)
461			shift
462			if [[ -z "${1}" ]] ; then
463				error_out 2 "Please provide the name of the repo together with --repo" >&2
464	 	    fi
465			repo=${1}
466			shift
467			;;
468		--for-kernels)
469			shift
470			if [[ -z "${1}" ]] ; then
471				error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
472	 		fi
473			for_kernels="${1}"
474			shift
475			;;
476		--noakmod)
477			shift
478			noakmod="true"
479			;;
480		--target)
481			shift
482			target="${1}"
483			shift
484			;;
485		--akmod)
486			shift
487			build_kernels="akmod"
488			;;
489		--newest)
490			shift
491			build_kernels="newest"
492			;;
493		--current)
494			shift
495			build_kernels="current"
496			;;
497		--buildroot)
498			shift
499			buildroot="${1}"
500			shift
501			;;
502		--help)
503			myprog_help
504			exit 0
505			;;
506		--version)
507			echo "${myprog} ${myver}"
508			exit 0
509			;;
510		*)
511			echo "Error: Unknown option '${1}'." >&2
512			usage >&2
513			exit 2
514			;;
515	esac
516done
517
518if [[ -e ./kmodtool-kernel-variants ]]; then
519	kernels_known_variants="$(cat ./kmodtool-kernel-variants)"
520elif [[ -e /usr/share/kmodtool/kernel-variants ]] ; then
521	kernels_known_variants="$(cat /usr/share/kmodtool/kernel-variants)"
522else
523	kernels_known_variants="@(smp?(-debug)|PAE?(-debug)|debug|kdump|xen|kirkwood|highbank|imx|omap|tegra)"
524fi
525
526# general sanity checks
527if [[ -z "${target}" ]]; then
528		error_out 2 "please pass target arch with --target"
529elif [[ -z "${kmodname}" ]]; then
530		error_out 2 "please pass kmodname with --kmodname"
531elif [[ -z "${kernels_known_variants}" ]] ; then
532		error_out 2 "could not determine known variants"
533fi
534
535# go
536if [[ -n "${for_kernels}" ]]; then
537	# this is easy:
538	print_customrpmtemplate "${for_kernels}"
539elif [[ "${build_kernels}" = "akmod" ]]; then
540	# do only a akmod package
541	print_akmodtemplate
542	print_akmodmeta
543else
544	# seems we are on out own to decide for which kernels to build
545
546	# we need more sanity checks in this case
547	if [[ -z "${repo}" ]]; then
548		error_out 2 "please provide repo name with --repo"
549	elif ! command -v "buildsys-build-${repo}-kerneldevpkgs" > /dev/null 2>&1; then
550		error_out 2 "buildsys-build-${repo}-kerneldevpkgs not found"
551	fi
552
553	# call buildsys-build-${repo}-kerneldevpkgs to get the list of kernels
554	cmdoptions="--target ${target}"
555
556	# filterfile to filter list of kernels?
557	if [[ -n "${filterfile}" ]] ; then
558		 cmdoptions="${cmdoptions} --filterfile ${filterfile}"
559	fi
560
561	kernel_versions_to_build_for=$(buildsys-build-${repo}-kerneldevpkgs "--${build_kernels}" ${cmdoptions}) ||
562		error_out 2 "buildsys-build-${repo}-kerneldevpkgs failed: ${kernel_versions_to_build_for}"
563
564	if [[ "${build_kernels}" = "current" ]] && [[ -z "${noakmod}" ]]; then
565		print_akmodtemplate
566	fi
567
568	print_rpmtemplate
569fi
570