commit c92dc1ae81f4f5c6c7a83850508ef1cdd3dd5cf4 Author: EnumDev Date: Sat May 9 18:35:55 2026 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d96df7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Ignore BPM archives and signatures +*.bpm +*.bpm.sig diff --git a/check-version.sh b/check-version.sh new file mode 100644 index 0000000..171aaee --- /dev/null +++ b/check-version.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Github repository +REPO="dkms-project/dkms" + +# Get tag name using Github Rest API +TAG_NAME=$(curl -s -L -H "X-GitHub-Api-Version: 2022-11-28" -H "Authorization: token ${GITHUB_API_TOKEN}" https://api.github.com/repos/"$REPO"/releases/latest | jq -r '.tag_name') + +# Trim 'v' character in TAG_NAME variable +VERSION=$(echo "$TAG_NAME" | tr -d 'v') + +echo "$VERSION" diff --git a/pkg.info b/pkg.info new file mode 100644 index 0000000..3a9adef --- /dev/null +++ b/pkg.info @@ -0,0 +1,25 @@ +name: dkms +description: Dynamic Kernel Modules System +version: 3.4.1 +revision: 1 +url: https://github.com/dkms-project/dkms +license: GPL2-or-later +maintainers: + - enumdev@enumerated.dev +architecture: any +output_architecture: any +type: source +depends: + - bash + - coreutils + - gawk + - kmod + - sed +optional_depends: + - linux-stable-headers:To build modules for the stable kernel + - linux-lts-headers:To build modules for the longterm support kernel +downloads: + - url: https://github.com/dkms-project/dkms/archive/refs/tags/v${BPM_PKG_VERSION}.tar.gz + extract_to: ${BPM_SOURCE} + extract_strip_components: 1 + checksum: c45b7b48f3569b0328594bcdc70058294a669ad7348484ae00758a73a4e91120 diff --git a/source-files/dkms-install.bpmhook b/source-files/dkms-install.bpmhook new file mode 100644 index 0000000..9dd8d06 --- /dev/null +++ b/source-files/dkms-install.bpmhook @@ -0,0 +1,7 @@ +trigger_operations: ["install", "upgrade"] +target_type: "path" +targets: + - "usr/src/*/dkms.conf" + - "usr/lib/modules/*/build/include/" + - "usr/lib/modules/*/modules.order" +run: "/var/lib/bpm/hook-scripts/dkms.sh install" diff --git a/source-files/dkms-remove.bpmhook b/source-files/dkms-remove.bpmhook new file mode 100644 index 0000000..ffb4d57 --- /dev/null +++ b/source-files/dkms-remove.bpmhook @@ -0,0 +1,7 @@ +trigger_operations: ["remove"] +target_type: "path" +targets: + - "usr/src/*/dkms.conf" + - "usr/lib/modules/*/build/include/" + - "usr/lib/modules/*/modules.order" +run: "/var/lib/bpm/hook-scripts/dkms.sh remove" diff --git a/source-files/dkms-upgrade.bpmhook b/source-files/dkms-upgrade.bpmhook new file mode 100644 index 0000000..72dbc45 --- /dev/null +++ b/source-files/dkms-upgrade.bpmhook @@ -0,0 +1,7 @@ +trigger_operations: ["upgrade"] +target_type: "path" +targets: + - "usr/src/*/dkms.conf" + - "usr/lib/modules/*/build/include/" + - "usr/lib/modules/*/modules.order" +run: "/var/lib/bpm/hook-scripts/dkms.sh -D remove" diff --git a/source-files/dkms.sh b/source-files/dkms.sh new file mode 100644 index 0000000..6c685ee --- /dev/null +++ b/source-files/dkms.sh @@ -0,0 +1,303 @@ +#!/bin/bash + +# +# Copyright © 2018-2021, 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 + local ret=$? + (( $ret )) && echo "==> WARNING: \`$*' exited $ret" + return $ret +} + +# check whether the dependencies of a module are installed +# $1: module name +# $2: module version +# $3: kernel version +check_dependency() { ( + source "$source_tree/$1-$2/dkms.conf" + local mod lines line + for mod in "${BUILD_DEPENDS[@]}"; do + mapfile lines < <(dkms status -m "$mod" -k "$3") + for line in "${lines[@]}"; do + [[ "$line" =~ "$mod/"[^,]+", $3, "[^:]+': installed' ]] && break 2 + done + exit 1 + done + exit 0 +) } + +# check whether the modules should be built with this kernel version +# $1: module name +# $2: module version +# $3: kernel version +check_buildexclusive() { + local BUILD_EXCLUSIVE_KERNEL=$(source "$source_tree/$1-$2/dkms.conf"; printf '%s\n' "$BUILD_EXCLUSIVE_KERNEL") + [[ "$3" =~ $BUILD_EXCLUSIVE_KERNEL ]] +} + +# list all kernel versions +all_kver() { + pushd "$install_tree" >/dev/null + local path + for path in */build/; do + echo "${path%%/*}" + done + popd >/dev/null +} + +# list all module name/version for a specific kernel version +# $1: kernel version +all_nv_from_kver() { + local path + for path in "$source_tree"/*-*/dkms.conf; do + if [[ -f "$path" && "$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then + echo "${BASH_REMATCH[1]}/${BASH_REMATCH[2]}" + fi + done +} + +# list of modules/version for installed/built kernel version +# $1: kernel version +built_nv_from_kver() { + local line + dkms status -k "$1" | while read -r line; do + if [[ "$line" =~ ^([^/]+/[^,]+)", $1, "[^:]+": "(built|installed) ]]; then + echo "${BASH_REMATCH[1]}" + fi + done +} + +# list installed or built kernel version for a specific module version +# $1 : module name/module version +built_kver_from_nv() { + local line + dkms status "$1" | while read -r line; do + if [[ "$line" =~ ^"$1, "([^,]+)", "[^:]+": "(built|installed) ]]; then + echo "${BASH_REMATCH[1]}" + fi + done +} + +# install registered modules +dkms_install() { + # list of modules to build for a specific kernel + local -A tobuild=() + + # add new/updated modules for all kernels to the build list + local nv kver + for nv in "${!DKMS_MODULES[@]}"; do + for kver in $(all_kver); do + tobuild["$nv/$kver"]='' + done + done + # add modules for new/updated kernels to the build list + for kver in "${!KERNEL_VERSIONS[@]}"; do + for nv in $(all_nv_from_kver "$kver"); do + tobuild["$nv/$kver"]='' + done + done + + # list of kver which requires depmod refresh + local -A depmods=() + + # let's build and install + local nvk mod mver + local -i retry=1 + while (( $retry > 0 )); do + retry=0 + for nvk in "${!tobuild[@]}"; do + [[ "$nvk" =~ ([^/]+)/([^/]+)/(.+) ]] || continue + mod="${BASH_REMATCH[1]}" + mver="${BASH_REMATCH[2]}" + kver="${BASH_REMATCH[3]}" + # do not build excluded modules + if ! check_buildexclusive "$mod" "$mver" "$kver"; then + unset tobuild[$nvk] + continue + # skip modules with missing kernel headers + elif [[ ! -d "$install_tree/$kver/build/include" ]]; then + ERROR_MESSAGES+=("Missing $kver kernel headers for module $mod/$mver.") + unset tobuild[$nvk] + continue + # skip modules with missing kernel package + elif [[ ! -d "$install_tree/$kver/kernel" ]]; then + ERROR_MESSAGES+=("Missing $kver kernel modules tree for module $mod/$mver.") + unset tobuild[$nvk] + continue + # postpone modules with missing dependencies + elif ! check_dependency "$mod" "$mver" "$kver"; then + continue + fi + # give it a try dkms + run dkms install --no-depmod "$mod/$mver" -k "$kver" + if (( $? == 0 )); then + # register kernel version for later depmod + depmods[$kver]='' + fi + unset tobuild[$nvk] + # maybe this module was a dep of another, so we retry + retry=1 + done + done + # run depmod later for performance improvments + if (( $DKMS_DEPMOD )); then + for kver in "${!depmods[@]}"; do + run depmod "$kver" + done + fi + # add errors messages for missing dependencies modules + for nvk in "${!tobuild[@]}"; do + [[ "$nvk" =~ ([^/]+/[^/]+)/(.+) ]] || continue + nv="${BASH_REMATCH[1]}" + kver="${BASH_REMATCH[2]}" + ERROR_MESSAGES+=("Missing dependencies to install module $nv for kernel $kver.") + done +} + +# remove registered modules +# run depmod once per kernel for performance improvments +dkms_remove() { + local nv kver + local -A depmods=() + # remove full modules first + for nv in "${!DKMS_MODULES[@]}"; do + # try to remove modules one by one to keep the depmod optimization + for kver in $(built_kver_from_nv "$nv"); do + run dkms remove --no-depmod "$nv" -k "$kver" + if (( $? == 0 )); then + # register kernel version for later depmod + depmods[$kver]='' + else + ERROR_MESSAGES+=("Failed to remove module $nv for kernel $kver.") + fi + done + # ensure module removal (even if only added) + if [[ $(dkms status "$nv") ]]; then + run dkms remove "$nv" + (( $? == 0 )) || ERROR_MESSAGES+=("Failed to remove module $nv.") + fi + done + # remove modules for a specific kernel version + for kver in "${!KERNEL_VERSIONS[@]}"; do + for nv in $(built_nv_from_kver "$kver"); do + run dkms remove --no-depmod "$nv" -k "$kver" + if (( $? == 0 )); then + # register kernel version for later depmod + depmods[$kver]='' + else + ERROR_MESSAGES+=("Failed to remove module $nv for kernel $kver.") + fi + done + done + # run depmod later for performance improvments + if (( $DKMS_DEPMOD )); then + for kver in "${!depmods[@]}"; do + run depmod "$kver" + done + fi +} + +# display hook usage and exit $1 (default 1) +usage() { + cat << EOF >&2 +usage: ${0##*/} install|remove +options: -D Do not run depmod +EOF + exit ${1:-1} +} + +# emulated program entry point +main() { + [[ "$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 + return 1 + fi + + # parse command line options + declare -i DKMS_DEPMOD=1 + local opt + while getopts 'hD' opt; do + case $opt in + D) DKMS_DEPMOD=0;; + *) usage;; + esac + done + shift $((OPTIND - 1)) + (( $# != 1 )) && usage + + # parse command action to early exit + case "$1" in + install|remove) declare -r DKMS_ACTION="$1";; + *) usage;; + esac + + # 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!" >&2 + return 1 + fi + done + + # global storage for changed DKMS modules + # we use associate arrays to prevent duplication + # the key is // + declare -A DKMS_MODULES + + # global storage for changed linux kernels + # we use associate arrays to prevent duplication + declare -A KERNEL_VERSIONS + + # global storage for error messages + declare -a ERROR_MESSAGES + + # parse stdin paths to guess what we should install/remove + while read -r path; do + if [[ "/$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then + # we match file updates on dkms modules sources + DKMS_MODULES["${BASH_REMATCH[1]}/${BASH_REMATCH[2]}"]='' + elif [[ "/$path" =~ ^$install_tree/([^/]+)/ ]]; then + # we match file updates on kernels install/removal + KERNEL_VERSIONS["${BASH_REMATCH[1]}"]='' + fi + done + + dkms_$DKMS_ACTION + + # display errors at the end, to maximize readers + local msg + for msg in "${ERROR_MESSAGES[@]}"; do + echo "==> ERROR: $msg" >&2 + done + + return 0 +} + +main "$@" diff --git a/source.sh b/source.sh new file mode 100644 index 0000000..df52a73 --- /dev/null +++ b/source.sh @@ -0,0 +1,21 @@ +# This is the source.sh script. It is executed by BPM in a temporary directory when compiling a source package +# BPM Expects the source code to be extracted into the automatically created 'source' directory which can be accessed using $BPM_SOURCE +# BPM Expects the output files to be present in the automatically created 'output' directory which can be accessed using $BPM_OUTPUT + +# The package function is executed in the source directory +# This function is used to move the compiled files into the output directory +package() { + make DESTDIR="$BPM_OUTPUT" KCONF=/../trash BINDIR=/../trash MODDIR=/usr/lib/modules install + + # Install bpm hooks + install -Dm644 "$BPM_WORKDIR"/dkms-install.bpmhook "$BPM_OUTPUT"/var/lib/bpm/hooks/70-dkms-install.bpmhook + install -Dm644 "$BPM_WORKDIR"/dkms-remove.bpmhook "$BPM_OUTPUT"/var/lib/bpm/hooks/71-dkms-remove.bpmhook + install -Dm644 "$BPM_WORKDIR"/dkms-upgrade.bpmhook "$BPM_OUTPUT"/var/lib/bpm/hooks/70-dkms-upgrade.bpmhook + + + # Install hook script from Arch Linux + install -Dm755 "$BPM_WORKDIR"/dkms.sh "$BPM_OUTPUT"/var/lib/bpm/hook-scripts/dkms.sh + + # Install package license + install -Dm644 "$BPM_SOURCE"/COPYING "$BPM_OUTPUT"/usr/share/licenses/dkms/COPYING +}