1#!/usr/bin/env bash 2# shellcheck disable=SC2086 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 if [ -n "${obsolete_name}" ]; then 86 echo "Provides: akmod-${obsolete_name} = ${obsolete_version}" 87 echo "Obsoletes: akmod-${obsolete_name} < ${obsolete_version}" 88 fi 89 90 cat <<EOF 91 92%description -n akmod-${kmodname} 93This package provides the akmod package for the ${kmodname} kernel modules. 94 95%posttrans -n akmod-${kmodname} 96nohup ${prefix}/sbin/akmods --from-akmod-posttrans --akmod ${kmodname} &> /dev/null & 97 98%files -n akmod-${kmodname} 99%defattr(-,root,root,-) 100%{_usrsrc}/akmods/* 101 102EOF 103} 104 105print_akmodmeta () 106{ 107 cat <<EOF 108%package -n kmod-${kmodname} 109Summary: Metapackage which tracks in ${kmodname} kernel module for newest kernel${dashvariant} 110Group: System Environment/Kernel 111 112Provides: ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release} 113Provides: kmod-${kmodname}-xen = %{?epoch:%{epoch}:}%{version}-%{release} 114Provides: kmod-${kmodname}-smp = %{?epoch:%{epoch}:}%{version}-%{release} 115Provides: kmod-${kmodname}-PAE = %{?epoch:%{epoch}:}%{version}-%{release} 116Requires: akmod-${kmodname} = %{?epoch:%{epoch}:}%{version}-%{release} 117EOF 118 119 if [ -n "${obsolete_name}" ]; then 120 echo "Provides: kmod-${obsolete_name} = ${obsolete_version}" 121 echo "Obsoletes: kmod-${obsolete_name} < ${obsolete_version}" 122 fi 123cat <<EOF 124 125%description -n kmod-${kmodname}${dashvariant} 126This is a meta-package without payload which sole purpose is to require the 127${kmodname} kernel module(s) for the newest kernel${dashvariant}, 128to make sure you get it together with a new kernel. 129 130%files -n kmod-${kmodname}${dashvariant} 131%defattr(644,root,root,755) 132EOF 133} 134 135print_rpmtemplate_per_kmodpkg () 136{ 137 if [ "${1}" = "--custom" ]; then 138 shift 139 local customkernel=true 140 elif [ "${1}" = "--redhat" ]; then 141 # this is needed for akmods 142 shift 143 local redhatkernel=true 144 fi 145 146 local kernel_uname_r=${1} 147 local kernel_variant="${2:+-${2}}" 148 149 # Detect depmod install location 150 local depmod_path=/sbin/depmod 151 if [ ! -f "${depmod_path}" ]; then 152 depmod_path=/usr/sbin/depmod 153 fi 154 155 # first part 156 cat <<EOF 157%package -n kmod-${kmodname}-${kernel_uname_r} 158Summary: ${kmodname} kernel module(s) for ${kernel_uname_r} 159Group: System Environment/Kernel 160Provides: kernel-modules-for-kernel = ${kernel_uname_r} 161Provides: kmod-${kmodname}-uname-r = ${kernel_uname_r} 162Provides: ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release} 163Requires: ${kmodname}-kmod-common >= %{?epoch:%{epoch}:}%{version} 164 165%if 0%{?rhel} == 6 || 0%{?centos} == 6 166Requires(post): module-init-tools 167Requires(postun): module-init-tools 168%else 169Requires(post): kmod 170Requires(postun): kmod 171%endif 172EOF 173 174 if [ -n "${obsolete_name}" ]; then 175 echo "Provides: kmod-${obsolete_name}-${kernel_uname_r} = ${obsolete_version}" 176 echo "Obsoletes: kmod-${obsolete_name}-${kernel_uname_r} < ${obsolete_version}" 177 fi 178 179 # second part 180 if [ -z "${customkernel}" ]; then 181 cat <<EOF 182Requires: kernel-uname-r = ${kernel_uname_r} 183BuildRequires: kernel-devel-uname-r = ${kernel_uname_r} 184%{?KmodsRequires:Requires: %{KmodsRequires}-uname-r = ${kernel_uname_r}} 185%{?KmodsRequires:BuildRequires: %{KmodsRequires}-uname-r = ${kernel_uname_r}} 186%post -n kmod-${kmodname}-${kernel_uname_r} 187if [ -f "/boot/System.map-${kernel_uname_r}" ]; then 188 ${prefix}${depmod_path} -aeF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} > /dev/null || : 189elif [ -f "/lib/modules/${kernel_uname_r}/System.map" ]; then 190 ${prefix}${depmod_path} -aeF /lib/modules/${kernel_uname_r}/System.map ${kernel_uname_r} > /dev/null || : 191else 192 ${prefix}${depmod_path} -ae ${kernel_uname_r} &> /dev/null || : 193fi 194%postun -n kmod-${kmodname}-${kernel_uname_r} 195if [ -f "/boot/System.map-${kernel_uname_r}" ]; then 196 ${prefix}${depmod_path} -aF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} &> /dev/null || : 197elif [ -f "/lib/modules/${kernel_uname_r}/System.map" ]; then 198 ${prefix}${depmod_path} -aF /lib/modules/${kernel_uname_r}/System.map ${kernel_uname_r} &> /dev/null || : 199else 200 ${prefix}${depmod_path} -a ${kernel_uname_r} &> /dev/null || : 201fi 202 203EOF 204 else 205 cat <<EOF 206%post -n kmod-${kmodname}-${kernel_uname_r} 207[ "\$(uname -r)" = "${kernel_uname_r}" ] && ${prefix}${depmod_path} -a > /dev/null || : 208%postun -n kmod-${kmodname}-${kernel_uname_r} 209[ "\$(uname -r)" = "${kernel_uname_r}" ] && ${prefix}${depmod_path} -a > /dev/null || : 210 211EOF 212 fi 213 214 # third part 215 cat <<EOF 216%description -n kmod-${kmodname}-${kernel_uname_r} 217This package provides the ${kmodname} kernel modules built for the Linux 218kernel ${kernel_uname_r} for the %{_target_cpu} family of processors. 219%files -n kmod-${kmodname}-${kernel_uname_r} 220%defattr(644,root,root,755) 221%dir $prefix/lib/modules/${kernel_uname_r}/extra 222${prefix}/lib/modules/${kernel_uname_r}/extra/${kmodname}/ 223 224 225EOF 226} 227 228print_rpmtemplate_kmoddevelpkg () 229{ 230 if [ "${1}" = "--custom" ]; then 231 shift 232 local customkernel=true 233 elif [ "${1}" = "--redhat" ]; then 234 shift 235 local redhatkernel=true 236 fi 237 238 local kernel_uname_r=${1} 239 240 cat <<EOF 241%package -n kmod-${kmodname}-devel 242Summary: ${kmodname} kernel module(s) devel common 243Group: System Environment/Kernel 244Provides: ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release} 245EOF 246 247 if [ -z "${customkernel}" ] && [ -z "${redhatkernel}" ]; then 248 echo "Requires: kmod-${kmodname}-devel-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release}" 249 fi 250 251 if [ -n "${obsolete_name}" ]; then 252 echo "Provides: kmod-${obsolete_name}-devel = ${obsolete_version}" 253 echo "Obsoletes: kmod-${obsolete_name}-devel < ${obsolete_version}" 254 fi 255 256 cat <<EOF 257%description -n kmod-${kmodname}-devel 258This package provides the common header files to build kernel modules 259which depend on the ${kmodname} kernel module. It may optionally require 260the ${kmodname}-devel-<kernel> objects for the newest kernel. 261 262%files -n kmod-${kmodname}-devel 263%defattr(644,root,root,755) 264%{_usrsrc}/${kmodname}-%{version} 265EOF 266 267 for kernel in ${1}; do 268 local kernel_uname_r=${kernel} 269 echo "%exclude %{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r}" 270 done 271 272 echo 273 echo 274} 275 276print_rpmtemplate_per_kmoddevelpkg () 277{ 278 if [ "${1}" = "--custom" ]; then 279 shift 280 local customkernel=true 281 elif [ "${1}" = "--redhat" ]; then 282 # this is needed for akmods 283 shift 284 local redhatkernel=true 285 fi 286 287 local kernel_uname_r=${1} 288 local kernel_variant="${2:+-${2}}" 289 290 # first part 291 cat <<EOF 292%package -n kmod-${kmodname}-devel-${kernel_uname_r} 293Summary: ${kmodname} kernel module(s) devel for ${kernel_uname_r} 294Group: System Environment/Kernel 295Provides: kernel-objects-for-kernel = ${kernel_uname_r} 296Provides: ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release} 297Provides: kmod-${kmodname}-devel-uname-r = ${kernel_uname_r} 298EOF 299 300 if [ -n "${obsolete_name}" ]; then 301 echo "Provides: kmod-${obsolete_name}-devel-${kernel_uname_r} = ${obsolete_version}" 302 echo "Obsoletes: kmod-${obsolete_name}-devel-${kernel_uname_r} < ${obsolete_version}" 303 fi 304 305 # second part 306 if [ -z "${customkernel}" ]; then 307 cat <<EOF 308Requires: kernel-devel-uname-r = ${kernel_uname_r} 309BuildRequires: kernel-devel-uname-r = ${kernel_uname_r} 310%{?KmodsDevelRequires:Requires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}} 311%{?KmodsDevelRequires:BuildRequires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}} 312EOF 313 fi 314 315 # third part 316 cat <<EOF 317%description -n kmod-${kmodname}-devel-${kernel_uname_r} 318This package provides objects and symbols required to build kernel modules 319which depend on the ${kmodname} kernel modules built for the Linux 320kernel ${kernel_uname_r} for the %{_target_cpu} family of processors. 321%files -n kmod-${kmodname}-devel-${kernel_uname_r} 322%defattr(644,root,root,755) 323%{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r} 324EOF 325} 326 327print_rpmtemplate_kmodmetapkg () 328{ 329 local kernel_uname_r=${1} 330 local kernel_variant="${2:+-${2}}" 331 332 cat <<EOF 333%package -n kmod-${kmodname}${kernel_variant} 334Summary: Metapackage which tracks in ${kmodname} kernel module for newest kernel${kernel_variant} 335Group: System Environment/Kernel 336 337Provides: ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release} 338Requires: kmod-${kmodname}-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release} 339%{?KmodsMetaRequires:Requires: %{?KmodsMetaRequires}} 340EOF 341 342 if [ -n "${obsolete_name}" ]; then 343 echo "Provides: kmod-${obsolete_name}${kernel_variant} = ${obsolete_version}" 344 echo "Obsoletes: kmod-${obsolete_name}${kernel_variant} < ${obsolete_version}" 345 fi 346 347 cat <<EOF 348 349%description -n kmod-${kmodname}${kernel_variant} 350This is a meta-package without payload which sole purpose is to require the 351${kmodname} kernel module(s) for the newest kernel${kernel_variant}. 352to make sure you get it together with a new kernel. 353 354%files -n kmod-${kmodname}${kernel_variant} 355%defattr(644,root,root,755) 356 357 358EOF 359} 360 361print_customrpmtemplate () 362{ 363 for kernel in ${1} 364 do 365 if [ -e "${buildroot}/usr/src/kernels/${kernel}" ] ; then 366 # this looks like a Fedora/RH kernel -- print a normal template (which includes the proper BR) and be happy :) 367 kernel_versions="${kernel_versions}${kernel}___${buildroot}%{_usrsrc}/kernels/${kernel} " 368 369 # parse kernel versions string and print template 370 local kernel_verrelarch=${kernel%%${kernels_known_variants}} 371 print_rpmtemplate_per_kmodpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 372 373 # create development package 374 if [ -n "${devel}" ]; then 375 # create devel package including common headers 376 print_rpmtemplate_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 377 378 # create devel package 379 print_rpmtemplate_per_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}} 380 fi 381 elif [ -e "${prefix}/lib/modules/${kernel}/build/Makefile" ]; then 382 # likely a user-build-kernel with available buildfiles 383 # fixme: we should check if uname from Makefile is the same as ${kernel} 384 385 kernel_versions="${kernel_versions}${kernel}___${prefix}/lib/modules/${kernel}/build/ " 386 print_rpmtemplate_per_kmodpkg --custom "${kernel}" 387 388 # create development package 389 if [ -n "${devel}" ]; then 390 # create devel package including common headers 391 print_rpmtemplate_kmoddevelpkg --custom "${kernel}" 392 393 # create devel package 394 print_rpmtemplate_per_kmoddevelpkg --custom "${kernel}" 395 fi 396 else 397 error_out 2 "Don't know how to handle ${kernel} -- ${prefix}/lib/modules/${kernel}/build/Makefile not found" 398 fi 399 done 400 401 # well, it's no header anymore, but who cares ;-) 402 print_rpmtemplate_header 403} 404 405 406print_rpmtemplate () 407{ 408 # create kernel_versions var 409 for kernel_version in ${kernel_versions_to_build_for} 410 do 411 kernel_versions="${kernel_versions}${kernel_version}___%{_usrsrc}/kernels/${kernel_version} " 412 done 413 414 # and print it and some other required stuff as macro 415 print_rpmtemplate_header 416 417 # now print the packages 418 for kernel in ${kernel_versions_to_build_for} ; do 419 420 local kernel_verrelarch=${kernel%%${kernels_known_variants}} 421 422 # create metapackage 423 print_rpmtemplate_kmodmetapkg "${kernel}" "${kernel##${kernel_verrelarch}}" 424 425 # create package 426 print_rpmtemplate_per_kmodpkg "${kernel}" "${kernel##${kernel_verrelarch}}" 427 428 if [ -n "${devel}" ]; then 429 # create devel package including common headers 430 print_rpmtemplate_kmoddevelpkg "${kernel}" "${kernel##${kernel_verrelarch}}" 431 432 # create devel package 433 print_rpmtemplate_per_kmoddevelpkg "${kernel}" "${kernel##${kernel_verrelarch}}" 434 fi 435 done 436} 437 438myprog_help () 439{ 440 echo "Usage: ${0##*/} [OPTIONS]" 441 echo 442 echo "Creates a template to be used during kmod building" 443 echo 444 echo "Available options:" 445 echo " --filterfile <file> -- filter the results with grep --file <file>" 446 echo " --for-kernels <list> -- created templates only for these kernels" 447 echo " --kmodname <file> -- name of the kmod (required)" 448 echo " --devel -- make kmod-devel package" 449 echo " --noakmod -- no akmod package" 450 echo " --repo <name> -- use buildsys-build-<name>-kerneldevpkgs" 451 echo " --target <arch> -- target-arch (required)" 452 echo " --buildroot <dir> -- Build root (place to look for build files)" 453} 454 455while [ -n "${1}" ] ; do 456 case "${1}" in 457 --filterfile) 458 shift 459 if [ -z "${1}" ] ; then 460 error_out 2 "Please provide path to a filter-file together with --filterfile" >&2 461 elif [ ! -e "${1}" ]; then 462 error_out 2 "Filterfile ${1} not found" >&2 463 fi 464 filterfile="${1}" 465 shift 466 ;; 467 --kmodname) 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 # strip pending -kmod 473 kmodname="${1%%-kmod}" 474 shift 475 ;; 476 --devel) 477 shift 478 devel="true" 479 ;; 480 --prefix) 481 shift 482 if [ -z "${1}" ] ; then 483 error_out 2 "Please provide a prefix with --prefix" >&2 484 fi 485 prefix="${1}" 486 shift 487 ;; 488 --repo) 489 shift 490 if [ -z "${1}" ] ; then 491 error_out 2 "Please provide the name of the repo together with --repo" >&2 492 fi 493 repo=${1} 494 shift 495 ;; 496 --for-kernels) 497 shift 498 if [ -z "${1}" ] ; then 499 error_out 2 "Please provide the name of the kmod together with --kmodname" >&2 500 fi 501 for_kernels="${1}" 502 shift 503 ;; 504 --noakmod) 505 shift 506 noakmod="true" 507 ;; 508 --obsolete-name) 509 shift 510 if [ -z "${1}" ] ; then 511 error_out 2 "Please provide the name of the kmod to obsolete together with --obsolete-name" >&2 512 fi 513 obsolete_name="${1}" 514 shift 515 ;; 516 --obsolete-version) 517 shift 518 if [ -z "${1}" ] ; then 519 error_out 2 "Please provide the version of the kmod to obsolete together with --obsolete-version" >&2 520 fi 521 obsolete_version="${1}" 522 shift 523 ;; 524 --target) 525 shift 526 target="${1}" 527 shift 528 ;; 529 --akmod) 530 shift 531 build_kernels="akmod" 532 ;; 533 --newest) 534 shift 535 build_kernels="newest" 536 ;; 537 --current) 538 shift 539 build_kernels="current" 540 ;; 541 --buildroot) 542 shift 543 buildroot="${1}" 544 shift 545 ;; 546 --help) 547 myprog_help 548 exit 0 549 ;; 550 --version) 551 echo "${myprog} ${myver}" 552 exit 0 553 ;; 554 *) 555 echo "Error: Unknown option '${1}'." >&2 556 usage >&2 557 exit 2 558 ;; 559 esac 560done 561 562if [ -e ./kmodtool-kernel-variants ]; then 563 kernels_known_variants="$(cat ./kmodtool-kernel-variants)" 564elif [ -e /usr/share/kmodtool/kernel-variants ] ; then 565 kernels_known_variants="$(cat /usr/share/kmodtool/kernel-variants)" 566else 567 kernels_known_variants="@(smp?(-debug)|PAE?(-debug)|debug|kdump|xen|kirkwood|highbank|imx|omap|tegra)" 568fi 569 570# general sanity checks 571if [ -z "${target}" ]; then 572 error_out 2 "please pass target arch with --target" 573elif [ -z "${kmodname}" ]; then 574 error_out 2 "please pass kmodname with --kmodname" 575elif [ -z "${kernels_known_variants}" ] ; then 576 error_out 2 "could not determine known variants" 577elif { [ -n "${obsolete_name}" ] && [ -z "${obsolete_version}" ]; } || { [ -z "${obsolete_name}" ] && [ -n "${obsolete_version}" ]; } ; then 578 error_out 2 "you need to provide both --obsolete-name and --obsolete-version" 579fi 580 581# go 582if [ -n "${for_kernels}" ]; then 583 # this is easy: 584 print_customrpmtemplate "${for_kernels}" 585elif [ "${build_kernels}" = "akmod" ]; then 586 # do only a akmod package 587 print_akmodtemplate 588 print_akmodmeta 589else 590 # seems we are on out own to decide for which kernels to build 591 592 # we need more sanity checks in this case 593 if [ -z "${repo}" ]; then 594 error_out 2 "please provide repo name with --repo" 595 elif ! command -v "buildsys-build-${repo}-kerneldevpkgs" > /dev/null 2>&1; then 596 error_out 2 "buildsys-build-${repo}-kerneldevpkgs not found" 597 fi 598 599 # call buildsys-build-${repo}-kerneldevpkgs to get the list of kernels 600 cmdoptions="--target ${target}" 601 602 # filterfile to filter list of kernels? 603 if [ -n "${filterfile}" ] ; then 604 cmdoptions="${cmdoptions} --filterfile ${filterfile}" 605 fi 606 607 kernel_versions_to_build_for=$(buildsys-build-${repo}-kerneldevpkgs "--${build_kernels}" ${cmdoptions}) 608 returncode=$? 609 if [ "$returncode" -ne 0 ]; then 610 611 error_out 2 "buildsys-build-${repo}-kerneldevpkgs failed: ${kernel_versions_to_build_for}" 612 fi 613 614 if [ "${build_kernels}" = "current" ] && [ -z "${noakmod}" ]; then 615 print_akmodtemplate 616 fi 617 618 print_rpmtemplate 619fi 620