summaryrefslogtreecommitdiffstats
path: root/dkms.in
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:40:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:40:50 +0000
commit10b5bfdee99e8161f353593ee3e85f4775b1dedc (patch)
tree958ac703fcfc692348b1564f02317e9f2ca67fd5 /dkms.in
parentInitial commit. (diff)
downloaddkms-10b5bfdee99e8161f353593ee3e85f4775b1dedc.tar.xz
dkms-10b5bfdee99e8161f353593ee3e85f4775b1dedc.zip
Adding upstream version 3.0.13.upstream/3.0.13upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dkms.in')
-rw-r--r--dkms.in2670
1 files changed, 2670 insertions, 0 deletions
diff --git a/dkms.in b/dkms.in
new file mode 100644
index 0000000..55eced3
--- /dev/null
+++ b/dkms.in
@@ -0,0 +1,2670 @@
+#!/bin/bash
+#
+# Dynamic Kernel Module Support (DKMS) <dkms-devel@dell.com>
+# Copyright (C) 2003-2008 Dell, Inc.
+# by Gary Lerhaupt, Matt Domsch, & Mario Limonciello
+# Copyright (C) 2012 by Darik Horn <dajhorn@vanadac.com>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+shopt -s extglob
+
+# All of the variables we will accept from dkms.conf.
+# Does not include directives
+# The last group of variables has been deprecated
+readonly dkms_conf_variables="CLEAN PACKAGE_NAME
+ PACKAGE_VERSION POST_ADD POST_BUILD POST_INSTALL POST_REMOVE PRE_BUILD
+ PRE_INSTALL BUILD_DEPENDS BUILD_EXCLUSIVE_ARCH BUILD_EXCLUSIVE_CONFIG
+ BUILD_EXCLUSIVE_KERNEL BUILD_EXCLUSIVE_KERNEL_MIN BUILD_EXCLUSIVE_KERNEL_MAX
+ build_exclude OBSOLETE_BY MAKE MAKE_MATCH
+ PATCH PATCH_MATCH patch_array BUILT_MODULE_NAME
+ built_module_name BUILT_MODULE_LOCATION built_module_location
+ DEST_MODULE_NAME dest_module_name
+ DEST_MODULE_LOCATION dest_module_location
+ STRIP strip AUTOINSTALL NO_WEAK_MODULES
+ SIGN_FILE MOK_SIGNING_KEY MOK_CERTIFICATE
+
+ REMAKE_INITRD MODULES_CONF MODULES_CONF_OBSOLETES
+ MODULES_CONF_ALIAS_TYPE MODULES_CONF_OBSOLETE_ONLY"
+
+# All of the variables not related to signing we will accept from framework.conf.
+readonly dkms_framework_nonsigning_variables="source_tree dkms_tree install_tree tmp_location
+ verbose symlink_modules autoinstall_all_kernels
+ modprobe_on_install"
+# All of the signing related variables we will accept from framework.conf.
+readonly dkms_framework_signing_variables="sign_file mok_signing_key mok_certificate"
+
+# Some important regular expressions. Requires bash 3 or above.
+# Any poor souls still running bash 2 or older really need an upgrade.
+readonly mv_re='^([^/]*)/(.*)$'
+
+# Areas that will vary between Linux and other OS's
+_get_kernel_dir() {
+ if [[ -z $ksourcedir_fromcli ]]; then
+ KVER=$1
+ case ${current_os} in
+ Linux) DIR="$install_tree/$KVER/build" ;;
+ GNU/kFreeBSD) DIR="/usr/src/kfreebsd-headers-$KVER/sys" ;;
+ esac
+ echo $DIR
+ else
+ echo $kernel_source_dir
+ fi
+}
+
+_check_kernel_dir() {
+ DIR=$(_get_kernel_dir $1)
+ case ${current_os} in
+ Linux) test -e $DIR/include ;;
+ GNU/kFreeBSD) test -e $DIR/kern && test -e $DIR/conf/kmod.mk ;;
+ *) return 1 ;;
+ esac
+ return $?
+}
+
+# Run a command that we may or may not want to be detailed about.
+invoke_command()
+{
+ # $1 = command to be executed using eval.
+ # $2 = Description of command to run
+ # $3 = Redirect command output to this file
+ # $4 = 'background' if you want to run the command asynchronously.
+ local exitval=0
+ local -r cmd=$([[ $3 ]] && echo "{ $1; } >> $3 2>&1" || echo "$1")
+
+ [[ $verbose ]] && echo -e "$cmd" || echo -en "$2..."
+ if [[ $4 = background && ! $verbose ]]; then
+ local pid progresspid
+ (eval "$cmd" >/dev/null 2>&1) & pid=$!
+ {
+ on_exit() {
+ kill $(jobs -p) 2>/dev/null
+ wait $(jobs -p) 2>/dev/null
+ }
+ trap on_exit EXIT
+ while /bin/kill --signal 0 $pid > /dev/null 2>&1; do
+ sleep 3 &
+ wait $!
+ echo -en "."
+ done
+ } & progresspid=$!
+ wait $pid 2>/dev/null
+ exitval=$?
+ kill $progresspid 2>/dev/null
+ wait $progresspid 2>/dev/null
+ else
+ eval "$cmd"; exitval=$?
+ fi
+ if (($exitval > 0)); then
+ echo -en "(bad exit status: $exitval)"
+ # Print the failing command without the clunky redirection
+ [[ ! $verbose ]] && echo -en "\nFailed command:\n$1"
+ fi
+ echo -en "\n"
+ return $exitval
+}
+
+error() (
+ exec >&2
+ echo -n $"Error! "
+ for s in "$@"; do echo "$s"; done
+)
+
+warn() (
+ exec >&2
+ echo -n $"Warning: "
+ for s in "$@"; do echo "$s"; done
+)
+
+deprecated() (
+ exec >&2
+ echo -n $"Deprecated feature: "
+ for s in "$@"; do echo "$s"; done
+)
+
+# Print an error message and die with the passed error code.
+die() {
+ # $1 = error code to return with
+ # rest = strings to print before we exit.
+ ret=$1
+ shift
+ error "$@"
+ [[ $die_is_fatal = yes ]] && exit $ret || return $ret
+}
+
+# Print a warning message and die with the passed error code.
+diewarn() {
+ # $1 = error code to return with
+ # rest = strings to print before we exit.
+ ret=$1
+ shift
+ warn "$@"
+ [[ $die_is_fatal = yes ]] && exit $ret || return $ret
+}
+
+mktemp_or_die() {
+ local t
+ t=$(mktemp "$@") && echo "$t" && return
+ [[ $* = *-d* ]] && die 1 $"Unable to make temporary directory"
+ die 1 "Unable to make temporary file."
+}
+
+show_usage()
+{
+ echo $"Usage: $0 [action] [options]"
+ echo $" [action] = { add | remove | build | unbuild | install | uninstall | match |"
+ echo $" autoinstall | mktarball | ldtarball | status }"
+ echo $" [options] = [-m module] [-v module-version] [-k kernel-version] [-a arch]"
+ echo $" [-c dkms.conf-location] [-q] [--force] [--force-version-override] [--all]"
+ echo $" [--templatekernel=kernel] [--directive='cli-directive=cli-value']"
+ echo $" [--config=kernel-.config-location] [--archive=tarball-location]"
+ echo $" [--kernelsourcedir=source-location] [--rpm_safe_upgrade]"
+ echo $" [--dkmstree path] [--sourcetree path] [--installtree path]"
+ echo $" [--binaries-only] [--source-only] [--verbose]"
+ echo $" [--no-depmod] [--modprobe-on-install] [-j number] [--version]"
+}
+
+VER()
+{
+ # $1 = kernel version string
+
+ # Pad all numbers in $1 so that they have at least three digits, e.g.,
+ # 2.6.9-1cvs200409091247 => 002.006.009-001cvs200409091247
+ # The result should compare correctly as a string.
+
+ echo $1 | sed -e 's:\([^0-9]\)\([0-9]\):\1 \2:g' \
+ -e 's:\([0-9]\)\([^0-9]\):\1 \2:g' \
+ -e 's:\(.*\): \1 :' \
+ -e 's: \([0-9]\) : 00\1 :g' \
+ -e 's: \([0-9][0-9]\) : 0\1 :g' \
+ -e 's: ::g'
+}
+
+# Find out how many CPUs there are so that we may pass an appropriate -j
+# option to make. Ignore hyperthreading for now.
+get_num_cpus()
+{
+ # use nproc(1) from coreutils 8.1-1+ if available, otherwise single job
+ if [[ -x /usr/bin/nproc ]]; then
+ nproc
+ else
+ echo "1"
+ fi
+}
+
+# Finds a .ko or .ko.xz based on a directory and module name
+# must call set_module_suffix first
+compressed_or_uncompressed()
+{
+ # module dir = $1
+ # module = $2
+ local test1="$1/$2$module_uncompressed_suffix"
+ local test2="$1/$2$module_uncompressed_suffix$module_compressed_suffix"
+ if [[ -e "$test1" ]]; then
+ echo "$test1"
+ elif [[ -e "$test2" ]]; then
+ echo "$test2"
+ fi
+}
+
+# Finds .ko or .ko.xz based on a tree and module name
+# must call set_module_suffix first
+find_module()
+{
+ # tree = $1
+ # module = $2
+ find "$1" -name "$2$module_uncompressed_suffix" -o -name "$2$module_suffix" -type f
+ return $?
+}
+
+
+# Figure out the correct module suffix for the kernel we are currently
+# dealing with, which may or may not be the currently installed kernel.
+set_module_suffix()
+{
+ # $1 = the kernel to base the module_suffix on
+ kernel_test="${1:-$(uname -r)}"
+ module_uncompressed_suffix=".ko"
+ grep -q '\.gz:' $install_tree/$kernel_test/modules.dep 2>/dev/null && module_compressed_suffix=".gz"
+ grep -q '\.xz:' $install_tree/$kernel_test/modules.dep 2>/dev/null && module_compressed_suffix=".xz"
+ grep -q '\.zst:' $install_tree/$kernel_test/modules.dep 2>/dev/null && module_compressed_suffix=".zst"
+ module_suffix="$module_uncompressed_suffix$module_compressed_suffix"
+}
+
+set_kernel_source_dir_and_kconfig()
+{
+ if [[ -z "${ksourcedir_fromcli}" ]]; then
+ # $1 = the kernel to base the directory on
+ kernel_source_dir="$(_get_kernel_dir "$1")"
+ fi
+ if [[ -z "${kconfig_fromcli}" ]]; then
+ kernel_config="${kernel_source_dir}/.config"
+ fi
+}
+
+check_all_is_banned()
+{
+ if [[ $all ]]; then
+ die 5 $"The action $1 does not support the --all parameter."
+ fi
+}
+
+# A little test function for DKMS commands that only work on one kernel.
+have_one_kernel() {
+ if (( ${#kernelver[@]} != 1 )); then
+ die 4 $"The action $1 does not support multiple kernel version parameters on the command line."
+ fi
+ check_all_is_banned $1
+}
+
+# Set up the kernelver and arch arrays. You must have a 1:1 correspondence --
+# if there is an entry in kernelver[$i], there must also be an entry in arch[$i]
+# Note the special casing for the status action -- the status functions just
+# report on what we already have, and will break with the preprocessing that
+# this function provides.
+setup_kernels_arches()
+{
+ # If all is set, use dkms status to fill the arrays
+ if [[ $all && $1 != status ]]; then
+ local i=0
+ while read line; do
+ line=${line#*/}; line=${line#*/};
+ # (I would leave out the delimiters in the status output
+ # in the first place.)
+ kernelver[$i]=${line%/*}
+ arch[$i]=${line#*/}
+ i=$(($i + 1))
+ done < <(module_status_built "$module" "$module_version" | sort -V)
+ fi
+
+ # Set default kernel version and arch, if none set (but only --all isn't set)
+ if [[ $1 != status ]]; then
+ if [[ ! $kernelver && ! $all ]]; then
+ kernelver[0]=$(uname -r)
+ fi
+ if [[ ! $arch ]]; then
+ kernelver_rpm=$(rpm -qf "$install_tree/$kernelver" 2>/dev/null | \
+ grep -v "not owned by any package" | grep kernel | head -n 1)
+ if ! arch[0]=$(rpm -q --queryformat "%{ARCH}" "$kernelver_rpm" 2>/dev/null); then
+ arch[0]=$(uname -m)
+ if [[ $arch = x86_64 ]] && grep -q Intel /proc/cpuinfo && ls $install_tree/$kernelver/build/configs 2>/dev/null | grep -q "ia32e"; then
+ arch[0]="ia32e"
+ fi
+ fi
+ fi
+ if [[ ! $arch ]]; then
+ die 12 $"Could not determine architecture."
+ fi
+ fi
+
+ # If only one arch is specified, make it so for all the kernels
+ if ((${#arch[@]} == 1 && ${#kernelver[@]} > 1)); then
+ while ((${#arch[@]} < ${#kernelver[@]})); do
+ arch[${#arch[@]}]=$arch
+ done
+ fi
+
+ # Set global multi_arch
+ multi_arch=""
+ local i=0
+ for ((i=0; $i < ${#arch[@]}; i++)); do
+ [[ $arch != ${arch[$i]} ]] && {
+ multi_arch="true"
+ break
+ }
+ done
+}
+
+do_depmod()
+{
+ if [[ $no_depmod ]]; then
+ return
+ fi
+ # $1 = kernel version
+ if [[ ${current_os} != Linux ]] ; then
+ return
+ fi
+ if [[ ! -f $install_tree/$1/modules.dep ]]; then
+ # if the corresponding linux image $1 is not installed
+ # do not create modules.dep
+ echo "Skipping depmod because '$install_tree/$1/modules.dep' is missing."
+ return
+ fi
+ if [[ -f /boot/System.map-$1 ]]; then
+ depmod -a "$1" -F "/boot/System.map-$1"
+ else
+ depmod -a "$1"
+ fi
+ if [[ -f $install_tree/$1/modules.dep && ! -s $install_tree/$1/modules.dep ]]; then
+ # if modules.dep is empty, we just removed the last kernel module from
+ # no longer installed kernel $1, so do not leave stale depmod files around
+ rm -fv $install_tree/$1/modules.{alias,dep,devname,softdep,symbols,*.bin}
+ rmdir --ignore-fail-on-non-empty $install_tree/$1
+ [[ -d $install_tree/$1 ]] || echo $"removed directory $install_tree/$1"
+ fi
+}
+
+# Grab distro information from os-release.
+distro_version()
+{
+ for f in /etc/os-release /usr/lib/os-release; do
+ if [[ -e $f ]]; then
+ (
+ . "$f"
+ if [[ "$ID" = "ubuntu" ]]; then
+ # ID_LIKE=debian in ubuntu
+ echo $ID
+ elif [[ ${#ID_LIKE[@]} != 0 ]]; then
+ echo ${ID_LIKE[0]}
+ else
+ echo $ID
+ fi
+ )
+ return
+ fi
+ done
+ die 4 $"System is missing os-release file."
+}
+
+override_dest_module_location()
+{
+ local orig_location="$1"
+ [[ ${addon_modules_dir} ]] && echo "/${addon_modules_dir}" && return
+
+ if [[ $current_os = GNU/kFreeBSD ]] ; then
+ # Does not support subdirs, regardless of distribution
+ echo "" && return
+ fi
+
+ case "$running_distribution" in
+ fedora* | rhel* | ovm*)
+ echo "/extra" && return
+ ;;
+ sles* | suse* | opensuse*)
+ echo "/updates" && return
+ ;;
+ debian* | ubuntu*)
+ echo "/updates/dkms" && return
+ ;;
+ arch*)
+ echo "/updates/dkms" && return
+ ;;
+ *)
+ ;;
+ esac
+ echo "$orig_location"
+}
+
+# Source a file safely.
+# We want to ensure that the .conf file we source does not stomp all over
+# parts of the environment we don't want them to. This makes it so that
+# it is harder to accidentally corrupt our environment. conf files can
+# still deliberately trash the environment by abusing dkms_directive env
+# variables or by crafting special values that will make eval do evil things.
+safe_source() {
+ # $1 = file to source
+ # $@ = environment variables to echo out
+ local to_source_file="$1"; shift
+ declare -a -r export_envs=("$@")
+ local tmpfile=$(mktemp_or_die)
+ ( exec >"$tmpfile"
+ . "$to_source_file" >/dev/null
+ # This is really ugly, but a neat hack
+ # Remember, in bash 2.0 and greater all variables are really arrays.
+ for _export_env in "${export_envs[@]}"; do
+ for _i in $(eval echo \${!$_export_env[@]}); do
+ eval echo '$_export_env[$_i]=\"${'$_export_env'[$_i]}\"'
+ done
+ done
+
+ # handle DKMS_DIRECTIVE stuff specially.
+ for directive in $(set | grep ^DKMS_DIRECTIVE | cut -d = -f 2-3); do
+ directive_name=${directive%%=*}
+ directive_value=${directive#*=}
+ echo "$directive_name=\"$directive_value\""
+ done
+ )
+ . "$tmpfile"
+ rm "$tmpfile"
+
+ (( ${#REMAKE_INITRD[@]} )) && deprecated "REMAKE_INITRD ($to_source_file)"
+ (( ${#MODULES_CONF[@]} )) && deprecated "MODULES_CONF ($to_source_file)"
+ (( ${#MODULES_CONF_OBSOLETES[@]} )) && deprecated "MODULES_CONF_OBSOLETES ($to_source_file)"
+ (( ${#MODULES_CONF_ALIAS_TYPE[@]} )) && deprecated "MODULES_CONF_ALIAS_TYPE ($to_source_file)"
+ (( ${#MODULES_CONF_OBSOLETE_ONLY[@]} )) && deprecated "MODULES_CONF_OBSOLETE_ONLY ($to_source_file)"
+}
+
+# Source a dkms.conf file and perform appropriate postprocessing on it.
+# Do our best to not repeatedly source the same .conf file -- this can happen
+# when chaining module installation functions or autoinstalling.
+read_conf()
+{
+ # $1 kernel version (required)
+ # $2 arch (required)
+ # $3 dkms.conf location (optional)
+
+ local return_value=0
+ local read_conf_file="$dkms_tree/$module/$module_version/source/dkms.conf"
+
+ # Set variables supported in dkms.conf files (eg. $kernelver)
+ local kernelver="$1"
+ local arch="$2"
+ set_kernel_source_dir_and_kconfig "$1"
+
+
+ # Find which conf file to check
+ [[ $conf ]] && read_conf_file="$conf"
+ [[ $3 ]] && read_conf_file="$3"
+
+ [[ -r $read_conf_file ]] || die 4 $"Could not locate dkms.conf file." \
+ $"File: $read_conf_file does not exist."
+
+ [[ $last_mvka = $module/$module_version/$1/$2 && \
+ $last_mvka_conf = $(readlink -f $read_conf_file) ]] && return
+
+
+ # Clear variables and arrays
+ for var in $dkms_conf_variables; do
+ unset $var
+ done
+
+ # Source in the dkms.conf.
+ # Allow for user-specified overrides in order of specificity.
+ local _conf_file
+ for _conf_file in "$read_conf_file" "/etc/dkms/$module.conf" \
+ "/etc/dkms/$module-$module_version.conf" "/etc/dkms/$module-$module_version-$1.conf" \
+ "/etc/dkms/$module-$module_version-$1-$2.conf"; do
+ [[ -e $_conf_file ]] && safe_source "$_conf_file" $dkms_conf_variables
+ done
+
+ # Source in the directive_array
+ for directive in "${directive_array[@]}"; do
+ directive_name=${directive%%=*}
+ directive_value=${directive#*=}
+ export $directive_name="$directive_value"
+ echo $"DIRECTIVE: $directive_name=\"$directive_value\""
+ done
+
+ # Set variables
+ clean="$CLEAN"
+ package_name="$PACKAGE_NAME"
+ package_version="$PACKAGE_VERSION"
+ post_add="$POST_ADD"
+ post_build="$POST_BUILD"
+ post_install="$POST_INSTALL"
+ post_remove="$POST_REMOVE"
+ pre_build="$PRE_BUILD"
+ pre_install="$PRE_INSTALL"
+ obsolete_by="$OBSOLETE_BY"
+
+ # Fail if no PACKAGE_NAME
+ if [[ ! $package_name ]]; then
+ echo $"dkms.conf: Error! No 'PACKAGE_NAME' directive specified.">&2
+ return_value=1
+ fi
+
+ # Fail if no PACKAGE_VERSION
+ if [[ ! $package_version ]]; then
+ echo $"dkms.conf: Error! No 'PACKAGE_VERSION' directive specified.">&2
+ return_value=1
+ fi
+
+ # Set module naming/location arrays
+ local index array_size=0 s
+ for s in ${#BUILT_MODULE_NAME[@]} \
+ ${#BUILT_MODULE_LOCATION[@]} \
+ ${#DEST_MODULE_NAME[@]} \
+ ${#DEST_MODULE_LOCATION[@]}; do
+ ((s > array_size)) && array_size=$s
+ done
+ for ((index=0; index < array_size; index++)); do
+ # Set values
+ built_module_name[$index]=${BUILT_MODULE_NAME[$index]}
+ built_module_location[$index]=${BUILT_MODULE_LOCATION[$index]}
+ dest_module_name[$index]=${DEST_MODULE_NAME[$index]}
+ dest_module_location[$index]=${DEST_MODULE_LOCATION[$index]}
+ case ${STRIP[$index]} in
+ [nN]*)
+ strip[$index]="no"
+ ;;
+ [yY]*)
+ strip[$index]="yes"
+ ;;
+ '')
+ strip[$index]=${strip[0]:-yes}
+ ;;
+ esac
+
+ # If unset, set by defaults
+ [[ ! ${built_module_name[$index]} ]] && \
+ ((array_size == 1)) && \
+ built_module_name[$index]=$PACKAGE_NAME
+ [[ ! ${dest_module_name[$index]} ]] && \
+ dest_module_name[$index]=${built_module_name[$index]}
+ [[ ${built_module_location[$index]} && \
+ ${built_module_location[$index]:(-1)} != / ]] && \
+ built_module_location[$index]="${built_module_location[$index]}/"
+
+ # FAIL if no built_module_name
+ if [[ ! ${built_module_name[$index]} ]]; then
+ echo $"dkms.conf: Error! No 'BUILT_MODULE_NAME' directive specified for record #$index." >&2
+ return_value=1
+ fi
+
+ # FAIL if built_module_name ends in .o or .ko
+ case ${built_module_name[$index]} in
+ *.o|*.ko)
+ echo $"dkms.conf: Error! 'BUILT_MODULE_NAME' directive ends in '.o' or '.ko' in record #$index." >&2
+ return_value=1
+ ;;
+ esac
+
+ # FAIL if dest_module_name ends in .o or .ko
+ case ${dest_module_name[$index]} in
+ *.o|*.ko)
+ echo $"dkms.conf: Error! 'DEST_MODULE_NAME' directive ends in '.o' or '.ko' in record #$index." >&2
+ return_value=1
+ ;;
+ esac
+
+ # Override location for specific distributions
+ dest_module_location[$index]="$(override_dest_module_location ${dest_module_location[$index]})"
+
+ # Fail if no DEST_MODULE_LOCATION
+ if [[ ! ${DEST_MODULE_LOCATION[$index]} ]]; then
+ echo $"dkms.conf: Error! No 'DEST_MODULE_LOCATION' directive specified for record #$index.">&2
+ return_value=1
+ fi
+
+ # Fail if bad DEST_MODULE_LOCATION
+ case ${DEST_MODULE_LOCATION[$index]} in
+ /kernel*)
+ ;;
+ /updates*)
+ ;;
+ /extra*)
+ ;;
+ *)
+ echo $"dkms.conf: Error! Directive 'DEST_MODULE_LOCATION' does not begin with">&2
+ echo $"'/kernel', '/updates', or '/extra' in record #$index.">&2
+ return_value=1
+ ;;
+ esac
+ done
+
+ # Warn if no modules are specified
+ if ((array_size == 0)); then
+ echo $"dkms.conf: Warning! Zero modules specified." >&2
+ fi
+
+ # Get the correct make command
+ [[ ${MAKE_MATCH[0]} ]] || make_command="${MAKE[0]}"
+ for ((index=0; index < ${#MAKE[@]}; index++)); do
+ [[ ${MAKE[$index]} && ${MAKE_MATCH[$index]} && \
+ $1 =~ ${MAKE_MATCH[$index]} ]] && \
+ make_command="${MAKE[$index]}"
+ done
+
+ # Use the generic make and make clean commands if not specified
+ [[ ! $make_command ]] && make_command="make -C $kernel_source_dir M=$dkms_tree/$module/$module_version/build"
+ [[ ! $clean ]] && clean="make -C $kernel_source_dir M=$dkms_tree/$module/$module_version/build clean"
+
+ # Check if clang was used to compile or lld was used to link the kernel.
+ if [[ -e $kernel_source_dir/vmlinux ]]; then
+ if readelf -p .comment $kernel_source_dir/vmlinux | grep -q clang; then
+ make_command="${make_command} CC=clang"
+ fi
+ if readelf -p .comment $kernel_source_dir/vmlinux | grep -q LLD; then
+ make_command="${make_command} LD=ld.lld"
+ fi
+ elif [[ -e "${kernel_config}" ]]; then
+ if grep -q CONFIG_CC_IS_CLANG=y "${kernel_config}"; then
+ make_command="${make_command} CC=clang"
+ fi
+ if grep -q CONFIG_LD_IS_LLD=y "${kernel_config}"; then
+ make_command="${make_command} LD=ld.lld"
+ fi
+ fi
+
+ # Set patch_array (including kernel specific patches)
+ count=0
+ for ((index=0; index < ${#PATCH[@]}; index++)); do
+ if [[ ${PATCH[$index]} && (! ${PATCH_MATCH[$index]} || $1 =~ ${PATCH_MATCH[$index]}) ]]; then
+ patch_array[$count]="${PATCH[$index]}"
+ count=$(($count+1))
+ fi
+ done
+
+ # Set build_exclude
+ [[ $BUILD_EXCLUSIVE_KERNEL && ! $1 =~ $BUILD_EXCLUSIVE_KERNEL ]] && build_exclude="yes"
+ [[ $BUILD_EXCLUSIVE_KERNEL_MIN && "$(VER "$1")" < "$(VER "$BUILD_EXCLUSIVE_KERNEL_MIN")" ]] && build_exclude="yes"
+ [[ $BUILD_EXCLUSIVE_KERNEL_MAX && "$(VER "$1")" > "$(VER "$BUILD_EXCLUSIVE_KERNEL_MAX")" ]] && build_exclude="yes"
+ [[ $BUILD_EXCLUSIVE_ARCH && ! $2 =~ $BUILD_EXCLUSIVE_ARCH ]] && build_exclude="yes"
+ if [[ $BUILD_EXCLUSIVE_CONFIG && -e "${kernel_config}" ]]; then
+ local kconf
+ for kconf in $BUILD_EXCLUSIVE_CONFIG ; do
+ case "$kconf" in
+ !*) grep -q "^${kconf#!}=[ym]" "${kernel_config}" && build_exclude="yes" ;;
+ *) grep -q "^${kconf}=[ym]" "${kernel_config}" || build_exclude="yes" ;;
+ esac
+ done
+ fi
+
+ # Set clean
+ [[ $clean ]] || clean="make clean"
+
+ ((return_value == 0)) && last_mvka="$module/$module_version/$1/$2" && last_mvka_conf="$(readlink -f "$read_conf_file")"
+ return $return_value
+}
+
+# Source specified variables from dkms framework configuration files.
+read_framework_conf() {
+ for i in /etc/dkms/framework.conf /etc/dkms/framework.conf.d/*.conf; do
+ [[ -e "$i" ]] && safe_source "$i" "$@"
+ done
+}
+
+# Little helper function for parsing the output of modinfo.
+get_module_verinfo(){
+ local ver
+ local srcver
+ local checksum
+ local vals=
+ while read -a vals; do
+ case "${vals[0]}" in
+ version:)
+ ver="${vals[1]}"
+ checksum="${vals[2]}"
+ ;;
+ srcversion:)
+ srcver="${vals[1]}"
+ ;;
+ esac
+ done < <(modinfo "$1")
+
+ echo -E "${ver}"
+ # Use obsolete checksum info if srcversion is not available
+ echo -E "${srcver:-$checksum}"
+}
+
+# Compare two modules' version
+# Output:
+# "==": They are the same version and the same srcversion
+# "=": They are the same version, but not the same srcversion
+# ">": 1st one is newer than 2nd one
+# "<": 1st one is older than 2nd one
+# "?": Cannot determine
+# Returns 0 if same version, otherwise 1
+compare_module_version()
+{
+ readarray -t ver1 <<< "$(get_module_verinfo "$1")"
+ readarray -t ver2 <<< "$(get_module_verinfo "$2")"
+ if [[ "${ver1[0]}" = "${ver2[0]}" ]]; then
+ if [[ "${ver1[1]}" = "${ver2[1]}" ]]; then
+ echo "=="
+ else
+ echo "="
+ fi
+ return 0
+ elif [[ ! "$ver1" ]] || [[ ! "$ver2" ]]; then
+ echo "?"
+ elif [[ "$(VER "${ver1[0]}")" > "$(VER "${ver2[0]}")" ]]; then
+ echo ">"
+ else
+ echo "<"
+ fi
+ return 1
+}
+
+# Perform some module version sanity checking whenever we are installing
+# modules.
+check_version_sanity()
+{
+ # $1 = kernel_version
+ # $2 = arch
+ # $3 = obs by kernel version
+ # $4 = dest_module_name
+
+ local lib_tree="$install_tree/$1" res=
+ echo $"Running module version sanity check."
+ local i=0
+ if [[ -n $3 ]]; then
+ # Magic split into array syntax saves trivial awk and cut calls.
+ local -a obs=(${3//-/ })
+ local -a my=(${1//-/ })
+ local obsolete=0
+ if [[ ${obs} && ${my} ]]; then
+ if [[ $(VER ${obs}) == $(VER ${my}) && ! $force ]]; then
+ # They get obsoleted possibly in this kernel release
+ if [[ ! ${obs[1]} ]]; then
+ # They were obsoleted in this upstream kernel
+ obsolete=1
+ elif [[ $(VER ${my[1]}) > $(VER ${obs[1]}) ]]; then
+ # They were obsoleted in an earlier ABI bump of the kernel
+ obsolete=1
+ elif [[ $(VER ${my[1]}) = $(VER ${obs[1]}) ]]; then
+ # They were obsoleted in this ABI bump of the kernel
+ obsolete=1
+ fi
+ elif [[ $(VER ${my}) > $(VER ${obs}) && ! $force ]]; then
+ # They were obsoleted in an earlier kernel release
+ obsolete=1
+ fi
+ fi
+
+ if ((obsolete == 1)); then
+ echo $"" >&2
+ echo $"Module has been obsoleted due to being included" >&2
+ echo $"in kernel $3. We will avoid installing" >&2
+ echo $"for future kernels above $3." >&2
+ echo $"You may override by specifying --force." >&2
+ return 1
+ fi
+ fi
+ set_module_suffix "$1"
+ read -a kernels_module < <(find_module "$lib_tree" "${4}")
+ [[ -z $kernels_module ]] && return 0
+
+ if [[ "$force_version_override" == "true" ]]; then
+ # Skip the following version checking code.
+ return 0
+ fi
+
+ if [[ ${kernels_module[1]} ]]; then
+ warn $"Warning! Cannot do version sanity checking because multiple ${4}$module_suffix" \
+ $"modules were found in kernel $1."
+ return 0
+ fi
+ local dkms_module=$(compressed_or_uncompressed "$dkms_tree/$module/$module_version/$1/$2/module/" "${4}")
+
+ local cmp_res="$(compare_module_version "${kernels_module}" "${dkms_module}")"
+ if [[ "${cmp_res}" = ">" ]]; then
+ if [[ ! "$force" ]]; then
+ error $"Module version $(get_module_verinfo "${dkms_module}" | head -n 1) for $4${module_suffix}" \
+ $"is not newer than what is already found in kernel $1 ($(get_module_verinfo "${kernels_module}" | head -n 1))." \
+ $"You may override by specifying --force."
+ return 1
+ fi
+ elif [[ "${cmp_res}" = "==" ]]; then
+ if [[ ! "$force" ]]; then
+ # if the module has neither version nor srcversion/checksum, check the binary files instead
+ local verinfo="$(get_module_verinfo "${dkms_module}")"
+ if [[ "$(echo "$verinfo" | tr -d '[:space:]')" ]] || diff "${kernels_module}" "${dkms_module}" &>/dev/null; then
+ echo $"Module version $(echo "$verinfo" | head -n 1) for $4${module_suffix}" >&2
+ echo $"exactly matches what is already found in kernel $1." >&2
+ echo $"DKMS will not replace this module." >&2
+ echo $"You may override by specifying --force." >&2
+ return 1
+ fi
+ fi
+ fi
+ return 0
+}
+
+check_module_args() {
+ [[ $module && $module_version ]] && return
+ die 1 $"Arguments <module> and <module-version> are not specified." \
+ $"Usage: $1 <module>/<module-version> or" \
+ $" $1 -m <module>/<module-version> or" \
+ $" $1 -m <module> -v <module-version>"
+}
+
+read_conf_or_die() {
+ read_conf "$@" && return
+ die 8 $"Bad conf file."\
+ $"File: ${3:-$conf} does not represent a valid dkms.conf file."
+}
+
+run_build_script() {
+ # $1 = script type
+ # $2 = script to run
+ local script_type run
+ [[ $2 ]] || return 0
+ case "$1" in
+ pre_build|post_build)
+ script_type='build'
+ ;;
+ *)
+ script_type='source'
+ ;;
+ esac
+ run="$dkms_tree/$module/$module_version/$script_type/$2"
+ if [[ -x ${run%% *} ]]; then
+ echo $""
+ echo $"Running the $1 script:"
+ (
+ cd "$dkms_tree/$module/$module_version/$script_type/"
+ exec $run
+ )
+ else
+ echo $""
+ warn $"The $1 script is not executable."
+ fi
+}
+
+# Register a DKMS-ified source tree with DKMS.
+# This function is smart enough to register the module if we
+# passed a source tree or a tarball instead of relying on the source tree
+# being unpacked into /usr/src/$module-$module_version.
+add_module()
+{
+ # If $archive is set and $module and $module_version are not,
+ # try loading the tarball passed first.
+ if [[ $archive_location && ! $module && ! $module_version ]]; then
+ load_tarball
+ elif [[ $try_source_tree && ! $module && ! $module_version ]]; then
+ add_source_tree "$try_source_tree"
+ fi
+
+ # Check that we have all the arguments
+ check_module_args add
+
+ # Do stuff for --rpm_safe_upgrade
+ if [[ $rpm_safe_upgrade ]]; then
+ local pppid=$(awk '/PPid:/ {print $2}' /proc/$PPID/status)
+ local lock_name=$(mktemp_or_die $tmp_location/dkms_rpm_safe_upgrade_lock.$pppid.XXXXXX)
+ echo "$module-$module_version" >> $lock_name
+ ps -o lstart --no-headers -p $pppid 2>/dev/null >> $lock_name
+ fi
+
+ # Check that this module-version hasn't already been added
+ if is_module_added "$module" "$module_version"; then
+ die 3 $"DKMS tree already contains: $module-$module_version" \
+ $"You cannot add the same module/version combo more than once."
+ fi
+
+ [[ $conf ]] || conf="$source_tree/$module-$module_version/dkms.conf"
+
+ # Check that /usr/src/$module-$module_version exists
+ if ! [[ -d $source_tree/$module-$module_version ]]; then
+ die 2 $"Could not find module source directory." \
+ $"Directory: $source_tree/$module-$module_version does not exist."
+ fi
+
+ # Check the conf file for sanity
+ read_conf_or_die "$kernelver" "$arch" "$conf"
+
+ # Create the necessary dkms tree structure
+ echo $"Creating symlink $dkms_tree/$module/$module_version/source -> $source_tree/$module-$module_version"
+ mkdir -p "$dkms_tree/$module/$module_version/build"
+ ln -s "$source_tree/$module-$module_version" "$dkms_tree/$module/$module_version/source"
+
+ # Run the post_add script
+ run_build_script post_add "$post_add"
+}
+
+# Prepare a kernel source or include tree for compiling a module.
+# Most modern-ish distros do not require this function at all,
+# so it will be removed in a future release.
+prepare_kernel()
+{
+ # $1 = kernel version to prepare
+ # $2 = arch to prepare
+
+ set_kernel_source_dir_and_kconfig "$1"
+
+ # Check that kernel-source exists
+ _check_kernel_dir "$1" || {
+ die 1 $"Your kernel headers for kernel $1 cannot be found at $install_tree/$1/build or $install_tree/$1/source." \
+ $"Please install the linux-headers-$1 package or use the --kernelsourcedir option to tell DKMS where it's located."
+ }
+}
+
+prepare_signing()
+{
+ do_signing=0
+
+ if [[ ! -f ${kernel_config} ]]; then
+ echo "Kernel config ${kernel_config} not found, modules won't be signed"
+ return
+ fi
+
+ if ! grep -q "^CONFIG_MODULE_SIG_HASH=" "${kernel_config}"; then
+ echo "The kernel is built without module signing facility, modules won't be signed"
+ return
+ fi
+
+ sign_hash=$(grep "^CONFIG_MODULE_SIG_HASH=" "${kernel_config}" | cut -f2 -d= | sed 's/"//g')
+
+ # Lazy source in signing related configuration
+ read_framework_conf $dkms_framework_signing_variables
+
+ if [[ ! ${sign_file} ]]; then
+ case "$running_distribution" in
+ debian* )
+ sign_file="/usr/lib/linux-kbuild-${kernelver%.*}/scripts/sign-file"
+ ;;
+ ubuntu* )
+ sign_file="$(command -v kmodsign)"
+ if [[ ! -x "${sign_file}" ]]; then
+ sign_file="/usr/src/linux-headers-$kernelver/scripts/sign-file"
+ fi
+ ;;
+ esac
+ if [[ ! -f ${sign_file} ]]; then
+ sign_file="$install_tree/$kernelver/build/scripts/sign-file"
+ fi
+ fi
+ echo "Sign command: $sign_file"
+
+ if [[ ! -f ${sign_file} || ! -x ${sign_file} ]]; then
+ echo "Binary ${sign_file} not found, modules won't be signed"
+ return
+ fi
+
+ if [[ -z "${mok_signing_key}" ]]; then
+ # No custom key specified, use the default key created by update-secureboot-policy for Ubuntu
+ # Debian's update-secureboot-policy has no --new-key option
+ case "$running_distribution" in
+ ubuntu* )
+ mok_signing_key="/var/lib/shim-signed/mok/MOK.priv"
+ mok_certificate="/var/lib/shim-signed/mok/MOK.der"
+
+ if [[ ! -f ${mok_signing_key} || ! -f ${mok_certificate} ]]; then
+ if [[ ! -x "$(command -v update-secureboot-policy)" ]]; then
+ echo "Binary update-secureboot-policy not found, modules won't be signed"
+ return
+ fi
+ # update-secureboot-policy won't create new key if $mok_certificate exists
+ if [[ -f ${mok_certificate} ]]; then
+ rm -f "${mok_certificate}"
+ fi
+ echo "Certificate or key are missing, generating them using update-secureboot-policy..."
+ SHIM_NOTRIGGER=y update-secureboot-policy --new-key &>/dev/null
+ update-secureboot-policy --enroll-key
+ fi
+
+ ;;
+ esac
+ fi
+
+ if [[ ! ${mok_signing_key} ]]; then
+ mok_signing_key="/var/lib/dkms/mok.key"
+ fi
+ echo "Signing key: $mok_signing_key"
+
+ if [[ ! ${mok_certificate} ]]; then
+ mok_certificate="/var/lib/dkms/mok.pub"
+ fi
+ echo "Public certificate (MOK): $mok_certificate"
+
+ # scripts/sign-file.c in kernel source also supports using "pkcs11:..." as private key
+ if [[ $mok_signing_key != "pkcs11:"* ]] && ( [[ ! -f $mok_signing_key || ! -f $mok_certificate ]] ); then
+ echo "Certificate or key are missing, generating self signed certificate for MOK..."
+ if ! command -v openssl >/dev/null; then
+ echo "openssl not found, can't generate key and certificate."
+ return
+ fi
+ openssl req -new -x509 -nodes -days 36500 -subj "/CN=DKMS module signing key" \
+ -newkey rsa:2048 -keyout "$mok_signing_key" \
+ -outform DER -out "$mok_certificate" > /dev/null 2>&1
+ if [[ ! -f ${mok_signing_key} ]]; then
+ echo "Key file ${mok_signing_key} not found and can't be generated, modules won't be signed"
+ return
+ fi
+ fi
+
+ if [[ ! -f ${mok_certificate} ]]; then
+ echo "Certificate file ${mok_certificate} not found and can't be generated, modules won't be signed"
+ return
+ fi
+
+ do_signing=1
+}
+
+# Get ready to build a module that has been registered with DKMS.
+prepare_build()
+{
+ # If the module has not been added, try to add it.
+ is_module_added "$module" "$module_version" || add_module
+
+ local -r base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch"
+ local -r build_dir="$dkms_tree/$module/$module_version/build"
+ local -r source_dir="$dkms_tree/$module/$module_version/source"
+
+ # Check that the module has not already been built for this kernel
+ [[ -d $base_dir ]] && die 3 \
+ $"This module/version has already been built on: $kernelver" \
+ $"Directory $base_dir already exists. Use the dkms remove function before trying to build again."
+
+ # Read the conf file
+ set_module_suffix "$kernelver"
+ read_conf_or_die "$kernelver" "$arch"
+
+ # Error out if build_exclude is set
+ [[ $build_exclude ]] && diewarn 77 \
+ $"The $base_dir/dkms.conf"\
+ $"for module $module includes a BUILD_EXCLUSIVE directive"\
+ $"which does not match this kernel/arch/config."\
+ $"This indicates that it should not be built."
+
+ # Error out if source_tree is basically empty (binary-only dkms tarball w/ --force check)
+ (($(ls $source_dir | wc -l | awk {'print $1'}) < 2)) && die 8 \
+ $"The directory $source_dir does not appear to have module source located within it."\
+ $"Build halted."
+
+ # Set up temporary build directory for build
+ rm -rf "$build_dir"
+ cp -a "$source_dir/" "$build_dir"
+
+ cd "$build_dir"
+
+ # Apply any patches
+ for p in "${patch_array[@]}"; do
+ [[ ! -e $build_dir/patches/$p ]] && \
+ report_build_problem 5 \
+ $" Patch $p as specified in dkms.conf cannot be" \
+ $"found in $build_dir/patches/."
+ invoke_command "patch -p1 < ./patches/$p" "applying patch $p" || \
+ report_build_problem 6 $"Application of patch $p failed." \
+ $"Check $build_dir for more information."
+ done
+
+ if [[ -f $kernel_source_dir/.kernelvariables ]]; then
+ export CC=$(echo -e "show-%:\n\t@echo \$(\$*)\ninclude $kernel_source_dir/.kernelvariables" | make -f - show-CC)
+ else
+ unset CC
+ fi
+
+ if [[ -e "${kernel_config}" ]]; then
+ local cc=$(sed -n 's|^CONFIG_CC_VERSION_TEXT="\([^ ]*\) .*"|\1|p' "${kernel_config}")
+ if command -v "$cc" >/dev/null; then
+ export CC="$cc"
+ export KERNEL_CC="$cc"
+ fi
+
+ if grep -q 'CONFIG_CC_IS_CLANG=y' "${kernel_config}"; then
+ local cc=clang
+ if command -v "$cc" >/dev/null; then
+ export CC="$cc"
+ export KERNEL_CC="$cc"
+ fi
+ fi
+
+ if grep -q 'CONFIG_LD_IS_LLD=y' "${kernel_config}"; then
+ local ld=ld.lld
+ if command -v "$ld" >/dev/null; then
+ export LD="$ld"
+ export KERNEL_LD="$ld"
+ fi
+ fi
+ fi
+
+ # Run the pre_build script
+ run_build_script pre_build "$pre_build"
+}
+
+# Build our previously prepared source tree. prepare_build must be called
+# before calling this function.
+actual_build()
+{
+ local -r base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch"
+ local -r build_dir="$dkms_tree/$module/$module_version/build"
+ local -r build_log="$build_dir/make.log"
+
+ echo $""
+ echo $"Building module:"
+
+ invoke_command "$clean" "Cleaning build area" '' background
+ echo $"DKMS make.log for $module-$module_version for kernel $kernelver ($arch)" >> "$build_log"
+ date >> "$build_log"
+ local the_make_command="${make_command/#make/make -j$parallel_jobs KERNELRELEASE=$kernelver}"
+
+ invoke_command "$the_make_command" "Building module(s)" "$build_log" background || \
+ report_build_problem 10 $"Bad return status for module build on kernel: $kernelver ($arch)" \
+ $"Consult $build_log for more information."
+
+ # Make sure all the modules built successfully
+ for ((count=0; count < ${#built_module_name[@]}; count++)); do
+ [[ -e ${built_module_location[$count]}${built_module_name[$count]}$module_uncompressed_suffix ]] && continue
+ report_build_problem 7 \
+ $" Build of ${built_module_name[$count]}$module_uncompressed_suffix failed for: $kernelver ($arch)" \
+ $"Make sure the name of the generated module is correct and at the root of the" \
+ $"build directory, or consult make.log in the build directory" \
+ $"$build_dir for more information."
+ done
+ cd - >/dev/null
+
+ # Build success, so create DKMS structure for a built module
+ mkdir -p "$base_dir/log"
+ [[ $kernel_config ]] && cp -f "$kernel_config" "$base_dir/log/"
+ mv -f "$build_log" "$base_dir/log/make.log" 2>/dev/null
+
+ # Save a copy of the new module
+ mkdir "$base_dir/module" >/dev/null
+ for ((count=0; count < ${#built_module_name[@]}; count++)); do
+ local the_module="$build_dir/${built_module_location[$count]}${built_module_name[$count]}"
+ local built_module="$the_module$module_uncompressed_suffix"
+ local compressed_module="$the_module$module_suffix"
+
+ [[ ${strip[$count]} != no ]] && strip -g "$built_module"
+
+ if (( do_signing )); then
+ echo "Signing module $built_module"
+ "$sign_file" "$sign_hash" "$mok_signing_key" "$mok_certificate" "$built_module"
+ fi
+
+ if [[ $module_compressed_suffix = .gz ]]; then
+ gzip -9f "$built_module" || compressed_module=""
+ elif [[ $module_compressed_suffix = .xz ]]; then
+ xz --check=crc32 --lzma2=dict=1MiB -f "$built_module" || compressed_module=""
+ elif [[ $module_compressed_suffix = .zst ]]; then
+ zstd -q -f -T0 -19 "$built_module" || compressed_module=""
+ fi
+ if [[ -n $compressed_module ]]; then
+ cp -f "$compressed_module" "$base_dir/module/${dest_module_name[$count]}$module_suffix" >/dev/null
+ else
+ cp -f "$built_module" "$base_dir/module/${dest_module_name[$count]}$module_uncompressed_suffix" >/dev/null
+ fi
+ done
+
+ # Run the post_build script
+ run_build_script post_build "$post_build"
+}
+
+# Clean up after a build.
+clean_build()
+{
+ # Run the clean commands
+ cd "$dkms_tree/$module/$module_version/build"
+ invoke_command "$clean" "Cleaning build area" '' background
+ cd - >/dev/null
+
+ # Clean the build directory
+ rm -rf "$dkms_tree/$module/$module_version/build"
+}
+
+do_build()
+{
+ set_kernel_source_dir_and_kconfig "$kernelver"
+ prepare_kernel "$kernelver" "$arch"
+ prepare_signing
+ prepare_build
+ actual_build
+ clean_build
+}
+
+# Force the installation of a module if this is listed
+# in the files in $forced_modules_dir, if any
+force_installation()
+{
+ forced_modules_dir="/usr/share/dkms/modules_to_force_install"
+ to_force=""
+ if [[ -d $forced_modules_dir ]]; then
+ for elem in $forced_modules_dir/*; do
+ if [[ -e $elem ]]; then
+ to_force="$to_force $(cat $elem)"
+ fi
+ done
+
+ for elem in $to_force; do
+ if [[ ${1} = ${elem} ]]; then
+ echo "force"
+ return 0
+ elif [[ ${1}_version-override = ${elem} ]]; then
+ echo "version-override"
+ return 0
+ fi
+ done
+ fi
+ return 1
+}
+
+# Install a previously built module
+# There are huge swaths of code here that special-case for various distros.
+# They should be split into their own functions.
+do_install()
+{
+ # If the module has not been built, try to build it first.
+ is_module_built "$module" "$module_version" "$kernelver" "$arch" || do_build
+ local base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch"
+
+ # Save the status of $force
+ tmp_force="$force"
+
+ # If the module is set to be force-installed
+ local ret=$(force_installation $module)
+ if [[ "$ret" == "force" ]];then
+ force="true"
+ echo "Forcing installation of $module"
+ elif [[ "$ret" == "version-override" ]];then
+ force_version_override="true"
+ echo "Forcing version override of $module"
+ fi
+ # Make sure that kernel exists to install into
+ [[ -e $install_tree/$kernelver ]] || die 6 \
+ $"The directory $install_tree/$kernelver doesn't exist." \
+ $"You cannot install a module onto a non-existant kernel."
+
+ # Read the conf file
+ read_conf_or_die "$kernelver" "$arch"
+
+ # Check that its not already installed (kernel symlink)
+ is_module_installed "$module" "$module_version" "$kernelver" "$arch" && die 5 \
+ $"This module/version combo is already installed for kernel $kernelver ($arch)."
+
+ # If upgrading using rpm_safe_upgrade, go ahead and force the install
+ # else we can wind up with the first half of an upgrade failing to install anything,
+ # while the second half of the upgrade, the removal, then succeeds, leaving us with
+ # nothing installed.
+ [[ $rpm_safe_upgrade ]] && force="true"
+
+ # Save the original_module if one exists, none have been saved before, and this is the first module for this kernel
+ local lib_tree="$install_tree/$kernelver"
+ local any_module_installed
+ local count
+ for ((count=0; count < ${#built_module_name[@]}; count++)); do
+ echo $""
+ echo $"${dest_module_name[$count]}$module_suffix:"
+ # Check this version against what is already in the kernel
+ check_version_sanity "$kernelver" "$arch" "$obsolete_by" "${dest_module_name[$count]}" || continue
+
+ if ((count == 0)) && ! run_build_script pre_install "$pre_install" && ! [[ $force ]]; then
+ die 101 $"pre_install failed, aborting install." \
+ $"You may override by specifying --force."
+ fi
+ local m=${dest_module_name[$count]}
+ local installed_modules=$(find_module "$lib_tree" "$m")
+ local module_count=${#installed_modules[@]}
+ echo $" - Original module"
+ local original_copy=$(compressed_or_uncompressed "$dkms_tree/$module/original_module/$kernelver/$arch" "$m")
+ if [[ -L $dkms_tree/$module/kernel-$kernelver-$arch &&
+ -n "$original_copy" ]]; then
+ echo $" - An original module was already stored during a previous install"
+ elif ! [[ -L $dkms_tree/$module/kernel-$kernelver-$arch ]]; then
+ local archive_pref1=$(compressed_or_uncompressed "$lib_tree/extra" "$m")
+ local archive_pref2=$(compressed_or_uncompressed "$lib_tree/updates" "$m")
+ local archive_pref3=$(compressed_or_uncompressed "$lib_tree${dest_module_location[$count]}" "$m")
+ local archive_pref4=""
+ ((module_count == 1)) && archive_pref4=${installed_modules[0]}
+ local original_module=""
+ local found_orginal=""
+ for original_module in $archive_pref1 $archive_pref2 $archive_pref3 $archive_pref4; do
+ [[ -f $original_module ]] || continue
+ case "$running_distribution" in
+ debian* | ubuntu* )
+ ;;
+ *)
+ echo $" - Found $original_module"
+ echo $" - Storing in $dkms_tree/$module/original_module/$kernelver/$arch/"
+ echo $" - Archiving for uninstallation purposes"
+ mkdir -p "$dkms_tree/$module/original_module/$kernelver/$arch"
+ mv -f "$original_module" "$dkms_tree/$module/original_module/$kernelver/$arch/"
+ ;;
+ esac
+ found_original="yes"
+ break
+ done
+ if [[ ! $found_original ]] && ((module_count > 1)); then
+ echo $" - Multiple original modules exist but DKMS does not know which to pick"
+ echo $" - Due to the confusion, none will be considered during a later uninstall"
+ elif [[ ! $found_original ]]; then
+ echo $" - No original module exists within this kernel"
+ fi
+ else
+ echo $" - This kernel never originally had a module by this name"
+ fi
+
+ if ((module_count > 1)); then
+ echo $" - Multiple same named modules!"
+ echo $" - $module_count named $m$module_suffix in $lib_tree/"
+ case "$running_distribution" in
+ debian* | ubuntu* )
+ ;;
+ *)
+ echo $" - All instances of this module will now be stored for reference purposes ONLY"
+ echo $" - Storing in $dkms_tree/$module/original_module/$kernelver/$arch/collisions/"
+ ;;
+ esac
+ for module_dup in $(find_module "$lib_tree" "$m"); do
+ dup_tree="${module_dup#$lib_tree}";
+ dup_name="${module_dup##*/}"
+ dup_tree="${dup_tree/${dup_name}}"
+ case "$running_distribution" in
+ debian* | ubuntu* )
+ ;;
+ *)
+ echo $" - Stored $module_dup"
+ mkdir -p "$dkms_tree/$module/original_module/$kernelver/$arch/collisions/$dup_tree"
+ mv -f $module_dup "$dkms_tree/$module/original_module/$kernelver/$arch/collisions/$dup_tree"
+ ;;
+ esac
+ done
+ fi
+
+ # Copy module to its location
+ echo $" - Installation"
+ echo $" - Installing to $install_tree/$kernelver${dest_module_location[$count]}/"
+ mkdir -p $install_tree/$kernelver${dest_module_location[$count]}
+ [[ $symlink_modules ]] && symlink="-s"
+ local toinstall=$(compressed_or_uncompressed "$base_dir/module" "$m")
+ cp -f $symlink "$toinstall" "$install_tree/$kernelver${dest_module_location[$count]}/${toinstall##*/}"
+ any_module_installed=1
+
+ done
+
+ if ((${#built_module_name[@]} > 0)) && [[ ! "${any_module_installed}" ]]; then
+ die 6 $"Installation aborted."
+ fi
+
+ # Create the kernel-<kernelver> symlink to designate this version as active
+ rm -f "$dkms_tree/$module/kernel-$kernelver-$arch" 2>/dev/null
+ ln -s "$module_version/$kernelver/$arch" "$dkms_tree/$module/kernel-$kernelver-$arch" 2>/dev/null
+
+ # Add to kabi-tracking
+ if [[ -z $NO_WEAK_MODULES ]]; then
+ if [[ ${weak_modules} ]]; then
+ echo $"Adding any weak-modules"
+ list_each_installed_module "$module" "$kernelver" "$arch" | ${weak_modules} ${weak_modules_no_initrd} --add-modules
+ fi
+ fi
+
+ # Run the post_install script
+ run_build_script post_install "$post_install"
+
+ invoke_command "do_depmod $kernelver" "depmod" '' background || {
+ do_uninstall "$kernelver" "$arch"
+ die 6 $"Problems with depmod detected. Automatically uninstalling this module." \
+ $"Install Failed (depmod problems). Module rolled back to built state."
+ exit 6
+ }
+
+ if [[ $modprobe_on_install ]]; then
+ # Make the newly installed modules available immediately
+ find /sys/devices -name modalias -print0 | xargs -0 cat | sort -u | xargs modprobe -a -b -q
+ if [[ -f /lib/systemd/system/systemd-modules-load.service ]]; then
+ systemctl restart systemd-modules-load.service
+ fi
+ fi
+
+ # Restore the status of $force
+ force="$tmp_force"
+}
+
+# List each kernel object that has been installed for a particular module.
+list_each_installed_module()
+{
+ # $1 = module
+ # $2 = kernel version
+ # $3 = arch
+ local count
+ local real_dest_module_location
+ local mod
+ for ((count=0; count < ${#built_module_name[@]}; count++)); do
+ real_dest_module_location="$(find_actual_dest_module_location $1 $count $2 $3)"
+ mod=$(compressed_or_uncompressed "$install_tree/$2${real_dest_module_location}" "${dest_module_name[$count]}")
+ echo "$mod"
+ done
+}
+
+# Check if either the module source, or the symlink pointing to it is missing
+# A module can only be in this broken state, if the user or a faulty program
+# messed up. The module then is considered volatile, because there is no reliable
+# way to tell if files in the source tree are still in a valid state.
+# Therefor any action (except 'add', if only the symlink is missing)
+# to operate on the module has to be refused.
+# Manual intervention by the user is required to return to a sane state.
+is_module_broken() {
+ [[ $1 && $2 ]] || return 1
+ [[ -d $dkms_tree/$1/$2 ]] || return 2
+ [[ -L $dkms_tree/$1/$2/source && ! -d $dkms_tree/$1/$2/source ]] && return
+ [[ ! -L $dkms_tree/$1/$2/source && -d $source_tree/$1-$2/ ]] && return
+}
+
+is_module_added() {
+ [[ $1 && $2 ]] || return 1
+ [[ -d $dkms_tree/$1/$2 ]] || return 2
+ [[ -L $dkms_tree/$1/$2/source && -d $dkms_tree/$1/$2/source ]] || return 2
+}
+
+is_module_built() {
+ [[ $1 && $2 && $3 && $4 ]] || return 1
+ local d="$dkms_tree/$1/$2/$3/$4" m=''
+ [[ -d $d/module ]] || return 1
+ local default_conf="$dkms_tree/$1/$2/source/dkms.conf"
+ # If a custom dkms.conf was specified use it, otherwise use the default one.
+ local real_conf="${conf:-${default_conf}}"
+ read_conf_or_die "$3" "$4" "$real_conf"
+ set_module_suffix "$3"
+ for m in "${dest_module_name[@]}"; do
+ local t=$(compressed_or_uncompressed "$d/module" "$m")
+ test -n "$t" || return 1
+ done
+}
+
+# This assumes we have already checked to see if the module has been built.
+_is_module_installed() {
+ [[ $1 && $2 && $3 && $4 ]] || return 1
+ local d="$dkms_tree/$1/$2/$3/$4"
+ local k="$dkms_tree/$1/kernel-$3-$4"
+ [[ -L $k && $(readlink -f $k) = $d ]]
+}
+
+# This does not.
+is_module_installed() { is_module_built "$@" && _is_module_installed "$@"; }
+
+maybe_add_module() (
+ is_module_added "$1" "$2" && {
+ echo $"Module $1/$2 already added."
+ return 0
+ }
+ module="$1" module_version="$2" add_module
+)
+
+maybe_build_module() (
+ is_module_built "$1" "$2" "$3" "$4" && {
+ if [[ "$force" = "true" ]]; then
+ do_unbuild "$3" "$4"
+ else
+ echo $"Module $1/$2 already built for kernel $3 ($4), skip." \
+ $"You may override by specifying --force."
+ return 0
+ fi
+ }
+ module="$1" module_version="$2" kernelver="$3" arch="$4" do_build
+)
+
+maybe_install_module() (
+ is_module_installed "$1" "$2" "$3" "$4" && {
+ if [[ "$force" = "true" ]]; then
+ do_uninstall "$3" "$4"
+ else
+ echo $"Module $1/$2 already installed on kernel $3 ($4), skip." \
+ $"You may override by specifying --force."
+ return 0
+ fi
+ }
+ module="$1" module_version="$2" kernelver="$3" arch="$4" do_install
+)
+
+build_module() {
+ local i=0
+ for ((i=0; i < ${#kernelver[@]}; i++)); do
+ maybe_build_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}"
+ done
+}
+
+install_module() {
+ local i=0
+ for ((i=0; i < ${#kernelver[@]}; i++)); do
+ maybe_install_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}"
+ done
+}
+
+possible_dest_module_locations()
+{
+ # $1 = count
+ # There are two places an installed module may really be:
+ # 1) "$install_tree/$kernelver/${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix"
+ # 2) "$install_tree/$kernelver/${DEST_MODULE_LOCATION[$count]}/${dest_module_name[$count]}$module_suffix"
+ # override_dest_module_location() is what controls whether or not they're the same.
+
+ local location
+ location[0]="${dest_module_location[$count]}"
+ [[ ${DEST_MODULE_LOCATION[$count]} != ${dest_module_location[$count]} ]] && \
+ location[1]="${DEST_MODULE_LOCATION[$count]}"
+
+ echo "${location[@]}"
+}
+
+find_actual_dest_module_location()
+{
+ local module="$1"
+ local count="$2"
+ local kernelver="$3"
+ local arch="$4"
+ local locations="$(possible_dest_module_locations $count)"
+ local l
+ local dkms_owned
+ local installed
+ dkms_owned=$(compressed_or_uncompressed "${dkms_tree}/${module}/kernel-${kernelver}-${arch}/module" "${dest_module_name[$count]}")
+
+ for l in $locations; do
+ installed=$(compressed_or_uncompressed "${install_tree}/${kernelver}${l}" "${dest_module_name[${count}]}")
+ if [[ -n "${installed}" ]] && compare_module_version "${dkms_owned}" "${installed}" &>/dev/null; then
+ echo "${l}"
+ return 0
+ fi
+ done
+
+}
+
+# Remove compiled DKMS modules from any kernels they are installed in.
+do_uninstall()
+{
+ # $1 = kernel version
+ # $2 = arch
+
+ echo $"Module $module-$module_version for kernel $1 ($2)."
+
+ set_module_suffix "$1"
+
+ # If kernel-<kernelver> symlink points to this module, check for original_module and put it back
+ local was_active=""
+ local kernel_symlink=$(readlink -f "$dkms_tree/$module/kernel-$1-$2")
+ local real_dest_module_location
+ if [[ $kernel_symlink = $dkms_tree/$module/$module_version/$1/$2 ]]; then
+ was_active="true"
+ echo $"Before uninstall, this module version was ACTIVE on this kernel."
+ # remove kabi-tracking if last instance removed
+ if [[ -z $NO_WEAK_MODULES ]]; then
+ if [[ ${weak_modules} ]] && (module_status_built $module $module_version |grep -q "installed"); then
+ echo $"Removing any linked weak-modules"
+ list_each_installed_module "$module" "$1" "$2" | ${weak_modules} ${weak_modules_no_initrd} --remove-modules
+ fi
+ fi
+
+ for ((count=0; count < ${#built_module_name[@]}; count++)); do
+ real_dest_module_location="$(find_actual_dest_module_location $module $count $1 $2)"
+ echo $""
+ echo $"${dest_module_name[$count]}$module_suffix:"
+ echo $" - Uninstallation"
+ if [[ ${real_dest_module_location} ]]; then
+ echo $" - Deleting from: $install_tree/$1${real_dest_module_location}/"
+ rm -f "$install_tree/$1${real_dest_module_location}/${dest_module_name[$count]}$module_uncompressed_suffix"*
+ dir_to_remove="${real_dest_module_location#/}"
+ while [[ ${dir_to_remove} != ${dir_to_remove#/} ]]; do
+ dir_to_remove="${dir_to_remove#/}"
+ done
+ (if cd "$install_tree/$1"; then rpm -qf "${dir_to_remove}" >/dev/null 2>&1 || rmdir -p --ignore-fail-on-non-empty "${dir_to_remove}"; fi || true)
+ else
+ echo $" - Module was not found within $install_tree/$1/"
+ fi
+ echo $" - Original module"
+ local origmod=$(compressed_or_uncompressed "$dkms_tree/$module/original_module/$1/$2" "${dest_module_name[$count]}")
+ if [[ -n $origmod ]]; then
+ case "$running_distribution" in
+ debian* | ubuntu* )
+ ;;
+ *)
+ echo $" - Archived original module found in the DKMS tree"
+ echo $" - Moving it to: $install_tree/$1${DEST_MODULE_LOCATION[$count]}/"
+ mkdir -p "$install_tree/$1${DEST_MODULE_LOCATION[$count]}/"
+ mv -f "$origmod" "$install_tree/$1${DEST_MODULE_LOCATION[$count]}/" 2>/dev/null
+ ;;
+ esac
+ else
+ echo $" - No original module was found for this module on this kernel."
+ echo $" - Use the dkms install command to reinstall any previous module version."
+ fi
+ done
+ rm -f "$dkms_tree/$module/kernel-$1-$2"
+ else
+ echo $"This module version was INACTIVE for this kernel."
+ fi
+
+ # Run the post_remove script
+ run_build_script post_remove "$post_remove"
+
+ # Run depmod because we changed $install_tree
+ invoke_command "do_depmod $1" "depmod" '' background
+
+ # Delete the original_module if nothing for this kernel is installed anymore
+ if [[ $was_active && -d $dkms_tree/$module/original_module/$1/$2 && ! -d $dkms_tree/$module/original_module/$1/$2/collisions ]]; then
+ echo $""
+ echo $"Removing original_module from DKMS tree for kernel $1 ($2)"
+ rm -rf "$dkms_tree/$module/original_module/$1/$2" 2>/dev/null
+ [[ $(find $dkms_tree/$module/original_module/$1/* -maxdepth 0 -type d 2>/dev/null) ]] || rm -rf "$dkms_tree/$module/original_module/$1"
+ elif [[ $was_active && -d $dkms_tree/$module/original_module/$1/$2/collisions ]]; then
+ echo $""
+ echo $"Keeping directory $dkms_tree/$module/original_module/$1/$2/collisions/"
+ echo $"for your reference purposes. Your kernel originally contained multiple"
+ echo $"same-named modules and this directory is now where these are located."
+ fi
+ [[ $(find $dkms_tree/$module/original_module/* -maxdepth 0 -type d 2>/dev/null) ]] || rm -rf "$dkms_tree/$module/original_module"
+}
+
+module_is_broken_and_die() {
+ is_module_broken "$module" "$module_version" && die 4 $"$module/$module_version is broken!"\
+ $"Missing the source directory or the symbolic link pointing to it."\
+ $"Manual intervention is required!"
+}
+
+module_is_added_or_die()
+{
+ is_module_added "$module" "$module_version" || die 3 \
+ $"The module/version combo: $module-$module_version is not located in the DKMS tree."
+}
+
+maybe_unbuild_module()
+{
+ is_module_built "$module" "$module_version" "$1" "$2" || {
+ echo $"Module $module $module_version is not built for kernel $1 ($2)."\
+ $"Skipping..."
+ return 0
+ }
+
+ do_unbuild "$1" "$2"
+}
+
+maybe_uninstall_module()
+{
+ is_module_installed "$module" "$module_version" "$1" "$2" || {
+ echo $"Module $module $module_version is not installed for kernel $1 ($2)."\
+ $"Skipping..."
+ return 0
+ }
+ do_uninstall "$1" "$2"
+}
+
+uninstall_module()
+{
+ local i
+ for ((i=0; i < ${#kernelver[@]}; i++)); do
+ maybe_uninstall_module "${kernelver[$i]}" "${arch[$i]}"
+ done
+}
+
+do_unbuild()
+{
+ # Delete or "unbuild" the $kernel_version/$arch_used part of the tree
+ rm -rf "$dkms_tree/$module/$module_version/$1/$2"
+ [[ $(find $dkms_tree/$module/$module_version/$1/* -maxdepth 0 -type d 2>/dev/null) ]] || \
+ rm -rf "$dkms_tree/$module/$module_version/$1"
+}
+
+# Remove the build module, w/o removing/unregistering it.
+# This uninstalls any installed modules along the way
+unbuild_module()
+{
+ local i
+ for ((i=0; i < ${#kernelver[@]}; i++)); do
+ maybe_uninstall_module "${kernelver[$i]}" "${arch[$i]}"
+ maybe_unbuild_module "${kernelver[$i]}" "${arch[$i]}"
+ done
+}
+
+# Unregister a DKMS module. This uninstalls any installed modules along the way.
+remove_module()
+{
+ # Do --rpm_safe_upgrade check (exit out and don't do remove if inter-release RPM upgrade scenario occurs)
+ if [[ $rpm_safe_upgrade ]]; then
+ local pppid=$(awk '/PPid:/ {print $2}' /proc/$PPID/status)
+ local time_stamp=$(ps -o lstart --no-headers -p $pppid 2>/dev/null)
+ for lock_file in $tmp_location/dkms_rpm_safe_upgrade_lock.$pppid.*; do
+ [[ -f $lock_file ]] || continue
+ lock_head=$(head -n 1 $lock_file 2>/dev/null)
+ lock_tail=$(tail -n 1 $lock_file 2>/dev/null)
+ [[ $lock_head = $module-$module_version && $time_stamp && $lock_tail = $time_stamp ]] || continue
+ rm -f $lock_file
+ die 0 $"Remove cancelled because --rpm_safe_upgrade scenario detected."
+ done
+ fi
+
+ local i
+ for ((i=0; i < ${#kernelver[@]}; i++)); do
+ maybe_uninstall_module "${kernelver[$i]}" "${arch[$i]}"
+ maybe_unbuild_module "${kernelver[$i]}" "${arch[$i]}"
+ done
+
+ # Delete the $module_version part of the tree if no other $module_version/$kernel_version dirs exist
+ if ! find $dkms_tree/$module/$module_version/* -maxdepth 0 -type d 2>/dev/null | grep -Eqv "(build|tarball|driver_disk|rpm|deb|source)$"; then
+ echo $"Deleting module $module-$module_version completely from the DKMS tree."
+ rm -rf "$dkms_tree/$module/$module_version"
+ fi
+
+ # Get rid of any remnant directories if necessary
+ if (($(ls "$dkms_tree/$module" | wc -w | awk '{print $1}') == 0)); then
+ rm -rf "$dkms_tree/$module" 2>/dev/null
+ fi
+}
+
+# Given a kernel object, figure out which DKMS module it is from.
+find_module_from_ko()
+{
+ local ko="$1"
+ local basename_ko="${ko##*/}"
+ local module
+ local kernellink
+
+ for kernellink in "$dkms_tree"/*/kernel-*; do
+ [[ -L $kernellink ]] || continue
+ module=${kernellink#$dkms_tree/}
+ module=${module%/kernel-*}
+ diff "$kernellink/module/${basename_ko}" "${ko}" >/dev/null 2>&1 || continue
+ rest=$(readlink $kernellink)
+ echo "$module/$rest"
+ return 0
+ done
+ return 1
+}
+
+# Check to see if modules meeting the passed parameters are weak-installed.
+# This function's calling convention is different from the usual DKMS status
+# checking functions -- the kernel version we usually have is the one we are currently
+# running on, not necessarily the one we compiled the module for.
+module_status_weak() {
+ # $1 = module, $2 = module version, $3 = kernel version weak installed to,
+ # $4 = kernel arch, $5 = kernel version built for
+ [[ -z $NO_WEAK_MODULES ]] || return 1
+ [[ $weak_modules ]] || return 1
+ local m v k a kern weak_ko mod installed_ko f ret=1 oifs=$IFS
+ local -A already_found
+ for weak_ko in "$install_tree/"*/weak-updates/*; do
+ [[ -e $weak_ko ]] || continue
+ [[ -L $weak_ko ]] && installed_ko="$(readlink -f "$weak_ko")" || continue
+ IFS=/ read m v k a < <(IFS=$oifs find_module_from_ko "$weak_ko") || continue
+ kern=${weak_ko#$install_tree/}
+ kern=${kern%/weak-updates/*}
+ [[ $m = ${1:-*} && $v = ${2:-*} && $k = ${5:-*} && $a = ${4:-*} && $kern = ${3:-*} ]] || continue
+ already_found[$m/$v/$kern/$a/$k]+=${weak_ko##*/}" "
+ done
+ # Check to see that all ko's are present for each module
+ for mod in ${!already_found[@]}; do
+ IFS=/ read m v k a kern <<< "$mod"
+ # ensure each module is weak linked
+ for installed_ko in $(find $dkms_tree/$m/$v/$kern/$a/module -type f); do
+ [[ ${already_found[$mod]} != *"$installed_ko"* ]] && continue 2
+ done
+ ret=0
+ echo "installed-weak $mod"
+ done
+ return $ret
+}
+
+# Print the requested status lines for weak-installed modules.
+do_status_weak()
+{
+ local mvka m v k a kern status
+ while read status mvka; do
+ IFS=/ read m v k a kern <<< "$mvka"
+ echo "$m, $v, $k, $a: installed-weak from $kern"
+ done < <(module_status_weak "$@")
+}
+
+# Spit out all the extra status information that people running DKMS are
+# interested in, but that the DKMS internals do not usually care about.
+module_status_built_extra() (
+ set_module_suffix "$3"
+ read_conf "$3" "$4" "$dkms_tree/$1/$2/source/dkms.conf" 2>/dev/null
+ [[ -d $dkms_tree/$1/original_module/$3/$4 ]] && echo -n " (original_module exists)"
+ for ((count=0; count < ${#dest_module_name[@]}; count++)); do
+ tree_mod=$(compressed_or_uncompressed "$dkms_tree/$1/$2/$3/$4/module" "${dest_module_name[$count]}")
+ if ! [[ -n "$tree_mod" ]]; then
+ echo -n " (WARNING! Missing some built modules!)"
+ elif _is_module_installed "$@"; then
+ real_dest="$(find_actual_dest_module_location "$1" $count "$3" "$4")"
+ real_dest_mod=$(compressed_or_uncompressed "$install_tree/$3${real_dest}" "${dest_module_name[$count]}")
+ if ! diff -q "$tree_mod" "$real_dest_mod" >/dev/null 2>&1; then
+ echo -n " (WARNING! Diff between built and installed module!)"
+ fi
+ fi
+ done
+)
+
+# Return a list of all the modules that are either built or installed.
+# This and module_status do some juggling of $IFS to ensure that
+# we do not get word splitting where it would be inconvenient.
+module_status_built() {
+ local ret=1 directory ka k a state oifs="$IFS" IFS=''
+ for directory in "$dkms_tree/$1/$2/"${3:-+([0-9]).*}/${4:-*}; do
+ IFS="$oifs"
+ ka="${directory#$dkms_tree/$1/$2/}"
+ k="${ka%/*}"
+ a="${ka#*/}"
+ is_module_built "$1" "$2" "$k" "$a" || continue
+ ret=0
+ state="built"
+ _is_module_installed "$1" "$2" "$k" "$a" && state="installed"
+ echo "$state $1/$2/$k/$a"
+ IFS=''
+ done
+ IFS="$oifs"
+ return $ret
+}
+
+# Return the status of all modules that have been added, built, or installed.
+module_status() {
+ local oifs="$IFS" IFS='' mv m v directory ret=1
+ for directory in "$dkms_tree/"${1:-*}/${2:-*}; do
+ IFS="$oifs"
+ mv="${directory#$dkms_tree/}"
+ m="${mv%/*}"
+ v="${mv#*/}"
+ is_module_broken "$m" "$v" && { echo "broken $m/$v"; continue; }
+ is_module_added "$m" "$v" || continue
+ ret=0
+ module_status_built "$m" "$v" "$3" "$4" || echo "added $m/$v"
+ IFS=''
+ done
+ IFS="$oifs"
+ return $ret
+}
+
+# Print out the status in the format that people who call DKMS expect.
+# Internal callers should use the module_status functions, as their output
+# is easier to parse.
+do_status() {
+ local status mvka m v k a
+ # separate deprecation warnings from status output
+ local tmpfile=$(mktemp_or_die)
+ (module_status "$@") >"$tmpfile"
+ while read status mvka; do
+ IFS=/ read m v k a <<< "$mvka"
+ case $status in
+ broken)
+ echo "$m/$v: $status"
+ error $"$m/$v: Missing the module source directory or the symbolic link pointing to it."\
+ $"Manual intervention is required!"
+ ;;
+ added)
+ echo "$m/$v: $status"
+ ;;
+ built|installed)
+ echo -n "$m/$v, $k, $a: $status"
+ module_status_built_extra "$m" "$v" "$k" "$a"
+ echo
+ ;;
+ esac
+ done < "$tmpfile"
+ rm "$tmpfile"
+}
+
+# Show all our status in the format that external callers expect, even
+# though it is slightly harder to parse.
+show_status()
+{
+ local j state_array
+ if ((${#kernelver[@]} == 0)); then
+ do_status "$module" "$module_version" "$kernelver" "$arch"
+ do_status_weak "$module" "$module_version" "$kernelver" "$arch"
+ else
+ for ((j=0; j < ${#kernelver[@]}; j++)); do
+ do_status "$module" "$module_version" "${kernelver[$j]}" "${arch[$j]}"
+ do_status_weak "$module" "$module_version" "${kernelver[$j]}" "${arch[$j]}"
+ done
+ fi
+}
+
+make_tarball()
+{
+ # Read the conf file
+ read_conf_or_die "$kernelver" "$arch"
+
+ local -r temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX)
+ trap "rm -rf $temp_dir_name" EXIT
+ mkdir -p $temp_dir_name/dkms_main_tree
+
+ if [[ $source_only ]]; then
+ kernel_version_list="source-only"
+ else
+ local i
+ for ((i=0; i<${#kernelver[@]}; i++)); do
+ local -r intree_module_dir="$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}"
+ local -r temp_module_dir="$temp_dir_name/dkms_main_tree/${kernelver[$i]}"
+
+ if ! [[ -d "$intree_module_dir" ]]; then
+ die 6 $"No modules built for ${kernelver[$i]} (${arch[$i]})." \
+ $"Modules must already be in the built state before using mktarball."
+ fi
+
+ set_module_suffix "${kernelver[$i]}"
+
+ echo "Marking modules for ${kernelver[$i]} (${arch[$i]}) for archiving..."
+ if [[ ! $kernel_version_list ]]; then
+ kernel_version_list="kernel${kernelver[$i]}-${arch[$i]}"
+ else
+ kernel_version_list="${kernel_version_list}-kernel${kernelver[$i]}-${arch[$i]}"
+ fi
+ mkdir -p "$temp_module_dir"
+ cp -rf "$intree_module_dir" "$temp_module_dir"
+ done
+ fi
+
+ local -r source_dir="$dkms_tree/$module/$module_version/source"
+
+ # Copy the source_tree or make special binaries-only structure
+ if [[ $binaries_only ]]; then
+ local -r binary_only_dir="$temp_dir_name/dkms_binaries_only"
+
+ echo $""
+ echo $"Creating tarball structure to specifically accomodate binaries."
+
+ mkdir "$binary_only_dir"
+ echo "$module" > "$binary_only_dir/PACKAGE_NAME"
+ echo "$module_version" > "$binary_only_dir/PACKAGE_VERSION"
+ [[ ! $conf ]] && conf="$source_dir/dkms.conf"
+ cp -f $conf "$binary_only_dir/" 2>/dev/null
+ else
+ echo $""
+ echo $"Marking $source_dir for archiving..."
+ mkdir -p $temp_dir_name/dkms_source_tree
+ cp -rf $source_dir/* $temp_dir_name/dkms_source_tree
+ fi
+
+ if (( $(echo $kernel_version_list | wc -m | awk {'print $1'}) > 200 )); then
+ kernel_version_list="manykernels"
+ fi
+
+ local tarball_name="$module-$module_version-$kernel_version_list.dkms.tar.gz"
+ local tarball_dest="$dkms_tree/$module/$module_version/tarball/"
+
+ if [[ $archive_location ]]; then
+ tarball_name="${archive_location##*/}"
+ if [[ ${archive_location%/*} != $archive_location ]]; then
+ tarball_dest="${archive_location%/*}"
+ fi
+ fi
+
+ echo $""
+ echo $"Tarball location: $tarball_dest/$tarball_name"
+
+ if [[ ! -d $tarball_dest ]]; then
+ if ! mkdir -p "$tarball_dest" 2>/dev/null; then
+ die 9 $"Missing write permissions for $tarball_dest."
+ fi
+ fi
+
+ [[ -w $tarball_dest ]] || die 9 $"Missing write permissions for $tarball_dest."
+
+ if ! tar -C $temp_dir_name -caf $tarball_dest/$tarball_name . 2>/dev/null; then
+ die 6 $"Failed to make tarball."
+ fi
+}
+
+# A tiny helper function to make sure dkms.conf describes a valid package.
+get_pkginfo_from_conf() {
+ [[ -f $1 && $1 = *dkms.conf ]] || return
+ read_conf_or_die "$kernelver" "$arch" "$1"
+ [[ $PACKAGE_NAME && $PACKAGE_VERSION ]]
+}
+
+# Unpack a DKMS tarball from a few different supported formats.
+# We expect $archive_location to have been passed either as a raw argument or
+# with --archive.
+load_tarball()
+{
+ # Error out if $archive_location does not exist
+ if [[ ! -e $archive_location ]]; then
+ die 2 $"$archive_location does not exist."
+ fi
+
+ # If it is an .rpm file. install it with rpm, run an autoinstall, and then exit.
+ if [[ $archive_location = *.rpm ]]; then
+ if rpm -Uvh "$archive_location"; then
+ autoinstall
+ exit $?
+ else
+ die 9 $"Unable to install $archive_location using rpm." \
+ $"Check to ensure that your system can install .rpm files."
+ fi
+ fi
+
+ # Untar it into $tmp_location
+ local -r temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX)
+ trap "rm -rf $temp_dir_name" EXIT
+ tar -xaf $archive_location -C $temp_dir_name
+
+ if [[ ! -d $temp_dir_name/dkms_main_tree ]]; then
+ # Tarball was not generated from mktarball.
+ # Just find the dkms.conf file and load the source.
+ conf=$(find $temp_dir_name/ -name dkms.conf 2>/dev/null | head -n 1)
+ if [[ ! $conf ]]; then
+ die 3 $"Tarball does not appear to be a correctly formed DKMS archive. No dkms.conf found within it."
+ fi
+ add_source_tree "${conf%dkms.conf}"
+ return
+ fi
+
+ # Make sure its a sane tarball. Sane ones will have one of the two
+ # directories we test for.
+ for loc in dkms_source_tree dkms_binaries_only ''; do
+ if [[ ! $loc ]]; then
+ die 7 $"No valid dkms.conf in dkms_source_tree or dkms_binaries_only." \
+ $"$archive_location is not a valid DKMS tarball."
+ fi
+ local conf="$temp_dir_name/$loc/dkms.conf"
+ [[ -f $conf ]] || continue
+ if ! get_pkginfo_from_conf "$conf"; then
+ echo >&2
+ echo $"Malformed dkms.conf, refusing to load." >&2
+ continue
+ fi
+ if is_module_added "$PACKAGE_NAME" "$PACKAGE_VERSION" && \
+ [[ ! $force ]]; then
+ die 8 $"$PACKAGE_NAME-$PACKAGE_VERSION is already added!" \
+ $"Aborting."
+ fi
+ # Success!
+ break
+ done
+
+ module="$PACKAGE_NAME"; module_version="$PACKAGE_VERSION"
+ echo $""
+ echo $"Loading tarball for $module-$module_version"
+ case $loc in
+ dkms_source_tree)
+ add_source_tree "$temp_dir_name/dkms_source_tree"
+ ;;
+ dkms_binaries_only)
+ #if there is a source tree on the system already, don't build a binaries stub
+ if [[ ! -d $source_tree/$module-$module_version ]]; then
+ local -r source_dir="$dkms_tree/$module/$module_version/source"
+
+ echo $"Creating $source_dir"
+ mkdir -p "$source_dir"
+ echo $"Copying dkms.conf to $source_dir ..."
+ cp -rf "$temp_dir_name/dkms_binaries_only/dkms.conf" "$source_dir"
+ fi
+ ;;
+ esac
+
+ # At this point, the source has been copied to the appropriate location
+ # and registered with dkms, or a binary-only config has been noted.
+ # Now, add any included precompiled modules.
+
+ # Load precompiled modules.
+ for directory in "$temp_dir_name/dkms_main_tree"/*/*; do
+ [[ -d $directory ]] || continue
+
+ local -r kernel_arch_to_load=${directory/*dkms_main_tree\/}
+ local -r dkms_dir_location="$dkms_tree/$module/$module_version/$kernel_arch_to_load"
+
+ if [[ -d $dkms_dir_location && ! $force ]]; then
+ warn $"$dkms_dir_location already exists. Skipping..."
+ else
+ echo $"Loading $dkms_dir_location..."
+ rm -rf $dkms_dir_location
+ mkdir -p $dkms_dir_location
+ cp -rf $directory/* $dkms_dir_location/
+ fi
+ done
+
+ [[ $loc != dkms_binaries_only ]] || [[ -d $source_tree/$module-$module_version ]]
+}
+
+run_match()
+{
+ set_kernel_source_dir_and_kconfig "$kernelver"
+
+ # Error if $template_kernel is unset
+ if [[ ! $template_kernel ]]; then
+ die 1 $"Invalid number of parameters passed." \
+ $"Usage: match --templatekernel=<kernel-version> -k <kernel-version>" \
+ $" or: match --templatekernel=<kernel-version> -k <kernel-version> <module>"
+ fi
+
+ # Error out if $template_kernel = $kernel_version
+ if [[ $template_kernel = $kernelver ]]; then
+ die 2 $"The templatekernel and the specified kernel version are the same."
+ fi
+
+ # Read in the status of template_kernel
+ local template_kernel_status=$(do_status '' '' $template_kernel $arch | grep ": installed")
+
+ # If $module is set, grep the status only for that module
+ if [[ $module ]]; then
+ # Make sure that its installed in the first place
+ if ! [[ -d $dkms_tree/$module/ ]]; then
+ die 3 $"The module: $module is not located in the DKMS tree."
+ fi
+ template_kernel_status=$(echo "$template_kernel_status" | grep "^$module,")
+ fi
+
+ echo $""
+ echo $"Matching modules in kernel: $kernelver ($arch)"
+ echo $"to the configuration of kernel: $template_kernel ($arch)"
+
+ # Prepare the kernel just once but only if there is actual work to do
+ if [[ ! $template_kernel_status ]]; then
+ echo $""
+ echo $"There is nothing to be done for this match."
+ return 0
+ fi
+
+ prepare_kernel "$kernelver" "$arch"
+
+ # Iterate over the kernel_status and match kernel to the template_kernel
+ while read template_line; do
+ template_module=$(echo "$template_line" | awk {'print $1'} | sed 's/,$//')
+ template_version=$(echo "$template_line" | awk {'print $2'} | sed 's/,$//')
+
+ # Print out a match header
+ echo $"Module: $template_module"
+ echo $"Version: $template_version"
+
+ # Continue if the status is broken, as there is nothing we can do
+ if is_module_broken "$template_module" "$template_version"; then
+ error $"$template_module/$template_version is broken!"\
+ $"Missing the source directory or the symbolic link pointing to it."\
+ $"Manual intervention is required!"
+ continue
+ fi
+ maybe_build_module "$template_module" "$template_version" "$kernelver" "$arch"
+ maybe_install_module "$template_module" "$template_version" "$kernelver" "$arch"
+ done < <(echo "$template_kernel_status")
+}
+
+report_build_problem()
+{
+ # If apport is on the system, files a build problem
+ if [[ -x /usr/share/apport/apport ]] && which python3 >/dev/null; then
+ python3 /usr/share/apport/package-hooks/dkms_packages.py -m $module -v $module_version -k ${kernelver[0]}
+ fi
+ die "$@"
+}
+
+# Little helper function for reading args from the commandline.
+# it automatically handles -a b and -a=b variants, and returns 1 if
+# we need to shift $3.
+read_arg() {
+ # $1 = arg name
+ # $2 = arg value
+ # $3 = arg parameter
+ local rematch='^[^=]*=(.*)$'
+ if [[ $2 =~ $rematch ]]; then
+ read "$1" <<< "${BASH_REMATCH[1]}"
+ else
+ read "$1" <<< "$3"
+ # There is no way to shift our callers args, so
+ # return 1 to indicate they should do it instead.
+ return 1
+ fi
+}
+
+# A couple of helper functions for parsing out our most common arguments.
+# This one allows you to pass -k kernel.version-extra/arch instead of
+# -k kernel-version.extra -a arch.
+# This makes it harder to pass mismatching numbers of kernel/arch pairs, because
+# they are all passed at the same time.
+parse_kernelarch(){
+ if [[ $1 =~ $mv_re ]]; then
+ kernelver[${#kernelver[@]}]="${BASH_REMATCH[1]}"
+ arch[${#arch[@]}]="${BASH_REMATCH[2]}"
+ else
+ kernelver[${#kernelver[@]}]="$1"
+ fi
+}
+
+# This allows you to pass module and module_version information on the commandline
+# in a more convenient form. Instead of the mostly mandatory and annoying
+# -m module -v module_version, you can use either -m module/module_version,
+# or just a raw module/module_version with no -m parameter.
+# This vastly improves readability and discoverability of
+# commands on the commandline.
+parse_moduleversion(){
+ if [[ $1 =~ $mv_re ]]; then
+ module="${BASH_REMATCH[1]}"
+ module_version="${BASH_REMATCH[2]}"
+ else
+ module="$1"
+ fi
+}
+
+check_root() {
+ [[ $(id -u) = 0 ]] && return
+ die 1 $"You must be root to use this command."
+}
+
+check_rw_dkms_tree() {
+ [[ -w "$dkms_tree" ]] && return
+ die 1 $"No write access to DKMS tree at ${dkms_tree}"
+}
+
+# Add a passed source tree to the default source location.
+# We will check the dkms.conf file to make sure it is valid
+# beforehand.
+add_source_tree() {
+ local from=$(readlink -f $1)
+ if ! [[ $from && -f $from/dkms.conf ]]; then
+ die 9 $"$1 must contain a dkms.conf file!"
+ fi
+ check_root
+ setup_kernels_arches
+ if ! get_pkginfo_from_conf "$from/dkms.conf" ; then
+ die 10 $"Malformed dkms.conf file. Cannot load source tree."
+ fi
+ module="$PACKAGE_NAME"
+ module_version="$PACKAGE_VERSION"
+ if [[ $force && -d $source_tree/$module-$module_version ]]; then
+ echo >&2
+ echo $"Forcing install of $module-$module_version"
+ rm -rf "$source_tree/$module-$module_version"
+ fi
+
+ # We are already installed, just return.
+ case $from in
+ "$source_tree/$module-$module_version")
+ return
+ ;;
+ "$dkms_tree/$module/$version/source")
+ return
+ ;;
+ "$dkms_tree/$module/$version/build")
+ return
+ ;;
+ esac
+ mkdir -p "$source_tree/$module-$module_version"
+ cp -fr "$from"/* "$source_tree/$module-$module_version"
+}
+
+# This code used to be in dkms_autoinstaller.
+# Moving it into the main dkms script gets rid of a fair amount of duplicate
+# functionality, and makes it much easier to reinstall DKMS kernel modules
+# by hand if dkms_autoinstaller is not used.
+autoinstall() {
+ local status mv mvka m v k a
+ local progress next_depends
+ local -a to_install=()
+ local -a next_install=()
+ local -a known_modules=()
+ local -a installed_modules=()
+ local -a skipped_modules=()
+ local -a failed_modules=()
+ local -A build_depends=()
+ local -A latest=()
+
+ # Walk through our list of installed and built modules, and create
+ # a list of modules and their latest version.
+ while read status mvka; do
+ IFS='/' read m v k a <<< "$mvka"
+ # If the module status is broken there is nothing that can be done
+ if [[ $status = broken ]]; then
+ error $"$m/$v is broken! Missing the source directory or the symbolic link pointing to it."\
+ $"Manual intervention is required!"
+ continue
+ fi
+ if [[ -z ${latest[$m]} ]]; then
+ known_modules[${#known_modules[@]}]="$m"
+ latest[$m]="$v"
+ elif [[ ("$(VER "$v")" > "$(VER "${latest["$m"]}")") ]]; then
+ latest["$m"]="$v"
+ fi
+ done < <(module_status)
+
+ # Walk through our list of known modules, and create
+ # a list of modules that need to be reinstalled.
+ for m in "${known_modules[@]}"; do
+ v="${latest["$m"]}"
+ # If the module is already installed or weak-installed, skip it.
+ if _is_module_installed "$m" "$v" "$kernelver" "$arch"; then
+ installed_modules[${#installed_modules[@]}]="$m"
+ continue
+ fi
+ if module_status_weak "$m" "$v" "$kernelver" "$arch" >/dev/null; then
+ installed_modules[${#installed_modules[@]}]="$m"
+ continue
+ fi
+ # If the module does not want to be autoinstalled, skip it.
+ read_conf_or_die "$kernelver" "$arch" "$dkms_tree/$m/$v/source/dkms.conf"
+ if [[ ! $AUTOINSTALL ]]; then
+ continue
+ fi
+ # Otherwise, autoinstall the latest version we have hanging around.
+ to_install[${#to_install[@]}]="$m/$v"
+ build_depends["$m"]="${BUILD_DEPENDS[@]}"
+ done
+
+ [[ $to_install ]] || return 0
+
+ while true; do
+ progress=0
+ next_install=( )
+
+ # Step 1: Remove installed modules from all dependency lists.
+ for m in ${!build_depends[@]}; do
+ next_depends=
+ for d in ${build_depends[$m]}; do
+ for i in ${installed_modules[@]} ${skipped_modules[@]}; do
+ [[ "$d" = "$i" ]] && continue 2
+ done
+ next_depends+="$d "
+ done
+ build_depends[$m]="${next_depends%% }"
+ done
+
+ # Step 2: Install modules that have an empty dependency list.
+ for mv in "${to_install[@]}"; do
+ IFS=/ read m v <<< "$mv"
+ if [[ -z ${build_depends[$m]} ]]; then
+ (module="$m" module_version="$v" kernelver="$kernelver" arch="$arch" install_module)
+ status=$?
+ if (( status == 0 )); then
+ installed_modules[${#installed_modules[@]}]="$m"
+ progress=$(($progress +1))
+ elif (( status == 77 )); then
+ skipped_modules[${#skipped_modules[@]}]="$m"
+ progress=$(($progress +1))
+ else
+ failed_modules[${#failed_modules[@]}]="$m($status)"
+ fi
+ else
+ next_install[${#next_install[@]}]="$mv"
+ fi
+ done
+
+ wait
+
+ # Step 3: Remove modules that install was attempted for
+ # during Step 2 from the job queue.
+ to_install=( "${next_install[@]}" )
+
+ # Step 4: Keep going if at least one module was installed during
+ # this iteration.
+ (( progress > 0 )) || break;
+
+ done
+
+ if (( ${#installed_modules[@]} > 0 )); then
+ echo "dkms autoinstall on $kernelver/$arch succeeded for ${installed_modules[@]}"
+ fi
+
+ if (( ${#skipped_modules[@]} > 0 )); then
+ echo "dkms autoinstall on $kernelver/$arch was skipped for ${skipped_modules[@]}"
+ fi
+
+ if (( ${#failed_modules[@]} > 0 )); then
+ echo "dkms autoinstall on $kernelver/$arch failed for ${failed_modules[@]}"
+ fi
+
+ for mv in "${to_install[@]}"; do
+ IFS=/ read m v <<< "$mv"
+ echo "$m/$v autoinstall failed due to missing dependencies: ${build_depends[$m]}"
+ done
+
+ if (( ${#failed_modules[@]} > 0 || ${#to_install[@]} > 0 )); then
+ die 11 $"One or more modules failed to install during autoinstall." \
+ $"Refer to previous errors for more information."
+ fi
+}
+
+#############################
+#### ####
+#### Program Starts Here ####
+#### ####
+#############################
+
+# Ensure files and directories we create are readable to anyone,
+# since we aim to build as a non-root user
+umask 022
+
+# Unset environment variables that may interfere with the build
+unset CC CXX CFLAGS CXXFLAGS LDFLAGS
+
+# Set important variables
+current_kernel=$(uname -r)
+current_os=$(uname -s)
+running_distribution=$(distro_version) || exit
+dkms_tree="/var/lib/dkms"
+source_tree="/usr/src"
+install_tree="@MODDIR@"
+tmp_location=${TMPDIR:-/tmp}
+verbose=""
+symlink_modules=""
+
+# Check that we can write temporary files
+tmpfile=$(mktemp_or_die)
+echo "Hello, DKMS!" > "$tmpfile"
+if [[ "$(cat "$tmpfile")" != "Hello, DKMS!" ]]; then
+ warn $"dkms will not function properly without some free space in \$TMPDIR ($tmp_location)."
+fi
+rm -f "$tmpfile"
+
+# These can come from the environment or the config file
+[[ ! ${ADDON_MODULES_DIR} && -e /etc/sysconfig/module-init-tools ]] && . /etc/sysconfig/module-init-tools
+addon_modules_dir="${ADDON_MODULES_DIR}"
+weak_modules="${WEAK_MODULES_BIN}"
+
+# Source in configuration not related to signing
+read_framework_conf $dkms_framework_nonsigning_variables
+
+
+# Clear out command line argument variables
+module=""
+module_version=""
+template_kernel=""
+conf=""
+kernel_config=""
+kconfig_fromcli=""
+archive_location=""
+kernel_source_dir=""
+ksourcedir_fromcli=""
+action=""
+force=""
+force_version_override=""
+binaries_only=""
+source_only=""
+all=""
+module_suffix=""
+module_uncompressed_suffix=""
+module_compressed_suffix=""
+rpm_safe_upgrade=""
+declare -a directive_array=() kernelver=() arch=()
+weak_modules=''
+last_mvka=''
+last_mvka_conf=''
+try_source_tree=''
+die_is_fatal="yes"
+[ -x /sbin/weak-modules ] && weak_modules='/sbin/weak-modules'
+[ -x /usr/lib/module-init-tools/weak-modules ] && weak_modules='/usr/lib/module-init-tools/weak-modules'
+no_depmod=""
+
+action_re='^(remove|(auto|un)?install|match|mktarball|(un)?build|add|status|ldtarball)$'
+
+# Parse command line arguments
+while (($# > 0)); do
+ case $1 in
+ --module*|-m)
+ read_arg _mv "$1" "$2" || shift
+ parse_moduleversion "$_mv"
+ ;;
+ -v)
+ read_arg module_version "$1" "$2" || shift
+ ;;
+ --kernelver*|-k)
+ read_arg _ka "$1" "$2" || shift
+ parse_kernelarch "$_ka"
+ ;;
+ --templatekernel*)
+ read_arg template_kernel "$1" "$2" || shift
+ ;;
+ -c)
+ read_arg conf "$1" "$2" || shift
+ ;;
+ --quiet|-q)
+ exec >/dev/null 2>&1
+ ;;
+ --version|-V)
+ echo $"@RELEASE_STRING@"
+ exit 0
+ ;;
+ --no-initrd)
+ # This is an old option, consume and warn
+ deprecated $"--no-initrd"
+ ;;
+ --no-clean-kernel)
+ # This is an old option, consume and warn
+ deprecated $"--no-clean-kernel"
+ ;;
+ --no-prepare-kernel)
+ # This is an old option, consume and warn
+ deprecated $"--no-prepare-kernel"
+ ;;
+ --binaries-only)
+ binaries_only="binaries-only"
+ ;;
+ --source-only)
+ source_only="source-only"
+ ;;
+ --force)
+ force="true"
+ ;;
+ --force-version-override)
+ force_version_override="true"
+ ;;
+ --all)
+ all="true"
+ ;;
+ --verbose)
+ verbose="true"
+ ;;
+ --rpm_safe_upgrade)
+ rpm_safe_upgrade="true"
+ ;;
+ --dkmstree*)
+ read_arg dkms_tree "$1" "$2" || shift
+ ;;
+ --sourcetree*)
+ read_arg source_tree "$1" "$2" || shift
+ ;;
+ --installtree*)
+ read_arg install_tree "$1" "$2" || shift
+ ;;
+ --symlink-modules)
+ symlink_module="true"
+ ;;
+ --config*)
+ read_arg kernel_config "$1" "$2" || shift
+ kconfig_fromcli="true"
+ ;;
+ --archive*)
+ read_arg archive_location "$1" "$2" || shift
+ ;;
+ --arch*|-a)
+ read_arg _aa "$1" "$2" || shift
+ arch[${#arch[@]}]="$_aa"
+ ;;
+ --kernelsourcedir*)
+ read_arg kernel_source_dir "$1" "$2" || shift
+ ksourcedir_fromcli="true"
+ ;;
+ --directive*)
+ read_arg _da "$1" "$2" || shift
+ directive_array[${#directive_array[@]}]="$_da"
+ ;;
+ --no-depmod)
+ no_depmod="true"
+ ;;
+ --modprobe-on-install)
+ modprobe_on_install="true"
+ ;;
+ --debug)
+ export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): '
+ set -x
+ ;;
+ -j)
+ read_arg parallel_jobs "$1" "$2" || shift
+ ;;
+ -*)
+ error $" Unknown option: $1"
+ show_usage
+ exit 2
+ ;;
+ *)
+ if [[ $1 =~ $action_re ]]; then
+ [[ $action ]] && die 4 $"Cannot specify more than one action."
+ action="$1" # Add actions to the action list
+ elif [[ -f $1 && $1 = *dkms.conf ]]; then
+ try_source_tree="${1%dkms.conf}./" # Flag as a source tree
+ elif [[ -d $1 && -f $1/dkms.conf ]]; then
+ try_source_tree="$1" # ditto
+ elif [[ -f $1 ]]; then
+ archive_location="$1" # It is a file, assume it is an archive.
+ elif [[ ! $module ]]; then
+ parse_moduleversion "$1" # Assume it is a module/version pair.
+ else
+ warn $"I do not know how to handle $1."
+ fi
+ ;;
+ esac
+ shift
+done
+
+# Sanity checking
+
+# The <(cmd) idiom does not work if /proc is not mounted
+read line < <(echo "Hello, DKMS!")
+if [[ $line != "Hello, DKMS!" ]]; then
+ warn $"dkms will not function properly if /proc is not mounted."
+fi
+
+# Error out if binaries-only is set and source-only is set
+if [[ $binaries_only && $source_only ]]; then
+ die 8 $" You have specified both --binaries-only and --source-only." \
+ $"You cannot do this."
+fi
+
+# Error if # of arches doesn't match # of kernels
+if (( ${#kernelver[@]} != ${#arch[@]} && \
+ ${#arch[@]} > 1 )); then
+ die 1 $" If more than one arch is specified on the command line, then there" \
+ $"must be an equal number of kernel versions also specified (1:1 relationship)."
+fi
+
+# Check that kernel version and all aren't both set simultaneously
+if [[ $kernelver && $all ]]; then
+ die 2 $" You cannot specify a kernel version and also specify" \
+ $"--all on the command line."
+fi
+
+# Check that arch and all aren't both set simultaneously
+if [[ $arch && $all ]]; then
+ die 3 $" You cannot specify an arch and also specify" \
+ $"--all on the command line."
+fi
+
+# Since initramfs/initrd rebuild is not requested, skip it with Redhat's weak-modules
+if [[ $weak_modules ]]; then
+ weak_modules_no_initrd="--no-initramfs"
+fi
+
+# Default to -j<number of CPUs>
+parallel_jobs=${parallel_jobs:-$(get_num_cpus)}
+
+# Make sure we're not passing -j0 to make; treat -j0 as just "-j"
+[[ "$parallel_jobs" = 0 ]] && parallel_jobs=""
+
+setup_kernels_arches "$action"
+case "$action" in
+remove | unbuild | uninstall)
+ check_module_args $action
+ module_is_broken_and_die
+ module_is_added_or_die
+ [[ $action = uninstall ]] && check_root || check_rw_dkms_tree
+ ${action}_module
+ ;;
+add | build | install)
+ check_all_is_banned $action # TODO: fix/enable --all
+ [[ $action != add ]] && module_is_broken_and_die
+ [[ $action = install ]] && check_root || check_rw_dkms_tree
+ ${action}_module
+ ;;
+autoinstall)
+ check_root && autoinstall
+ ;;
+match)
+ check_root && have_one_kernel "match" && run_match
+ ;;
+mktarball)
+ check_module_args mktarball
+ module_is_broken_and_die
+ module_is_added_or_die
+ make_tarball
+ ;;
+status)
+ show_status
+ ;;
+ldtarball) # Make sure they're root if we're using --force
+ if [[ $(id -u) != 0 ]] && [[ $force = true ]]; then
+ die 1 $"You must be root to use this command with the --force option."
+ fi
+ load_tarball && add_module
+ ;;
+*)
+ error $"Unknown action specified: \"$action\""
+ show_usage
+ ;;
+esac