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