You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
8.6 KiB

#!/bin/bash
#
# akmodbuild - Helper script for building kernel module SRPMs
# Copyright (c) 2007 Thorsten Leemhuis <fedora@leemhuis.info>
#
# 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 [[ ! -n "${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 [[ ! -n "${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 [[ -n "${watch_jobid}" ]] ; then
kill "${watch_jobid}"
fi
if [[ -n "${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 [[ ! -n ${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] <SRPMS>"
echo $'\n'"Options:"
echo " -k, --kernels -- build for kernel-versions (output from 'uname -r')"
echo " -l, --logfile <file> -- save rpmbuild output to <file>"
echo " -o, --outputdir <dir> -- 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 [[ ! -n "${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 [[ ! -n "${1}" ]] ; then
echo "ERROR: Please provide a filename together with --logfile" >&2
exit 1
fi
logfile="${1}"
shift
;;
-o|--outputdir)
shift
if [[ ! -n "${1}" ]] ; then
echo "ERROR: Please provide the output directory together with --outputdir" >&2
exit 1
fi
outputdir="${1}"
shift
;;
-t|--target)
shift
if [[ ! -n "${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