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