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