Yanz Mini Shell
[_]
[-]
[X]
[
HomeShell 1
] [
HomeShell 2
] [
Upload
] [
Command Shell
] [
Scripting
] [
About
]
[ Directory ] =>
/
home
guitarlisty
public_html
Action
[*]
New File
[*]
New Folder
Sensitive File
[*]
/etc/passwd
[*]
/etc/shadow
[*]
/etc/resolv.conf
[
Delete
] [
Edit
] [
Rename
] [
Back
]
#!/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 # # Exit status values and error messages used by dkms: # (as parameters to die, diewarn, report_build_problem, exit) # # 0: global: SUCCESS # 0: remove_module(): Remove cancelled because --rpm_safe_upgrade scenario detected. # 1: ldtarball: You must be root to use this command with the --force option. # 1: check_root(): You must be root to use this command. # 1: check_rw_dkms_tree(): No write access to DKMS tree at ... # 1: mktemp_or_die(): Unable to make temporary file/directory. # 1: check_module_args(): Arguments <module> and <module-version> are not specified. # 1: run_match(): Invalid number of parameters passed. # 1: global: 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). # 2: global: Unknown option: ... # 2: global: You cannot specify a kernel version and also specify --all on the command line. # 2: run_match(): The templatekernel and the specified kernel version are the same. # 2: add_module(): Could not find module source directory. # 2: load_tarball(): ... does not exist. # 3: global: You cannot specify an arch and also specify --all on the command line. # 3: load_tarball(): Tarball does not appear to be a correctly formed DKMS archive. No dkms.conf found within it. # 3: run_match(): The module: $module is not located in the DKMS tree. # 3: add_module(): You cannot add the same module/version combo more than once. # 3: prepare_build(): This module/version has already been built on: ... # 3: module_is_added_or_die(): The module/version combo: ... is not located in the DKMS tree. # 4: global: Cannot specify more than one action. # 4: distro_version(): System is missing os-release file. # 4: read_conf(): Could not locate dkms.conf file. # 4: have_one_kernel(): The action ... does not support multiple kernel version parameters on the command line. # 4: module_is_broken_and_die(): ... is broken! # 5: check_all_is_banned(): The action ... does not support the --all parameter. # 5: prepare_build(): Patch ... as specified in dkms.conf contains '..' path component. # 5: prepare_build(): Patch ... as specified in dkms.conf cannot be found in ... # 5: install: This module/version combo is already installed for kernel ... # 6: prepare_build(): Application of patch ... failed. # 6: install: You cannot install a module onto a non-existant kernel. # 6: install: Installation aborted. # 6: install: Install Failed (depmod problems). Module rolled back to built state. # 6: make_tarball(): Modules must already be in the built state before using mktarball. # 6: make_tarball(): Failed to make tarball. # 7: load_tarball(): No valid dkms.conf in dkms_source_tree or dkms_binaries_only. # 7: actual_build(): Build of ... failed for: ... # 8: load_tarball(): ... is already added! # 8: global: You have specified both --binaries-only and --source-only. # 8: read_conf_or_die(): Bad conf file. # 8: prepare_build(): The directory $source_dir does not appear to have module source located within it. # 9: add_source_tree(): ... must contain a dkms.conf file! # 9: make_tarball(): Missing write permissions for ... # 9: load_tarball(): Unable to install ... using rpm. # 10: add_source_tree(): Malformed dkms.conf file. Cannot load source tree. # 10: build: Bad return status for module build on kernel: ... # 11: autoinstall: One or more modules failed to install during autoinstall. # 12: setup_kernels_arches(): Could not determine architecture. # 13: build: Aborting build of module ... for kernel ... due to missing BUILD_DEPENDS: ... # 14: kernel_prerm: dkms kernel_prerm for kernel ... failed for module(s) ... # 21: prepare_kernel(): Your kernel headers for kernel ... cannot be found ... # 77: skipped due to BUILD_EXCLUSIVE # 101: install: pre_install failed, aborting install. 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 parallel_jobs compress_gzip_opts compress_xz_opts compress_zstd_opts" # 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 DIR="$install_tree/$KVER/build" echo $DIR else echo $kernel_source_dir fi } _check_kernel_dir() { DIR=$(_get_kernel_dir $1) test -e $DIR/include return $? } on_exit() { local exitcode_on_exit=$? # must be one line or $? captures rc from `local` local j j="$(jobs -p)" [[ -n "$j" ]] && kill $j 2>/dev/null [[ $make_tarball_rm_temp_dir_name ]] && eval "$make_tarball_rm_temp_dir_name" [[ $load_tarball_rm_temp_dir_name ]] && eval "$load_tarball_rm_temp_dir_name" exit $exitcode_on_exit } unset make_tarball_rm_temp_dir_name load_tarball_rm_temp_dir_name trap on_exit EXIT # 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 (including stderr) to this file # $4 = background, if you want print . each 3 seconds while command runs local cmd local cmd_description local cmd_output_file local cmd_mode local exitval local progresspid cmd="$1" cmd_description="$2" cmd_output_file="$3" cmd_mode="$4" exitval=0 [[ $verbose ]] && echo -e "$cmd" || echo -en "$cmd_description..." if [[ $cmd_mode == background && ! $verbose && $package_name != dkms*_test ]]; then while true ; do sleep 3 echo -n "." done & progresspid=$! fi if [[ -n "$cmd_output_file" ]]; then local t_start local t_end echo -e "$cmd_description" >> "$cmd_output_file" echo -e "# command: $cmd" >> "$cmd_output_file" t_start=$SECONDS ( eval "$cmd" ) >> "$cmd_output_file" 2>&1 exitval=$? t_end=$SECONDS echo -e "\n# exit code: $exitval" >> "$cmd_output_file" echo "# elapsed time: $(date -u -d "0 $t_end sec - $t_start sec" +%T)" >> "$cmd_output_file" elif [[ -z "$cmd_output_file" && $cmd_mode == background && ! $verbose ]]; then ( eval "$cmd" ) >/dev/null 2>&1 exitval=$? else ( eval "$cmd" ) exitval=$? fi if [ -n "$progresspid" ]; then kill -9 "$progresspid" >/dev/null 2>&1 wait "$progresspid" 2>/dev/null fi if (( exitval > 0 )); then echo -en "(bad exit status: $exitval)" # Print the failing command without the clunky redirection [[ ! $verbose ]] && echo -e "\nFailed command:\n$1" else echo " done." fi return "$exitval" } error() ( exec >&2 echo "" 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 | generate_mok |" echo " kernel_postinst | kernel_prerm }" 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-include/config/auto.conf-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] [--help]" } 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 local test2 test1="$1/$2$module_uncompressed_suffix" 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" -type f -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. Do not use modules.dep # as it might not be available (in Red Hat removal is triggered with kernel-core but modules.dep # is contained in kernel-modules-core). set_module_suffix() { # $1 = the kernel to base the module_suffix on kernel_test="${1:-$(uname -r)}" module_uncompressed_suffix=".ko" find $install_tree/$kernel_test/ -name "*.ko.gz" 2>/dev/null | grep -q . && module_compressed_suffix=".gz" find $install_tree/$kernel_test/ -name "*.ko.xz" 2>/dev/null | grep -q . && module_compressed_suffix=".xz" find $install_tree/$kernel_test/ -name "*.ko.zst" 2>/dev/null | grep -q . && 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 if [[ -e "${kernel_source_dir}/include/config/auto.conf" ]]; then kernel_config="${kernel_source_dir}/include/config/auto.conf" else kernel_config="${kernel_source_dir}/.config" fi 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() { check_all_is_banned $1 if (( ${#kernelver[@]} != 1 )); then [[ $1 =~ kernel_(postinst|prerm) ]] && die 4 "The action $1 requires exactly one kernel version parameter on the command line." die 4 "The action $1 does not support multiple kernel version parameters on the command line." fi } # 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 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 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,weakdep,*.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 orig_location="$1" [[ ${addon_modules_dir} ]] && echo "/${addon_modules_dir}" && return 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 to_source_file="$1"; shift declare -a -r export_envs=("$@") local -r CR=$(echo -e '\r') local tmpfile 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]%$CR}\"' 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 local read_conf_file return_value=0 read_conf_file="$dkms_tree/$module/$module_version/source/dkms.conf" # Set variables supported in dkms.conf files (eg. $kernelver) local kernelver local arch kernelver="$1" 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 local array_size local s array_size=0 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 2>&1 | grep -q clang; then make_command="${make_command} LLVM=1" fi elif [[ -e "${kernel_config}" ]]; then if grep -q CONFIG_CC_IS_CLANG=y "${kernel_config}"; then make_command="${make_command} LLVM=1" 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 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 local res local i lib_tree="$install_tree/$1" res= i=0 if [[ -n $3 ]]; then # Magic split into array syntax saves trivial awk and cut calls. local -a obs local -a my local obsolete obs=(${3//-/ }) my=(${1//-/ }) 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 in kernel $3." >&2 echo "We will avoid installing 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 "Cannot do version sanity checking because multiple ${4}$module_suffix modules were found in kernel $1." return 0 fi local dkms_module dkms_module=$(compressed_or_uncompressed "$dkms_tree/$module/$module_version/$1/$2/module/" "${4}") local cmp_res 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 verinfo="$(get_module_verinfo "${dkms_module}")" if [[ "$(echo "$verinfo" | tr -d '[:space:]')" ]] || diff "${kernels_module}" "${dkms_module}" &>/dev/null; then verinfo=$(echo "$verinfo" | head -n 1) if [[ $verinfo ]]; then echo "Module ${kernels_module} already installed at version ${verinfo}, override by specifying --force" >&2 else echo "Module ${kernels_module} already installed (unversioned module), override by specifying --force" >&2 fi 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 # $3 = (optional) logfile for script output local script_type local 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 if [[ $3 ]]; then invoke_command "cd $dkms_tree/$module/$module_version/$script_type/ && $run" "Running the $1 script" "$3" background || exit $? else echo "Running the $1 script:" ( cd "$dkms_tree/$module/$module_version/$script_type/" exec $run ) fi 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 local lock_name pppid=$(awk '/PPid:/ {print $2}' /proc/$PPID/status) 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 # Check that kernel-source exists _check_kernel_dir "$1" || { die 21 "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_mok() { 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 } prepare_signing() { # Lazy source in signing related configuration read_framework_conf $dkms_framework_signing_variables 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') 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 prepare_mok do_signing=1 } # Build a module that has been registered with DKMS. prepare_and_actual_build() { # If the module has not been added, try to add it. if ! is_module_added "$module" "$module_version" ; then add_module echo "" fi 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" local -r build_log="$build_dir/make.log" local bd local bd_missing local status local mvka # 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/$module_version 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." # Check for missing BUILD_DEPENDS bd_missing= for bd in "${BUILD_DEPENDS[@]}"; do while read status mvka; do [[ $status = installed ]] && continue 2 done < <(module_status "$bd" "*" "$kernelver" "$arch") bd_missing="$bd_missing $bd" done if [[ $bd_missing ]]; then if [[ $force ]]; then warn "Trying to build module $module/$module_version for kernel $kernelver ($arch) despite of missing BUILD_DEPENDS:$bd_missing." else die 13 "Aborting build of module $module/$module_version for kernel $kernelver ($arch) due to missing BUILD_DEPENDS:$bd_missing."\ "You may override by specifying --force." fi fi # Set up temporary build directory for build rm -rf "$build_dir" cp -a "$source_dir/" "$build_dir" echo "DKMS (dkms-3.1.5) make.log for $module/$module_version for kernel $kernelver ($arch)" >> "$build_log" date >> "$build_log" cd "$build_dir" # Apply any patches for p in "${patch_array[@]}"; do [[ patches/$p == *"/../"* ]] && report_build_problem 5 \ "Patch $p as specified in dkms.conf contains '..' path component." [[ ! -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" "$build_log" background || \ report_build_problem 6 "Application of patch $p failed." \ "Consult $build_log for more information." done if [[ -f $kernel_source_dir/.kernelvariables ]]; then CC=$(echo -e "show-%:\n\t@echo \$(\$*)\ninclude $kernel_source_dir/.kernelvariables" | make -f - show-CC) export CC else unset CC fi if [[ -e "${kernel_config}" ]]; then local cc cc=$(sed -n 's|^CONFIG_CC_VERSION_TEXT="\([^ ]*\) .*"|\1|p' "${kernel_config}") if command -v "$cc" >/dev/null; then CC="$cc" KERNEL_CC="$cc" export CC export KERNEL_CC fi if grep -q 'CONFIG_CC_IS_CLANG=y' "${kernel_config}"; then local cc cc=clang if command -v "$cc" >/dev/null; then CC="$cc" KERNEL_CC="$cc" export CC export KERNEL_CC fi fi if grep -q 'CONFIG_LD_IS_LLD=y' "${kernel_config}"; then local ld ld=ld.lld if command -v "$ld" >/dev/null; then LD="$ld" KERNEL_LD="$ld" export LD export KERNEL_LD fi fi fi # Run the pre_build script run_build_script pre_build "$pre_build" "$build_log" invoke_command "$clean" "Cleaning build area" "$build_log" background local the_make_command 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 $build_log 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/" # Save a copy of the new module mkdir "$base_dir/module" >/dev/null if [ -f "$build_dir/Module.symvers" ] ; then cp -f "$build_dir/Module.symvers" "$base_dir/module/Module.symvers" fi for ((count=0; count < ${#built_module_name[@]}; count++)); do local the_module local built_module local compressed_module the_module="$build_dir/${built_module_location[$count]}${built_module_name[$count]}" built_module="$the_module$module_uncompressed_suffix" compressed_module="$the_module$module_suffix" if [[ ${strip[$count]} != no ]] && [[ ${CC} == "clang" ]]; then llvm-strip -g "$built_module" elif [[ ${strip[$count]} != no ]]; then strip -g "$built_module" fi if (( do_signing )); then echo "Signing module $built_module" "$sign_file" "$sign_hash" "$mok_signing_key" "$mok_certificate" "$built_module" 2>/dev/null fi if [[ $module_compressed_suffix = .gz ]]; then gzip $compress_gzip_opts -f "$built_module" || compressed_module="" elif [[ $module_compressed_suffix = .xz ]]; then xz $compress_xz_opts -f "$built_module" || compressed_module="" elif [[ $module_compressed_suffix = .zst ]]; then zstd $compress_zstd_opts -f "$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" "$build_log" # Run the clean commands cd "$dkms_tree/$module/$module_version/build" invoke_command "$clean" "Cleaning build area" "$build_log" background cd - >/dev/null # Save the log file mv -f "$build_log" "$base_dir/log/make.log" 2>/dev/null # Clean the build directory rm -rf "$dkms_tree/$module/$module_version/build" } prepare_kernel_and_signing() { [[ $prepared_kernel = "$kernelver/$arch" ]] && return set_kernel_source_dir_and_kconfig "$kernelver" prepare_kernel "$kernelver" prepare_signing prepared_kernel="$kernelver/$arch" echo "" } do_build() { prepare_kernel_and_signing prepare_and_actual_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 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 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 local any_module_installed local count lib_tree="$install_tree/$kernelver" for ((count=0; count < ${#built_module_name[@]}; count++)); do # 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 local installed_modules local module_count local original_copy m=${dest_module_name[$count]} installed_modules=$(find_module "$lib_tree" "$m") module_count=${#installed_modules[@]} 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 original_module local found_orginal local archive_pref1 local archive_pref2 local archive_pref3 local archive_pref4 original_module="" found_orginal="" archive_pref1=$(compressed_or_uncompressed "$lib_tree/extra" "$m") archive_pref2=$(compressed_or_uncompressed "$lib_tree/updates" "$m") archive_pref3=$(compressed_or_uncompressed "$lib_tree${dest_module_location[$count]}" "$m") archive_pref4="" ((module_count == 1)) && archive_pref4=${installed_modules[0]} for original_module in $archive_pref1 $archive_pref2 $archive_pref3 $archive_pref4; do [[ -f $original_module ]] || continue echo "Found pre-existing $original_module, archiving for uninstallation" mkdir -p "$dkms_tree/$module/original_module/$kernelver/$arch" mv -f "$original_module" "$dkms_tree/$module/original_module/$kernelver/$arch/" found_original="yes" break done if [[ ! $found_original ]] && ((module_count > 1)); then echo "Multiple original modules exist, so none will be put back in place during a later uninstall" echo "All instances will be stored for reference purposes in $dkms_tree/$module/original_module/$kernelver/$arch/collisions/" fi fi if ((module_count > 1)); then echo "Multiple same named modules! $module_count named $m$module_suffix in $lib_tree/" 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}}" 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" done fi # Copy module to its location echo "Installing $install_tree/$kernelver${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix" mkdir -p $install_tree/$kernelver${dest_module_location[$count]} [[ $symlink_modules ]] && symlink="-s" local toinstall 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_add} ]]; then echo "Adding linked weak modules..." list_each_installed_module "$module" "$kernelver" "$arch" | ${weak_modules_add} fi fi # Run the post_install script run_build_script post_install "$post_install" invoke_command "do_depmod $kernelver" "Running 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 ]] && [[ $kernelver = "$(uname -r)" ]]; 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. # Therefore 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 d="$dkms_tree/$1/$2/$3/$4" [[ -d $d/module ]] || return 1 local default_conf 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 real_conf="${conf:-${default_conf}}" read_conf_or_die "$3" "$4" "$real_conf" set_module_suffix "$3" local m for m in "${dest_module_name[@]}"; do local t 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 local k d="$dkms_tree/$1/$2/$3/$4" 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" echo "" 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 for ((i=0; i < ${#kernelver[@]}; i++)); do maybe_build_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}" done } install_module() { local i 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 local count local kernelver local arch local locations module="$1" count="$2" kernelver="$3" arch="$4" 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 local real_dest_module_location was_active="" kernel_symlink=$(readlink -f "$dkms_tree/$module/kernel-$1-$2") 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_remove} ]] && (module_status_built $module $module_version |grep -q "installed"); then echo "Removing linked weak modules..." list_each_installed_module "$module" "$1" "$2" | ${weak_modules_remove} fi fi for ((count=0; count < ${#built_module_name[@]}; count++)); do real_dest_module_location="$(find_actual_dest_module_location $module $count $1 $2)" if [[ ${real_dest_module_location} ]]; then echo "Deleting $install_tree/$1${real_dest_module_location}/${dest_module_name[$count]}$module_suffix" 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 ${dest_module_name[$count]}$module_suffix was not found within $install_tree/$1/" fi local origmod origmod=$(compressed_or_uncompressed "$dkms_tree/$module/original_module/$1/$2" "${dest_module_name[$count]}") if [[ -n $origmod ]]; then echo "Restoring archived original module" mkdir -p "$install_tree/$1${DEST_MODULE_LOCATION[$count]}/" mv -f "$origmod" "$install_tree/$1${DEST_MODULE_LOCATION[$count]}/" 2>/dev/null 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 if [[ ! $delayed_depmod ]]; then invoke_command "do_depmod $1" "Running depmod" '' background else touch $dkms_tree/depmod-pending-$1-$2 fi # Delete the original_module if nothing for this kernel is installed anymore if [[ $was_active && -d $dkms_tree/$module/original_module/$1/$2 ]]; then echo "" echo "Removing original module(s) 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" 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 [[ $i = 0 ]] || echo "" 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 built 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 [[ $i = 0 ]] || echo "" 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 local time_stamp pppid=$(awk '/PPid:/ {print $2}' /proc/$PPID/status) 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]}" echo "" 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 local basename_ko ko="$1" 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 [[ -n $NO_WEAK_MODULES ]] || return 1 [[ $weak_modules_add ]] && [[ $weak_modules_remove ]] || continue local m local v local k local a local kern local weak_ko local mod local installed_ko local f local ret local oifs 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 local m local v local k local a local kern local 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 modules exist)" 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 " (Built modules are missing in the kernel modules folder)" break 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 " (Differences between built and installed modules)" break fi fi done ) # Return a list of all the modules that are either built or installed. # This and list_module_version_combos do some juggling of $IFS to ensure that # we do not get word splitting where it would be inconvenient. module_status_built() { local ret local directory local ka local k local a local state local oifs ret=1 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 a list of all module/version combos known to DKMS. list_module_version_combos() { local ret local modv local directory local oifs ret=1 oifs="$IFS" IFS='' for directory in "$dkms_tree/"${1:-*}/${2:-*}; do IFS="$oifs" [[ -d $directory ]] || continue modv="${directory#$dkms_tree/}" # skip <module>/kernel-<kver>-<karch> -> <modver>/<kver>/<karch> symlinks [[ $modv != */kernel-*-* ]] || continue echo "$modv" ret=0 IFS='' done IFS="$oifs" return $ret } # Return the status of all modules that have been added, built, or installed. module_status() { local ret local m local v ret=1 while IFS='/' read m v; do 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" done < <(list_module_version_combos "$1" "$2") 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 local mvka local m local v local k local a local tmpfile # separate deprecation warnings from status output 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 local 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) make_tarball_rm_temp_dir_name="rm -rf $temp_dir_name" 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 intree_module_dir="$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}" local 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 local tarball_dest tarball_name="$module-$module_version-$kernel_version_list.dkms.tar.gz" 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 eval "$make_tarball_rm_temp_dir_name" unset make_tarball_rm_temp_dir_name } # 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) load_tarball_rm_temp_dir_name="rm -rf $temp_dir_name" 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 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 eval "$load_tarball_rm_temp_dir_name" unset load_tarball_rm_temp_dir_name [[ $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 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" # 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 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 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() { if [[ -f /etc/dkms/no-autoinstall ]]; then echo "Automatic installation of modules has been disabled." return fi local status local mv local mvka local m local v local k local a local progress local 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. module=$m module_version=$v 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 modv in "${to_install[@]}"; do IFS=/ read m v <<< "$modv" if [[ -z ${build_depends[$m]} ]]; then is_module_built "$m" "$v" "$kernelver" "$arch" || prepare_kernel_and_signing echo "Autoinstall of module $m/$v for kernel $kernelver ($arch)" (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 echo "" else next_install[${#next_install[@]}]="$modv" 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 "Autoinstall on $kernelver succeeded for module(s) ${installed_modules[@]}." fi if (( ${#skipped_modules[@]} > 0 )); then echo "Autoinstall on $kernelver was skipped for module(s) ${skipped_modules[@]}." fi if (( ${#failed_modules[@]} > 0 )); then echo "Autoinstall on $kernelver failed for module(s) ${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 } # A wrapper for 'autoinstall', to be used in combination with 'kernel_prerm'. kernel_postinst() { local m local v local failed have_one_kernel kernel_postinst autoinstall } # This is roughly the inverse action to 'autoinstall'. It is supposed to be # called upon removal of a kernel to also remove all modules (including # those with AUTOINSTALL="") that were built or installed for that kernel. # # Compromise on using 'unbuild' to remove the module when a kernel is being # removed. The 'remove' command is too destructive. The 'uninstall' command # leaves built files around that have no other trigger to 'unbuild' them. # (Triggering 'unbuild' on kernel header removal would not be a good idea # because that would also cause the module to be uninstalled for the kernel, # even though only the headers are being removed.) kernel_prerm() { local m local v local failed have_one_kernel kernel_prerm # run depmod only once after uninstalling all dkms modules delayed_depmod=1 while IFS='/' read m v; do is_module_built "$m" "$v" "$kernelver" "$arch" || continue echo "dkms: removing module $m/$v for kernel $kernelver ($arch)" >&2 (module="$m" module_version="$v" unbuild_module) || failed="$failed $m/$v($?)" echo "" done < <(list_module_version_combos) if [[ -f $dkms_tree/depmod-pending-$kernelver-$arch ]]; then rm -f $dkms_tree/depmod-pending-$kernelver-$arch invoke_command "do_depmod $1" "Running depmod" '' background fi delayed_depmod= # clean leftover empty directories [[ ! -d $install_tree/$kernelver ]] || find "$install_tree/$kernelver" -type d -empty -delete [[ -z $failed ]] || die 14 "dkms kernel_prerm for kernel $kernelver ($arch) failed for module(s)$failed." } ############################# #### #### #### 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="/lib/modules" tmp_location=${TMPDIR:-/tmp} verbose="" symlink_modules="" # Set compression defaults compress_gzip_opts="" compress_xz_opts="--check=crc32 --lzma2=dict=1MiB" compress_zstd_opts="-q -T0" # 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}" # 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_add='' weak_modules_remove='' last_mvka='' last_mvka_conf='' try_source_tree='' die_is_fatal="yes" no_depmod="" delayed_depmod="" prepared_kernel="none" action_re='^(remove|(auto|un)?install|match|mktarball|(un)?build|add|status|ldtarball|generate_mok|kernel_(postinst|prerm))$' # 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 "dkms-3.1.5" 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) PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): ' export PS4 set -x ;; -j) read_arg parallel_jobs "$1" "$2" || shift ;; --help|-h) show_usage exit 0 ;; -*) 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 # 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="" # Require explicit --kernelver argument [[ $action =~ kernel_(postinst|prerm) ]] && have_one_kernel "$action" setup_kernels_arches "$action" # Since initramfs/initrd rebuild is not requested, skip it with Redhat's weak-modules if [[ -z $NO_WEAK_MODULES ]]; then case "$running_distribution" in rhel*) weak_modules_add='/usr/sbin/weak-modules --no-initramfs --add-modules' weak_modules_remove='/usr/sbin/weak-modules --no-initramfs --remove-modules' ;; sles* | suse* | opensuse*) weak_modules_add='/usr/lib/module-init-tools/weak-modules2 --add-kernel-modules ${kernelver}' weak_modules_remove='/usr/lib/module-init-tools/weak-modules2 --remove-kernel-modules ${kernelver}' ;; *) ;; esac fi 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) have_one_kernel $action 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 ;; generate_mok) read_framework_conf $dkms_framework_signing_variables prepare_mok ;; kernel_postinst | kernel_prerm) check_root && have_one_kernel "$action" && "$action" ;; *) error "Unknown action specified: \"$action\"" show_usage ;; esac
Free Space : 29883154432 Byte