summarylogtreecommitdiffstats
path: root/alpm-hook
diff options
context:
space:
mode:
Diffstat (limited to 'alpm-hook')
-rwxr-xr-xalpm-hook167
1 files changed, 167 insertions, 0 deletions
diff --git a/alpm-hook b/alpm-hook
new file mode 100755
index 000000000000..1e5f83b1e050
--- /dev/null
+++ b/alpm-hook
@@ -0,0 +1,167 @@
+#!/bin/bash
+
+#
+# Copyright © 2017 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 kernel is valid for action
+# it means kernel and its headers are installed
+# $1: kernel version
+check_kernel() {
+ local kver="$1"; shift
+ if [[ ! -d "$install_tree/$kver/kernel" ]]; then
+ echo "==> No kernel $kver modules. You must install them to use DKMS!"
+ return 1
+ elif [[ ! -d "$install_tree/$kver/build/Makefile" ]]; then
+ echo "==> No kernel $kver headers. You must install them to use DKMS!"
+ return 1
+ fi
+ return 0
+}
+
+# handle actions on module addition/upgrade/removal
+# $1: module name
+# $2: module version
+# $3: dkms action
+parse_module() {
+ pushd "$install_tree" >/dev/null
+ local path
+ for path in */build/; do
+ local kver="${path%%/*}"
+ dkms_register "$1" "$2" "$kver" "$3"
+ done
+ popd >/dev/null
+}
+
+# handle actions on kernel addition/upgrade/removal
+# $1: kernel version
+# $2: dkms action
+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" "$2"
+ fi
+ done
+}
+
+# register a dkms call
+# this function suppress echo call for a module
+# $1: module name, $2: module version, $3: kernel version, $4: action
+dkms_register() {
+ DKMS_ACTION["$1/$2/$3"]="$4"
+}
+
+# check whether the dependencies of a module are installed
+# $1: module name/module version
+# $2: kernel version
+check_dependency() {
+ local BUILD_DEPENDS
+ mod_name=${1%/*}
+ mod_ver=${1#*/}
+ readarray -t BUILD_DEPENDS <<<$(source "$source_tree/$mod_name-$mod_ver/dkms.conf"; printf '%s\n' "${BUILD_DEPENDS[@]}")
+ [ "$BUILD_DEPENDS" = "" ] && unset BUILD_DEPENDS
+ for dep in "${BUILD_DEPENDS[@]}"; do
+ if [ ! "$(dkms status -m "$dep" -k "$2" | grep -o installed)" = "installed" ]; then
+ return 1
+ fi
+ done
+ return 0
+}
+
+# run registered dkms commands
+dkms_run() {
+ local nvk mod kver cont
+ cont=y
+ while [ "$cont" = "y" ]; do
+ cont=n
+ for nvk in "${!DKMS_ACTION[@]}"; do
+ mod=${nvk%/*}
+ kver=${nvk##*/}
+ check_kernel "$kver" || continue
+ if [ "${DKMS_ACTION[$nvk]}" = "install" ]; then
+ check_dependency "$mod" "$kver" || continue
+ fi
+ run dkms "${DKMS_ACTION[$nvk]}" "$mod" -k "$kver"
+ cont=y
+ unset DKMS_ACTION[$nvk]
+ done
+ done
+ # show warning for modules not installed
+ for nvk in "${!DKMS_ACTION[@]}"; do
+ [ "${DKMS_ACTION[$nvk]}" = "install" ] || continue
+ mod=${nvk%/*}
+ kver=${nvk##*/}
+ check_kernel "$kver" || continue
+ echo "==> WARNING: Cannot resolve dependencies for module $mod, kernel version $kver"
+ done
+}
+
+# emulated program entry point
+main() {
+ [[ -n "$DKMS_ALPM_HOOK_DEBUG" ]] && set -x
+
+ # prevent to have all each dkms call to fail
+ if (( EUID )); then
+ echo 'You must be root to use this hook' >&2
+ exit 1
+ fi
+
+ # check args count
+ if (( $# < 1 )); then
+ echo "usage: ${0##*/} dkms-arguments" >&2
+ exit 1
+ fi
+
+ # dkms path from framework config
+ # note: the alpm hooks which trigger this script use static path
+ source_tree='/usr/src'
+ install_tree='/usr/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 action to run
+ declare -A DKMS_ACTION
+
+ # 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_run
+
+ return 0
+}
+
+main "$@"