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 "${prefix}/lib/modules/${kernel}/build/Makefile" ]]; then 337 # likely a user-build-kernel with available buildfiles 338 # fixme: we should check if uname from Makefile is the same as ${kernel} 339 340 kernel_versions="${kernel_versions}${kernel}___${prefix}/lib/modules/${kernel}/build/ " 341 print_rpmtemplate_per_kmodpkg --custom "${kernel}" 342 343 # create development package 344 if [[ -n "${devel}" ]]; then 345 # create devel package including common headers 346 print_rpmtemplate_kmoddevelpkg --custom "${kernel}" 347 348 # create devel package 349 print_rpmtemplate_per_kmoddevelpkg --custom "${kernel}" 350 fi 351 elif [[ -e "${buildroot}/usr/src/kernels/${kernel}" ]]; then 352 # this looks like a Fedora/RH kernel -- print a normal template (which includes the proper BR) and be happy :) 353 kernel_versions="${kernel_versions}${kernel}___${buildroot}%{_usrsrc}/kernels/${kernel} " 354 355 # parse kernel versions string and print template 356 local kernel_verrelarch=${kernel%%${kernels_known_variants}} 357 print_rpmtemplate_per_kmodpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 358 359 # create development package 360 if [[ -n "${devel}" ]]; then 361 # create devel package including common headers 362 print_rpmtemplate_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 363 364 # create devel package 365 print_rpmtemplate_per_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 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