From c1a53c5ea36198c61be6e928d125b7d51523b46f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mar 06 2017 16:10:02 +0000 Subject: Initial fedora akmods import --- diff --git a/95-akmods.preset b/95-akmods.preset new file mode 100644 index 0000000..0c73a6b --- /dev/null +++ b/95-akmods.preset @@ -0,0 +1,8 @@ +# Also see: +# https://fedoraproject.org/wiki/Starting_services_by_default + +# Installing presets is not the preferred solution but until another one +# presents itself: +# https://bugzilla.rpmfusion.org/show_bug.cgi?id=3713 +enable akmods.service +#enable akmods-shutdown.service diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c9b44cb --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +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. diff --git a/README b/README new file mode 100644 index 0000000..45e311f --- /dev/null +++ b/README @@ -0,0 +1,9 @@ +Akmods startup script will rebuild akmod packages during system +boot while its background daemon will build them for kernels right +after they were installed. + +The akmods systemd service it enabled by default. + +The akmods-shutdown service is disabled by default but can, in some +circumstantes, provide an additional chance to build and install a kernel +module. diff --git a/akmods b/akmods new file mode 100644 index 0000000..7d8d24a --- /dev/null +++ b/akmods @@ -0,0 +1,525 @@ +#!/bin/bash - +############################################################################ +# +# akmods - Rebuilds and install akmod RPMs +# Copyright (c) 2007, 2008 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. +# +############################################################################ +# +# ToDo: +# - use yum/dnf to install required kernel-devel packages? +# - better way to detect if a earlier build failed or succeeded +# - special kernel "all" (all that are installed with a matching -devel package; could be called from posttrans in akmods packages) +# - manpage +# - make it configurable if kmod building is done with nohup +# - check on shutdown if akmods is still running and let it finish before continuing +# - make it configurable if kmods from the repo replace local ones + +# global vars +myprog="akmods" +myver="0.5.6" +kmodlogfile= +continue_line="" +tmpdir= +kernels= +verboselevel=2 + +akmods_echo() +{ + # where to output + local this_fd=${1} + shift + + # verboselevel + local this_verbose=${1} + shift + + # output to console + if (( ${verboselevel} >= ${this_verbose} )) ; then + if [[ "${1}" == "--success" ]] ; then + echo_success + continue_line="" + echo + return 0 + elif [[ "${1}" == "--failure" ]]; then + echo_failure + echo + continue_line="" + return 0 + elif [[ "${1}" == "--warning" ]]; then + echo_warning + echo + continue_line="" + return 0 + elif [[ "${1}" == "-n" ]]; then + continue_line="true" + fi + echo "$@" >&${this_fd} + fi + + # no need to print the status flags in the logs + if [[ "${1}" == "--success" ]] || [[ "${1}" == "--failure" ]] || [[ "${1}" == "--warning" ]]; then + return 0 + fi + + # no need to continues in the log + if [[ "${1}" == "-n" ]]; then + shift + fi + + # global logfile + echo "$(date +%Y/%m/%d\ %H:%M:%S) akmods: $@" >> "/var/cache/akmods/akmods.log" + + # the kmods logfile as well, if we work on a kmod + if [[ "${kmodlogfile}" ]]; then + echo "$(date +%Y/%m/%d\ %H:%M:%S) akmods: $@" >> "${kmodlogfile}" + fi +} + +finally() +{ + # remove tmpfiles + remove_tmpdir + + # remove lockfile + rm -f /var/cache/akmods/.lockfile + + exit ${1:-128} +} + +# Make sure finally() is run regardless of reason for exiting. +trap "finally" ABRT HUP INT QUIT + +create_tmpdir() +{ + if ! tmpdir="$(mktemp -d -p /tmp ${myprog}.XXXXXXXX)/" ; then + akmods_echo 2 1 "ERROR: failed to create tmpdir." + akmods_echo 2 1 --failure; return 1 + fi + if ! mkdir "${tmpdir}"results ; then + akmods_echo 2 1 "ERROR: failed to create result tmpdir." + akmods_echo 2 1 --failure; return 1 + fi +} + +remove_tmpdir() +{ + # remove tmpfiles + if [[ "${tmpdir}" ]] && [[ -d "${tmpdir}" ]]; then + rm -f "${tmpdir}"results/* "${tmpdir}"*.log + rmdir "${tmpdir}"results/ "${tmpdir}" + fi +} + +cleanup_cachedir () +{ + create_tmpdir + find /boot/ -maxdepth 1 -name 'vmlinuz*' | sed 's|/boot/vmlinuz-||' > "${tmpdir}"results/kernels + find "/var/cache/akmods/" -maxdepth 2 -mtime +14 -type f \( -name '*.rpm' -or -name '*.log' \) | grep -v --file "${tmpdir}"results/kernels | xargs --no-run-if-empty rm + remove_tmpdir +} + +init () +{ + # some security provisions + \export PATH='/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin' + \unalias -a + hash -r + # https://bugzilla.rpmfusion.org/show_bug.cgi?id=4023 + #ulimit -H -c 0 -- + IFS=$' \t\n' + UMASK=022 + umask ${UMASK} + + # fall back to current kernel if user didn't provide one + if [[ ! "${kernels}" ]]; then + kernels="$(uname -r)" + fi + + # we get the echo_{success,failure} stuff from there + if [[ -r /etc/rc.d/init.d/functions ]]; then + source /etc/rc.d/init.d/functions + else + echo "/etc/rc.d/init.d/functions not found" >&2 + exit 1 + fi + + # needs root permissions + if [[ ! -w / ]]; then + echo -n "Needs to run as root to be able to install rpms." >&2 + echo_failure; echo; exit 1 + fi + + # no akmods + if [[ ! -d "/usr/src/akmods/" ]] ; then + echo -n "/usr/src/akmods/ not found." >&2 + echo_failure; echo; exit 1 + fi + + # if there are no akmod packages installed there is nothing to do for us + if ! ls /usr/src/akmods/*-kmod.latest &> /dev/null ; then + echo -n "No akmod packages found, nothing to do." >&2 + echo_success; echo; exit 1 + fi + + + # now that we know that we're root make sure our dir for logging and results is available + if [[ ! -d "/var/cache/akmods/" ]] ; then + if ! mkdir -p "/var/cache/akmods/" ; then + echo -n "/var/cache/akmods/ not found and could not be created" >&2 + echo_failure; echo; exit 1 + fi + fi + if [[ ! -w "/var/cache/akmods/" ]] ; then + echo -n "${directory} not writable" >&2 + echo_failure; echo; exit 1 + fi + + # tools needed + for tool in akmodsbuild chown flock sed rpmdev-vercmp; do + if ! which "${tool}" &> /dev/null ; then + echo -n "${tool} not found" >&2 + echo_failure; echo; exit 1 + fi + done + + # create lockfile and wait till we get it + exec 99>/var/lock/subsys/akmods + flock -w 900 99 +} + +buildinstall_kmod() +{ + local this_kernelver=${1} + local this_kmodname=${2} + local this_kmodsrpm=${3} + local this_kmodverrel=${4} + + if [[ ! -r "${this_kmodsrpm}" ]]; then + akmods_echo 2 1 "ERROR: ${this_kmodsrpm} not found." + akmods_echo 2 1 --failure; return 1 + fi + + + # result and logdir + if [[ ! -d "/var/cache/akmods/${this_kmodname}" ]]; then + if ! mkdir "/var/cache/akmods/${this_kmodname}" ; then + akmods_echo 2 1 "ERROR: could not create /var/cache/akmods/${this_kmodname}." + akmods_echo 2 1 --failure; return 1 + fi + fi + + ## preparations + # tmpdir + create_tmpdir + + # akmods needs to write there (and nobody else, but mktemp takes care of that!) + chown akmods "${tmpdir}" "${tmpdir}"results + + # remove old logfiles if they exist + rm -f "/var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}.log" "/var/cache/akmods/${this_kmodname}/.last.log" + + # create a per kmod logfile + if ! touch "/var/cache/akmods/${this_kmodname}/.last.log" ; then + akmods_echo 2 1 "ERROR: failed to create kmod specific logfile." + return 1 + fi + + # akmods_echo will log to this file from now on as well + kmodlogfile="/var/cache/akmods/${this_kmodname}/.last.log" + + # Unset TMPDIR since it is misused by "runuser" + # https://bugzilla.rpmfusion.org/show_bug.cgi?id=2596 + unset TMPDIR + + # build module using akmod + akmods_echo 1 4 "Building RPM using the command '$(which akmodsbuild) --target $(uname -m) --kernels ${this_kernelver} ${this_kmodsrpm}'" + /sbin/runuser -s /bin/bash -c "$(which akmodsbuild) --quiet --quiet --target $(uname -m) --kernels ${this_kernelver} --outputdir ${tmpdir}results --logfile ${tmpdir}/akmodsbuild.log ${this_kmodsrpm}" akmods >> "${kmodlogfile}" 2>&1 + local returncode=$? + + # copy rpmbuild log to kmod specific logfile + if [[ -s "${tmpdir}"/akmodsbuild.log ]]; then + while read line ; do + echo "$(date +%Y/%m/%d\ %H:%M:%S) akmodsbuild: ${line}" >> "${kmodlogfile}" + done < "${tmpdir}"/akmodsbuild.log + fi + + # result + if (( ! ${returncode} == 0 )); then + if [[ "${continue_line}" ]]; then + akmods_echo 1 2 --failure + fi + akmods_echo 2 1 "Building rpms failed; see /var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}.failed.log for details" + cp -fl "${kmodlogfile}" "/var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}.failed.log" + kmodlogfile="" + remove_tmpdir + return 4 + fi + + # dnf/yum install - repository disabled on purpose see rfbz#3350 + akmods_echo 1 4 "Installing newly built rpms" + if [ -f /usr/bin/dnf ]; then + akmods_echo 1 4 "DNF detected" + dnf -y install --disablerepo='*' $(find "${tmpdir}results" -type f -name '*.rpm' | grep -v debuginfo) >> "${kmodlogfile}" 2>&1 + else + akmods_echo 1 4 "DNF not found, using YUM instead." + yum -y install --disablerepo='*' $(find "${tmpdir}results" -type f -name '*.rpm' | grep -v debuginfo) >> "${kmodlogfile}" 2>&1 + fi + local returncode=$? + + # place the newly built rpms where user expects them + cp "${tmpdir}results/"* "/var/cache/akmods/${this_kmodname}/" + + # everything fine? + if (( ${returncode} != 0 )); then + if [[ "${continue_line}" ]]; then + akmods_echo 1 2 --failure + fi + akmods_echo 2 1 "Could not install newly built RPMs. You can find them and the logfile" + akmods_echo 2 1 "${this_kmodverrel}-for-${this_kernelver}.failed.log in /var/cache/akmods/${this_kmodname}/" + cp -fl "${kmodlogfile}" "/var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}.failed.log" + kmodlogfile="" + remove_tmpdir + return 8 + fi + + # finish + akmods_echo 1 4 "Successful." + cp -fl "${kmodlogfile}" "/var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}.log" + kmodlogfile="" + remove_tmpdir + + return 0 +} + +check_kmod_up2date() +{ + local this_kernelver=${1} + local this_kmodname=${2} + + # kmod present? + if [[ ! -d /usr/lib/modules/${this_kernelver}/extra/${this_kmodname}/ ]] ; then + # build it + return 1 + fi + + # kmod up2date? + local kmodpackage="$(rpm -qf /usr/lib/modules/${this_kernelver}/extra/${this_kmodname}/ 2> /dev/null)" + if [[ ! "${kmodpackage}" ]]; then + # seems we didn't get what we wanted + # well, better to do nothing in this case + akmods_echo 1 2 -n "Warning: Could not determine what package owns /usr/lib/modules/${this_kernelver}/extra/${this_kmodname}/" + return 0 + fi + local kmodver=$(rpm -q --qf '%{EPOCH}:%{VERSION}-%{RELEASE}\n' "${kmodpackage}" | sed 's|(none)|0|; s!\.\(fc\|lvn\)[0-9]*!!g') + local akmodver=$(rpm -qp --qf '%{EPOCH}:%{VERSION}-%{RELEASE}\n' /usr/src/akmods/"${this_kmodname}"-kmod.latest | sed 's|(none)|0|; s!\.\(fc\|lvn\)[0-9]*!!g') + + rpmdev-vercmp "${kmodver}" "${akmodver}" &>/dev/null + local retvalue=$? + if [ "$retvalue" == 0 ]; then + # Versions are the same. Nothing to do. + return 0 + elif [ "$retvalue" == 11 ]; then + # kmod is newer, nothing to do. + return 0 + elif [ "$retvalue" == 12 ]; then + # akmod is newer, need to build kmod. + return 1 + else + # Something went wrong + akmods_echo 1 2 -n "Error: Could not determine if akmod is newer than the installed kmod" + akmods_echo 1 2 --failure + return 0 + fi +} + +check_kmods() +{ + local this_kernelver="${1}" + + akmods_echo 1 2 -n "Checking kmods exist for ${this_kernelver}" + for akmods_kmodfile in /usr/src/akmods/*-kmod.latest ; do + local this_kmodname="$(basename ${akmods_kmodfile%%-kmod.latest})" + + # actually check this akmod? + if [[ "${akmods}" ]]; then + for akmod in ${akmods} ; do + if [[ "${this_kmodname}" != "${akmod}" ]] ; then + # ignore this one + continue 2 + fi + done + fi + + # go + if ! check_kmod_up2date ${this_kernelver} ${this_kmodname} ; then + # okay, kmod wasn't found or is not up2date + if [[ "${continue_line}" ]]; then + akmods_echo 1 2 --success + # if the files for building modules are not available don't even try to build modules + if [[ ! -r /usr/src/kernels/"${this_kernelver}"/Makefile ]] && \ + [[ ! -r /usr/lib/modules/${this_kernelver}/build/Makefile ]]; then + akmods_echo 1 2 "Files needed for building modules against kernel" + akmods_echo 1 2 "${this_kernelver} could not be found as the following" + akmods_echo 1 2 "directories are missing:" + akmods_echo 1 2 "/usr/src/kernels/${this_kernelver}/" + akmods_echo 1 2 -n "/usr/lib/modules/${this_kernelver}/build/" + akmods_echo 1 2 -n "Is the correct kernel-devel package installed?" + akmods_echo 1 2 --failure + return 1 + fi + fi + + local this_kmodverrel="$(rpm -qp --qf '%{VERSION}-%{RELEASE}' "${akmods_kmodfile}" | sed 's!\.\(fc\|lvn\)[0-9]*!!g' )" + if [[ ! "${alwaystry}" ]] && [[ -e "/var/cache/akmods/${this_kmodname}/${this_kmodverrel}-for-${this_kernelver}".failed.log ]]; then + akmods_echo 1 2 -n "Ignoring ${this_kmodname}-kmod as it failed earlier" + akmods_echo 1 2 --warning + local someignored="true" + else + akmods_echo 1 2 -n "Building and installing ${this_kmodname}-kmod" + buildinstall_kmod ${this_kernelver} ${this_kmodname} ${akmods_kmodfile} ${this_kmodverrel} + local returncode=$? + if [[ "$returncode" == "0" ]]; then + akmods_echo 1 2 --success + elif [[ "$returncode" == "8" ]]; then + akmods_echo 1 2 --failure "New kmod RPM was built but could not be installed." + else + local somefailed="true" + fi + fi + fi + done + + if [[ "${continue_line}" ]]; then + akmods_echo 1 2 --success + elif [[ "${someignored}" ]] || [[ "${somefailed}" ]] ; then + echo + akmods_echo 1 2 "Hint: Some kmods were ignored or failed to build or install." + akmods_echo 1 2 "You can try to rebuild and install them by by calling" + akmods_echo 1 2 "'/usr/sbin/akmods --force' as root." + echo + sleep 2 + fi + +} + +myprog_help () +{ + echo "Checks the akmod packages and rebuilds them if needed" + echo $'\n'"Usage: ${myprog} [OPTIONS]" + echo $'\n'"Options:" + echo " --force -- try all, even if they failed earlier" + echo " --kernels -- build and install only for kernel " + echo " (formatted the same as 'uname -r' would produce)" + echo " --akmod -- build and install only akmod " +} + + +# first parse command line options +while [ "${1}" ] ; do + case "${1}" in + --kernel|--kernels) + shift + if [[ ! "${1}" ]] ; then + echo "ERROR: Please provide the kernel-version to build for together with --kernel" >&2 + exit 1 + elif [[ ! -r /usr/src/kernels/"${1}"/Makefile ]] && \ + [[ ! -r /usr/lib/modules/${1}/build/Makefile ]]; then + echo "Could not find files needed to compile modules for ${1}" + echo "Are the development files for kernel ${1} or the appropriate kernel-devel package installed?" + exit 1 + elif [[ -r /usr/src/kernels/"${1}"/Makefile ]] && \ + [[ ! -r /boot/vmlinuz-"${1}" ]]; then + # this is a red hat / fedora kernel-devel package, but the kernel for it is not installed + # kmodtool would add a dep on that kernel when building; thus when we'd try to install the + # rpms we'd run into a missing-dep problem. Thus we prevent that case + echo "Kernel ${1} not installed" + exit 1 + fi + # overwrites the default: + kernels="${kernels}${1}" + # an try to build, even if we tried already + alwaystry=true + shift + ;; + --akmod|--kmod) + shift + if [[ ! "${1}" ]] ; then + echo "ERROR: Please provide a name of a akmod package together with --akmods" >&2 + exit 1 + elif [[ -r /usr/src/akmods/"${1}"-kmod.latest ]] ; then + akmods="${akmods}${1} " + elif [[ -r /usr/src/akmods/"${1}".latest ]] ; then + akmods="${akmods}${1%%-kmod} " + else + echo "Could not find akmod ${1}" + exit 1 + fi + shift + ;; + --force) + alwaystry=true + shift + ;; + --from-init) + # just in case: remove stale lockfile if it exists: + rm -f /var/cache/akmods/.lockfile + shift + ;; + --from-posttrans|--from-kernel-posttrans|--from-akmod-posttrans) + # ignored + shift + ;; + --verbose) + let verboselevel++ + shift + ;; + --quiet) + let verboselevel-- + shift + ;; + --help) + myprog_help + exit 0 + ;; + --version) + echo "${myprog} ${myver}" + exit 0 + ;; + *) + echo "Error: Unknown option '${1}'." >&2 + myprog_help >&2 + exit 2 + ;; + esac +done + +# sanity checks +init + +# go +for kernel in ${kernels} ; do + check_kmods ${kernel} +done + +# finished :) +finally 0 diff --git a/akmods-shutdown b/akmods-shutdown new file mode 100644 index 0000000..9bdd41d --- /dev/null +++ b/akmods-shutdown @@ -0,0 +1,31 @@ +#!/bin/bash +# +# akmods-shutdown - Helper script to build kernel modules on shutdown +# Copyright (c) 2012 Richard shaw +# +# 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. +# + +echo "Building modules for all installed kernels." +for kernel in /usr/src/kernels/*; do + kernel=$(basename $kernel) + /usr/sbin/akmods --force --kernels $kernel +done + diff --git a/akmods-shutdown.service b/akmods-shutdown.service new file mode 100644 index 0000000..7fcccc1 --- /dev/null +++ b/akmods-shutdown.service @@ -0,0 +1,14 @@ +[Unit] +Description=Builds and install new kmods from akmod packages +Before=shutdown.service reboot.service halt.service +Conflicts=shutdown.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/true +ExecStop=-/usr/sbin/akmods-shutdown +TimeoutStopSec=5min + +[Install] +WantedBy=multi-user.target diff --git a/akmods.h2m b/akmods.h2m new file mode 100644 index 0000000..22f3e55 --- /dev/null +++ b/akmods.h2m @@ -0,0 +1,12 @@ +[BUGS] +https://bugzilla.rpmfusion.org/buglist.cgi?product=Fedora&component=akmods&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED +[REPORTING BUGS] +Submit a bug against the akmods component at: +.br +https://bugzilla.rpmfusion.org/enter_bug.cgi?product=Fedora +[AUTHOR] +Thorsten Leemhuis +[MAINTAINER] +Richard Shaw +[SEE ALSO] +http://rpmfusion.org/Packaging/KernelModules/Akmods diff --git a/akmods.service.in b/akmods.service.in new file mode 100644 index 0000000..ad82fee --- /dev/null +++ b/akmods.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Builds and install new kmods from akmod packages +Before=@SERVICE@ + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/akmods --from-init + +[Install] +WantedBy=multi-user.target diff --git a/akmods.spec b/akmods.spec new file mode 100644 index 0000000..1ab053f --- /dev/null +++ b/akmods.spec @@ -0,0 +1,201 @@ +Name: akmods +Version: 0.5.6 +Release: 5%{?dist} +Summary: Automatic kmods build and install tool + +License: MIT +URL: http://rpmfusion.org/Packaging/KernelModules/Akmods + +# We are upstream, these files are maintained directly in pkg-git +Source0: 95-akmods.preset +Source1: akmods +Source2: akmodsbuild +Source3: akmods.h2m +Source4: akmodsinit +Source5: akmodsposttrans +Source6: akmods.service.in +Source7: akmods-shutdown +Source8: akmods-shutdown.service +Source9: README +Source10: LICENSE + +BuildArch: noarch + +BuildRequires: help2man + +# not picked up automatically +Requires: %{_bindir}/nohup +Requires: %{_bindir}/flock +Requires: %{_bindir}/time + +# needed for actually building kmods: +Requires: %{_bindir}/rpmdev-vercmp +Requires: kmodtool >= 1-9 + +# this should track in all stuff that is normally needed to compile modules: +Requires: bzip2 coreutils diffutils file findutils gawk gcc grep +Requires: gzip perl make sed tar unzip util-linux which rpm-build + +# We use a virtual provide that would match either +# kernel-devel or kernel-PAE-devel +Requires: kernel-devel-uname-r +%if 0%{?fedora} +Suggests: kernel-devel +%endif + +# we create a special user that used by akmods to build kmod packages +Requires(pre): shadow-utils + +# systemd unit requirements. +BuildRequires: systemd +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + + +%description +Akmods startup script will rebuild akmod packages during system +boot while its background daemon will build them for kernels right +after they were installed. + + +%prep +cp -p %{SOURCE9} %{SOURCE10} . + + +%build +# Nothing to build + + +%install +mkdir -p %{buildroot}%{_usrsrc}/akmods \ + %{buildroot}%{_sbindir} \ + %{buildroot}%{_sysconfdir}/kernel/postinst.d \ + %{buildroot}%{_unitdir} \ + %{buildroot}%{_localstatedir}/cache/akmods \ + %{buildroot}%{_presetdir} +install -pm 0755 %{SOURCE1} %{buildroot}%{_sbindir}/ +install -pm 0755 %{SOURCE2} %{buildroot}%{_sbindir}/ +install -pm 0755 %{SOURCE7} %{buildroot}%{_sbindir}/ +install -pm 0755 %{SOURCE5} %{buildroot}%{_sysconfdir}/kernel/postinst.d/ +install -pm 0644 %{SOURCE8} %{buildroot}%{_unitdir}/ + +sed "s|@SERVICE@|display-manager.service|" %{SOURCE6} >\ + %{buildroot}%{_unitdir}/akmods.service + +install -pm 0644 %{SOURCE0} %{buildroot}%{_presetdir}/ + +# Generate and install man pages. +mkdir -p %{buildroot}%{_mandir}/man1 +help2man -N -i %{SOURCE3} -s 1 \ + -o %{buildroot}%{_mandir}/man1/akmods.1 \ + %{buildroot}%{_sbindir}/akmods +help2man -N -i %{SOURCE3} -s 1 \ + -o %{buildroot}%{_mandir}/man1/akmodsbuild.1 \ + %{buildroot}%{_sbindir}/akmodsbuild + + +%pre +# create group and user +getent group akmods >/dev/null || groupadd -r akmods +getent passwd akmods >/dev/null || \ +useradd -r -g akmods -d /var/cache/akmods/ -s /sbin/nologin \ + -c "User is used by akmods to build akmod packages" akmods + +%post +%systemd_post akmods.service +%systemd_post akmods-shutdown.service + +%preun +%systemd_preun akmods.service +%systemd_preun akmods-shutdown.service + +%postun +%systemd_postun akmods.service +%systemd_postun akmods-shutdown.service + + +%files +%doc README +%license LICENSE +%{_sbindir}/akmodsbuild +%{_sbindir}/akmods-shutdown +%{_sbindir}/akmods +%{_sysconfdir}/kernel/postinst.d/akmodsposttrans +%{_unitdir}/akmods.service +%{_unitdir}/akmods-shutdown.service +%{_presetdir}/95-akmods.preset +%{_usrsrc}/akmods +%attr(-,akmods,akmods) %{_localstatedir}/cache/akmods +%{_mandir}/man1/* + + +%changelog +* Mon Mar 6 2017 Hans de Goede - 0.5.6-5 +- Add LICENSE file (rhbz#1422918) + +* Fri Feb 24 2017 Hans de Goede - 0.5.6-4 +- Replace %%{_prefix}/lib/systemd/system-preset with %%{_presetdir} + +* Thu Feb 16 2017 Hans de Goede - 0.5.6-3 +- Submit to Fedora for package review + +* Mon Nov 28 2016 Nicolas Chauvet - 0.5.6-2 +- Use Suggests kernel-devel weak-dependency - see rfbz#3386 + +* Fri Oct 14 2016 Richard Shaw - 0.5.6-1 +- Disable shutdown systemd service file by default. +- Remove modprobe line from main service file. + +* Wed Aug 17 2016 Sérgio Basto - 0.5.4-3 +- New release + +* Sun Jan 03 2016 Nicolas Chauvet - 0.5.4-2 +- Revert conflicts kernel-debug-devel + +* Thu Jul 23 2015 Richard Shaw - 0.5.4-1 +- Do not mark a build as failed when only installing the RPM fails. +- Run akmods-shutdown script instead of akmods on shutdown. +- Add systemd preset file to enable services by default. + +* Wed Jul 15 2015 Richard Shaw - 0.5.3-2 +- Add package conflicts to stop pulling in kernel-debug-devel, fixes BZ#3386. +- Add description for the formatting of the parameter, BZ#3580. +- Update static man pages and clean them up. +- Fixed another instance of TMPDIR causing issues. +- Added detection of dnf vs yum to akmods, fixed BZ#3481. + +* Wed Apr 1 2015 Richard Shaw - 0.5.2-1 +- Fix temporary directory creation when TMPDIR environment variable is set, + fixes BZ#2596. +- Update systemd scripts to use macros. +- Fix akmods run on shutdown systemd unit file, fixes BZ#3503. + +* Sun Nov 16 2014 Nicolas Chauvet - 0.5.1-4 +- Fix akmods on armhfp - rfbz#3117 +- Use yum instead of rpm to install packages - rfbz#3350 + Switch to a better date format + +* Fri Jan 11 2013 Richard Shaw - 0.5.1-3 +- Really fix akmods.service.in. + +* Fri Jun 01 2012 Richard Shaw - 0.5.1-2 +- Add service file to run again on shutdown. +- Add conditional for Fedora 18 to specify correct systemd graphical service. + +* Thu Apr 12 2012 Nicolas Chauvet - 0.4.0-4 +- Rebuilt + +* Tue Mar 20 2012 Richard Shaw - 0.4.0-3 +- Add additional error output if the needed kernel development files are not + installed. (Fixes #561) + +* Mon Mar 05 2012 Richard Shaw - 0.4.0-2 +- Remove remaining references to previous Fedora releases +- Remove legacy SysV init script from CVS. +- Added man page for akmods and cleaned up man page for akmodsbuild. + +* Tue Feb 07 2012 Nicolas Chauvet - 0.4.0-1 +- Update for UsrMove support +- Remove unused references to older fedora +- Change Requires from kernel-devel to kernel-devel-uname-r diff --git a/akmodsbuild b/akmodsbuild new file mode 100644 index 0000000..8cc18a9 --- /dev/null +++ b/akmodsbuild @@ -0,0 +1,358 @@ +#!/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 / ]]; 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 rpmduild 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 diff --git a/akmodsinit b/akmodsinit new file mode 100644 index 0000000..8489151 --- /dev/null +++ b/akmodsinit @@ -0,0 +1,47 @@ +#!/bin/bash - +# +# akmodinit Builds and install new kmods from akmod packages +# +# Author: Thorsten Leemhuis +# +# chkconfig: 2345 5 95 +# +# description: akmodsinit calls akmod during system boot to build and install +# kmods for the currently running kernel if neccessary. +# +# processname: akmodsd +# pidfile: /var/run/akmodsd.pid +# + +### BEGIN INIT INFO +# Provides: akmodsd +# Required-Start: $local_fs +# Required-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Builds and install new kmods from akmod packages +# Description: akmodsinit calls akmod during system boot to build and install +# kmods for the currently running kernel if neccessary. +### END INIT INFO + +start_akmods () +{ + # build and install all kmods if neccessary + # for the currently running kernel (default in akmods) + /usr/sbin/akmods --from-init +} + + +# See how we were called. +case "$1" in + start|restart|reload|condrestart) + start_akmods + ;; + stop|status) + exit 0 + ;; + *) + echo $"Usage: $0 start" + exit 1 + ;; +esac diff --git a/akmodsposttrans b/akmodsposttrans new file mode 100644 index 0000000..c619952 --- /dev/null +++ b/akmodsposttrans @@ -0,0 +1,37 @@ +#!/bin/bash - +# +# akmodposttrans - Calls akmods for newly installed kernels +# +# Copyright (c) 2009 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. +# +# todo-list: +# - scary idea: install kernel-devel packages on demand? +# - redirect output to a seperate logfile? + +# just check in case a user calls this directly +if [[ ! -w / ]]; then + echo "Needs to run as root to be able to install rpms." >&2 + exit 1 +fi + +# needs to run in background as rpmdb might be locked otherwise +nohup /usr/sbin/akmods --from-kernel-posttrans --kernels ${1} &> /dev/null &