initial import
This commit is contained in:
194
dkms/hook.sh
Normal file
194
dkms/hook.sh
Normal file
@@ -0,0 +1,194 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2018 Sébastien Luttringer
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
# display what to run and run it quietly
|
||||
run() {
|
||||
echo "==> $*"
|
||||
"$@" > /dev/null
|
||||
}
|
||||
|
||||
# check whether the dependencies of a module are installed
|
||||
# $1: module name/module version
|
||||
# $2: kernel version
|
||||
check_dependency() { (
|
||||
source "$source_tree/${1/\//-}/dkms.conf"
|
||||
for dep in "${BUILD_DEPENDS[@]}"; do
|
||||
if ! [[ "$(dkms status -m "$dep" -k "$2")" =~ :[[:space:]]installed$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
) }
|
||||
|
||||
# check whether the modules should be built with this kernel version
|
||||
# $1: module name/module version
|
||||
# $2: kernel version
|
||||
check_buildexclusive() {
|
||||
local BUILD_EXCLUSIVE_KERNEL=$(source "$source_tree/${1/\//-}/dkms.conf"; printf '%s\n' "$BUILD_EXCLUSIVE_KERNEL")
|
||||
[[ "$2" =~ $BUILD_EXCLUSIVE_KERNEL ]]
|
||||
}
|
||||
|
||||
# handle actions on module addition/upgrade/removal
|
||||
# $1: module name
|
||||
# $2: module version
|
||||
parse_module() {
|
||||
pushd "$install_tree" >/dev/null
|
||||
local path
|
||||
for path in */build/; do
|
||||
local kver="${path%%/*}"
|
||||
dkms_register "$1" "$2" "$kver"
|
||||
done
|
||||
popd >/dev/null
|
||||
}
|
||||
|
||||
# handle actions on kernel addition/upgrade/removal
|
||||
# $1: kernel version
|
||||
parse_kernel() {
|
||||
local path
|
||||
for path in "$source_tree"/*-*/dkms.conf; do
|
||||
if [[ -f "$path" && "$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then
|
||||
dkms_register "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "$1"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# register a dkms module to install/remove
|
||||
# this function suppress echo call for a module
|
||||
# $1: module name, $2: module version, $3: kernel version
|
||||
dkms_register() {
|
||||
DKMS_MODULES["$1/$2/$3"]=''
|
||||
}
|
||||
|
||||
# install registered modules
|
||||
dkms_install() {
|
||||
local nvk mod kver
|
||||
local -i retry=1
|
||||
|
||||
while (( $retry > 0 )); do
|
||||
retry=0
|
||||
for nvk in "${!DKMS_MODULES[@]}"; do
|
||||
mod=${nvk%/*}
|
||||
kver=${nvk##*/}
|
||||
# do not build excluded modules
|
||||
if ! check_buildexclusive "$mod" "$kver"; then
|
||||
unset DKMS_MODULES[$nvk]
|
||||
continue
|
||||
# skip modules with missing kernel headers
|
||||
elif [[ ! -d "$install_tree/$kver/build/include" ]]; then
|
||||
DKMS_MODULES[$nvk]="Missing kernel headers"
|
||||
continue
|
||||
# skip modules with missing kernel package
|
||||
elif [[ ! -d "$install_tree/$kver/kernel" ]]; then
|
||||
DKMS_MODULES[$nvk]="Missing kernel modules tree"
|
||||
continue
|
||||
# postpone modules with missing dependencies
|
||||
elif ! check_dependency "$mod" "$kver"; then
|
||||
DKMS_MODULES[$nvk]="Missing dependency"
|
||||
continue
|
||||
fi
|
||||
# give it a try dkms
|
||||
run dkms install "$mod" -k "$kver"
|
||||
unset DKMS_MODULES[$nvk]
|
||||
# maybe this module was a dep of another, so we retry
|
||||
retry=1
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# remove registered modules when built/installed
|
||||
dkms_remove() {
|
||||
local nvk mod kver
|
||||
for nvk in "${!DKMS_MODULES[@]}"; do
|
||||
mod=${nvk%/*}
|
||||
kver=${nvk##*/}
|
||||
state=$(dkms status -m "$mod" -k "$kver")
|
||||
if [[ "$state" =~ :[[:space:]](built|installed)$ ]]; then
|
||||
run dkms remove "$mod" -k "$kver"
|
||||
fi
|
||||
unset DKMS_MODULES[$nvk]
|
||||
done
|
||||
}
|
||||
|
||||
# show information about failed modules
|
||||
show_errors() {
|
||||
local nvk mod kver
|
||||
for nvk in "${!DKMS_MODULES[@]}"; do
|
||||
mod=${nvk%/*}
|
||||
kver=${nvk##*/}
|
||||
echo "==> Unable to $DKMS_ACTION module $mod for kernel $kver: ${DKMS_MODULES[$nvk]}."
|
||||
done
|
||||
}
|
||||
|
||||
# emulated program entry point
|
||||
main() {
|
||||
[[ -n "$DKMS_ALPM_HOOK_DEBUG" ]] && set -x
|
||||
|
||||
# prevent each dkms call from failing with authorization errors
|
||||
if (( EUID )); then
|
||||
echo 'You must be root to use this hook' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# register DKMS action
|
||||
case "$1" in
|
||||
install|remove)
|
||||
declare -r DKMS_ACTION="$1"
|
||||
;;
|
||||
*)
|
||||
echo "usage: ${0##*/} install|remove" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dkms path from framework config
|
||||
# note: the alpm hooks which trigger this script use static path
|
||||
source_tree='/usr/src'
|
||||
install_tree='/lib/modules'
|
||||
source /etc/dkms/framework.conf
|
||||
|
||||
# check source_tree and install_tree exists
|
||||
local path
|
||||
for path in "$source_tree" "$install_tree"; do
|
||||
if [[ ! -d "$path" ]]; then
|
||||
echo "==> Missing mandatory directory: $path. Exiting!"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# storage for DKMS modules to install/remove
|
||||
# we use associate arrays to prevent duplicate
|
||||
declare -A DKMS_MODULES
|
||||
|
||||
# parse stdin paths to guess what do do
|
||||
while read -r path; do
|
||||
if [[ "/$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then
|
||||
parse_module "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
|
||||
elif [[ "/$path" =~ ^$install_tree/([^/]+)/ ]]; then
|
||||
parse_kernel "${BASH_REMATCH[1]}"
|
||||
fi
|
||||
done
|
||||
|
||||
dkms_$DKMS_ACTION
|
||||
|
||||
show_errors
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user