#!/bin/bash # # akmodbuild - Helper script for building kernel module SRPMs # Copyright (c) 2007 Thorsten Leemhuis # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # myprog="akmodsbuild" myver="0.5.6" # defaults that might get overwritten by user: kernels="$(uname -r)" target="$(uname -m)" if [[ "${target}" == "armv7l" ]] ; then target="armv7hl" fi numberofjobs=$(grep -c processor /proc/cpuinfo 2> /dev/null) verboselevel=2 outputdir="${PWD}" srpms= init () { ## startup checks # prevent root-usage if [[ -w /var ]] ; then echo "ERROR: Not to be used as root; start as user or '${myprog}' instead." >&2 exit 1 fi # do we have everything we need to build for the kernels in question? for kernel in ${kernels}; do if [[ ! -e /usr/src/kernels/${kernel}/Makefile ]] && [[ ! -e /usr/lib/modules/${kernel}/build/Makefile ]] ; then echo "ERROR: Files needed for building modules against kernel" >&2 echo " ${kernel} could not be found as the following" >&2 echo " directories are missing:" echo " /usr/src/kernels/${kernel}/" >&2 echo " /usr/lib/modules/${kernel}/build/" >&2 exit 2 fi done if [[ ! "${srpms}" ]] ; then echo "ERROR: Please provide a list of SRPM-files to build." exit 2 fi # SRPMS available? for srpm in ${srpms}; do if [[ ! -r ${srpm} ]] ; then echo "ERROR: Can't find SRPM ${srpm}" exit 1 fi done # room to save things if [[ ! -d "${outputdir}" ]] ; then echo "ERROR: ${outputdir} is not a directory" >&2 exit 1 elif [[ ! -w "${outputdir}" ]] ; then echo "ERROR: ${outputdir} is not a writable" >&2 exit 1 fi # make sure this is a number if ! (( ${numberofjobs} > 0 )) ; then echo "Warning: using hardcoded defaut value for number of jobs" numberofjobs=2 fi ## preparations # tmpdir if ! tmpdir="$(mktemp -d -p /tmp ${myprog}.XXXXXXXX)" ; then echo "ERROR: Could create tempdir." exit 1 fi # buildtreee mkdir "${tmpdir}"/{BUILD,SOURCES,SPECS,SRPMS,RPMS,RPMS/"${target}"} # logfile if [[ ! "${logfile}" ]] ; then logfile="${tmpdir}/logfile" fi if ( [[ -e "${logfile}" ]] && [[ ! -w "${logfile}" ]] ) || ! touch "${logfile}" ; then echo "ERROR: Could not write logfile." finally exit 1 fi } finally() { # kill background jobs if needed if [[ "${watch_jobid}" ]] ; then kill "${watch_jobid}" fi if [[ "${rpmbuild_jobid}" ]] ; then kill "${rpmbuild_jobid}" fi # remove tmpfiles if [[ -d "${tmpdir}" ]] ; then rm -rf "${tmpdir}" fi } trap "finally" 2 akmods_echo() { # where to output local this_fd=${1} shift # verboselevel local this_verbose=${1} shift if [[ "${1}" == "--not-logfile" ]] ; then local notlogfile=true shift fi # output to console if (( ${verboselevel} >= ${this_verbose} )) ; then echo "$@" >&${this_fd} fi # global logfile if [[ ! ${notlogfile} ]] ; then echo "$@" >> "${logfile}" fi } watch_rpmbuild() { # background function to show rpmbuild progress # does't use akmods_echo here; this stage handles the output on its own # (seperate process and there is no need to log this) if (( ${verboselevel} == 2 )) ; then tail --pid ${1} -n +1 -s 0.1 -f ${2} 2>/dev/null | grep --line-buffered -e '%prep' -e '%build' -e '%install' -e '%clean' | while read line ; do if [[ "${line}" != "${line##*prep}" ]] ; then echo -n "prep " elif [[ "${line}" != "${line##*build}" ]] ; then echo -n "build " elif [[ "${line}" != "${line##*install}" ]] ; then echo -n "install " elif [[ "${line}" != "${line##*clean}" ]] ; then echo -n "clean; " # last linefeed is done by the caller fi done elif (( ${verboselevel} > 2 )) ; then tail --pid ${1} -n +1 -s 0.1 -f ${2} fi } process_srpm() { local source_rpm="${1}" # status info akmods_echo 1 2 -n "* Rebuilding ${source_rpm} for kernel(s) ${kernels}: " # kick off rebuild into background /usr/bin/time --format='%x' --output="${tmpdir}/.jobexit" rpmbuild \ --define "_topdir ${tmpdir}/" \ --define "_buildtree ${tmpdir}/BUILD" \ --define "_specdir ${tmpdir}/SPECS" \ --define "_sourcedir ${tmpdir}/SOURCES" \ --define "_srcrpmdir ${tmpdir}/SRPMS" \ --define "_rpmdir ${tmpdir}/RPMS" \ --define "_smp_mflags -j${numberofjobs}" \ --define "kernels ${kernels}" \ --target ${target} \ --rebuild "${source_rpm}" 2>&1 | tee -a "${logfile}" > "${tmpdir}/.joblog" & local rpmbuild_jobid=$! # show progress if (( ${verboselevel} >= 2 )) ; then watch_rpmbuild ${rpmbuild_jobid} "${tmpdir}/.joblog" 2> /dev/null & local watch_jobid=$! fi # wait for rpmbuild wait ${rpmbuild_jobid} local rpmbuild_returncode=$(tail -n 1 "${tmpdir}/.jobexit") unset rpmbuild_jobid # give watch_rpmbuild a moment to catch up; kill it if it does not if (( ${verboselevel} >= 2 )) ; then sleep 0.5 kill ${watch_jobid} &> /dev/null unset watch_jobid fi # did rpmbuild succeed? if (( ${rpmbuild_returncode} != 0 )) ; then # linefeed: akmods_echo 1 2 "" akmods_echo 2 2 --not-logfile "rpmbuild failed with errorcode ${rpmbuild_returncode}; last 35 Lines of log:" akmods_echo 2 2 --not-logfile "--- " tail -n 35 "${tmpdir}/.joblog" >&2 akmods_echo 2 2 --not-logfile "---" return ${rpmbuild_returncode} fi # finish status for watch_rpmbuild if (( ${verboselevel} >= 2 )) ; then akmods_echo 1 2 -n "Successfull; " fi local rpms_built="$(cd "${tmpdir}"/RPMS/"${target}" ; echo *)" if ! mv "${tmpdir}/RPMS/${target}/"* "${outputdir}" ; then # linefeed: akmods_echo 1 2 "" akmods_echo 2 2 "Failed to move ${tmpdir}/RPMS/${target}/"* "to ${outputdir}" return 128 fi if (( ${verboselevel} == 1 )) ; then for rpm in ${rpms_built}; do echo "${outputdir%%/}/${rpm}" done elif (( ${verboselevel} >= 2 )) ; then akmods_echo 1 2 "Saved ${rpms_built} in ${outputdir%%/}/" fi # finished return 0 } myprog_help () { echo "Rebuilds kmod SRPM(s)" echo $'\n'"Usage: ${myprog} [OPTIONS] " echo $'\n'"Options:" echo " -k, --kernels -- build for kernel-versions (output from 'uname -r')" echo " -l, --logfile -- save rpmbuild output to " echo " -o, --outputdir -- save rpms and logs here (current directory)" echo " -t, --target -- target-arch (output from 'uname -m')" echo " -v, --verbose -- increase verboseness" echo " -q, --quiet -- be more quiet" echo " -h, --help -- show usage" echo " -V, --version -- show version" } while [ "${1}" ] ; do case "${1}" in -k|--kernels) shift if [[ ! "${1}" ]] ; then echo "ERROR: Please provide kernel-version(s) to build for together with --kernel" >&2 exit 1 fi kernels="${1}" shift ;; -l|--logfile) shift if [[ ! "${1}" ]] ; then echo "ERROR: Please provide a filename together with --logfile" >&2 exit 1 fi logfile="${1}" shift ;; -o|--outputdir) shift if [[ ! "${1}" ]] ; then echo "ERROR: Please provide the output directory together with --outputdir" >&2 exit 1 fi outputdir="${1}" shift ;; -t|--target) shift if [[ ! "${1}" ]] ; then echo "ERROR: Please provide the target-arch together with --target" >&2 exit 1 fi target="${1}" shift ;; -v|--verbose) let verboselevel++ shift ;; -q|--quiet) let verboselevel-- shift ;; -h|--help) myprog_help exit 0 ;; -V|--version) echo "${myprog} ${myver}" exit 0 ;; --*) echo "Error: Unknown option '${1}'." >&2 myprog_help >&2 exit 2 ;; *) srpms="${srpms} ${1}" shift ;; esac done # sanity checks init # go for srpm in ${srpms}; do process_srpm ${srpm} returncode=$? if (( ${returncode} != 0 )) ; then finally exit ${returncode} fi done # finished finally exit 0