View file File name : dkms Content :#!/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 readonly dkms_conf_variables="CLEAN REMAKE_INITRD remake_initrd PACKAGE_NAME PACKAGE_VERSION POST_ADD POST_BUILD POST_INSTALL POST_REMOVE PRE_BUILD PRE_INSTALL BUILD_DEPENDS BUILD_EXCLUSIVE_KERNEL BUILD_EXCLUSIVE_ARCH build_exclude OBSOLETE_BY MAKE MAKE_MATCH MODULES_CONF modules_conf_array PATCH PATCH_MATCH patch_array BUILT_MODULE_NAME built_module_name BUILT_MODULE_LOCATION built_module_location DEST_MODULE_NAME dest_module_name MODULES_CONF_OBSOLETES DEST_MODULE_LOCATION dest_module_location modules_conf_obsoletes MODULES_CONF_ALIAS_TYPE modules_conf_alias_type STRIP strip MODULES_CONF_OBSOLETE_ONLY modules_conf_obsolete_only AUTOINSTALL NO_WEAK_MODULES SIGN_TOOL" # Some important regular expressions. Requires bash 3 or above. # Any poor souls still running bash 2 or older really need an upgrade. readonly y_re='^(Y|y)' readonly mv_re='^([^/]*)/(.*)$' readonly rh_kernels='(debug|summit|smp|enterprise|bigmem|hugemem|BOOT|vmnix)' # 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="/lib/modules/$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 = 'background' if you want to run the command asynchronously. local exitval=0 [[ $verbose ]] && echo -e "$1" || echo -en "$2..." if [[ $3 = background && ! $verbose ]]; then local pid progresspid (eval "$1" >/dev/null 2>&1) & pid=$! { on_exit() { kill $(jobs -p) 2>/dev/null wait $(jobs -p) 2>/dev/null } trap on_exit EXIT while [ -d /proc/$pid ]; 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 "$1"; exitval=$? fi (($exitval > 0)) && echo -en "(bad exit status: $exitval)" 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 ) # 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 } 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 | install | uninstall | match | autoinstall | mkdriverdisk |" echo $" mktarball | ldtarball | mkrpm | mkkmp | mkdeb | mkdsc | mkbmdeb | status }" echo $" [options] = [-m module] [-v module-version] [-k kernel-version] [-a arch]" echo $" [-d distro] [-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] [--no-prepare-kernel] [--no-initrd]" echo $" [--binaries-only] [--source-only] [-r release (SuSE)] [--verbose]" echo $" [--size] [--spec=specfile] [--media=floppy|iso|tar] [--legacy-postinst=0|1]" echo $" [--no-depmod] [-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" [[ $(VER $kernel_test) < $(VER 2.5) ]] && module_uncompressed_suffix=".o" grep -q '\.gz:' /lib/modules/$kernel_test/modules.dep 2>/dev/null && module_compressed_suffix=".gz" grep -q '\.xz:' /lib/modules/$kernel_test/modules.dep 2>/dev/null && module_compressed_suffix=".xz" module_suffix="$module_uncompressed_suffix$module_compressed_suffix" } set_kernel_source_dir() { if [[ -z $ksourcedir_fromcli ]]; then # $1 = the kernel to base the directory on kernel_source_dir="$(_get_kernel_dir "$1")" 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 if [[ $all ]]; then die 5 $"The action $1 does not support the --all" \ $"parameter." 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=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") 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) kernels_arches_default="yes" fi if [[ ! $arch ]]; then kernelver_rpm=$(rpm -qf "/lib/modules/$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 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 /boot/System.map-$1 ]]; then depmod -a "$1" -F "/boot/System.map-$1" else depmod -a "$1" fi } # This function is a little hairy -- every distro has slightly different tools # and naming conventions for creating initial ramdisks. It should probably # be split out into one function per distro, with make_initrd left as a stub. make_initrd() { # $1 = kernel version # $2 = arch # $3 = 'backup', if backup of old initrd is wanted (using .old-dkms filename suffix) [[ $no_initrd ]] && return local mkinitrd kernel_file initrd_dir="/boot" for mkinitrd in dracut update-initramfs mkinitrd ''; do [[ $mkinitrd ]] && which "$mkinitrd" >/dev/null 2>&1 && break done # No mkinitrd? Just return. [[ $mkinitrd ]] || return 0 # Back up our current initrd echo $"" # Find out what the proper filename will be for initrd in "initrd-$1.img" "initramfs-$1.img" "initrd.img-$1" "initrd-$1" ''; do [[ $initrd && -f $initrd_dir/$initrd ]] && break done if ! [[ $initrd ]]; then # Return if we cannot find an initrd. warn $"Unable to find an initial ram disk that I know how to handle." \ $"Will not try to make an initrd." return 0 fi if [[ $3 = backup ]]; then echo $"Backing up $initrd to $initrd_dir/$initrd.old-dkms" cp -f "$initrd_dir/$initrd" "$initrd_dir/$initrd.old-dkms" echo $"Making new $initrd" echo $"(If next boot fails, revert to $initrd.old-dkms image)" fi if [[ $mkinitrd = dracut ]]; then invoke_command "$mkinitrd -f $initrd_dir/$initrd $1" "$mkinitrd" background elif [[ $mkinitrd = update-initramfs ]]; then invoke_command "$mkinitrd -u -k $1" "$mkinitrd" background elif $mkinitrd --version >/dev/null 2>&1; then invoke_command "$mkinitrd -f $initrd_dir/$initrd $1" "$mkinitrd" background elif [[ -e /etc/SuSE-release || -d /etc/SuSEconfig ]]; then for kernel_file in vmlinuz vmlinux ''; do [[ $kernel_file && -f $initrd_dir/$kernel_file ]] && break done if [[ ! $kernel_file ]]; then error $"Unable to find valid kernel file under " \ $"$initrd_dir for kernel version $1" return 1; fi invoke_command "$mkinitrd -k $kernel_file-$1 -i $initrd" "$mkinitrd" background elif [[ -e /etc/debian_version ]]; then invoke_command "$mkinitrd -o $initrd_dir/$initrd $1" "$mkinitrd" background else echo $"" echo $"Calling $mkinitrd (bad exit status 9 may occur)" invoke_command "$mkinitrd" "$mkinitrd" background fi return } # Grab our distro information from RPM-based distros. distro_version_rpm() { which rpm > /dev/null 2>&1 || { echo unknown; return; } local r wp ver dist for r in redhat-release sles-release suse-release ovs-release; do wp=$(rpm -q --whatprovides "$r") || continue ver=$(rpm -q --qf "%{version}\n" ${wp}) case $r in sles*) echo sles${ver} ;; suse*) echo suse${ver} ;; ovs*) echo ovm${ver} ;; redhat*) case $wp in redhat*|sl*) ver=$(echo $ver | \ sed -e 's/^\([[:digit:]]*\).*/\1/g') echo el${ver} ;; centos*|enterprise*) echo el${ver} ;; fedora*) echo fc${ver} ;; *) echo unknown ;; esac ;; *) echo unknown ;; esac return done echo unknown } # Grab distro information from LSB compliant distros. # Falls back to distro_version_rpm if needed. distro_version() { # What distribution are we running? local LSB_DESCRIPTION DISTRIB_ID DISTRIB_RELEASE ver # Try the LSB-provided strings first if [ -r /etc/lsb-release ]; then . /etc/lsb-release elif type lsb_release >/dev/null 2>&1; then DISTRIB_ID=$(lsb_release -i -s) DISTRIB_RELEASE=$(lsb_release -r -s) fi case ${DISTRIB_ID} in Fedora) echo fc${DISTRIB_RELEASE} ;; RedHatEnterprise*|CentOS|ScientificSL) # OEL also reports as such; format is 4.7, 5.3 ver=$(echo "${DISTRIB_RELEASE}" | \ sed -e 's/^\([[:digit:]]*\).*/\1/g') echo el${ver} ;; SUSE*) if [[ $(lsb_release -d -s) =~ Enterprise ]]; then echo sles${DISTRIB_RELEASE} else echo suse${DISTRIB_RELEASE} fi ;; *) if [[ ${DISTRIB_ID} && ${DISTRIB_RELEASE} ]]; then echo "${DISTRIB_ID}${DISTRIB_RELEASE}" else distro_version_rpm fi ;; esac } 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 sles[123456789]) ;; suse[123456789]) ;; suse10\.[01]) ;; fc*) echo "/extra" && return ;; el*) echo "/extra" && return ;; ovm*) echo "/extra" && return ;; sles*) echo "/updates" && return ;; suse*) echo "/updates" && return ;; Ubuntu*) echo "/updates/dkms" && return ;; Debian*) 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 deliberatly 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" } # 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 installtion 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 "$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" sign_tool="$SIGN_TOOL" # 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]} modules_conf_obsoletes[$index]=${MODULES_CONF_OBSOLETES[$index]} modules_conf_alias_type[$index]=${MODULES_CONF_ALIAS_TYPE[$index]} case ${MODULES_CONF_OBSOLETE_ONLY[$index]} in [yY]*) modules_conf_obsolete_only[$index]="yes" ;; esac 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]} ]] && \ ((${#DEST_MODULE_LOCATION[@]} == 1)) && \ built_module_name[$index]=$module [[ ! ${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 kernels 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 # 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 if [[ $(VER $1) < $(VER 2.6.6) ]]; then [[ ! $make_command ]] && make_command="make -C $kernel_source_dir SUBDIRS=$dkms_tree/$module/$module_version/build modules" [[ ! $clean ]] && clean="make -C $kernel_source_dir SUBDIRS=$dkms_tree/$module/$module_version/build clean" else [[ ! $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" fi # Set modules_conf_array for ((index=0; index < ${#MODULES_CONF[@]}; index++)); do [[ ${MODULES_CONF[$index]} ]] && modules_conf_array[$index]="${MODULES_CONF[$index]}" done # 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 remake_initrd [[ $REMAKE_INITRD =~ $y_re ]] && remake_initrd="yes" # Set build_exclude [[ $BUILD_EXCLUSIVE_KERNEL && ! $1 =~ $BUILD_EXCLUSIVE_KERNEL ]] && build_exclude="yes" [[ $BUILD_EXCLUSIVE_ARCH && ! $2 =~ $BUILD_EXCLUSIVE_ARCH ]] && build_exclude="yes" # Fail if absolutely no DEST_MODULE_LOCATION if ((${#dest_module_location[@]} == 0)); then echo $"dkms.conf: Error! No 'DEST_MODULE_LOCATION' directive specified." >&2 return_value=1 fi # 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 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 } # Little helper function for parsing the output of modinfo. get_module_verinfo(){ res=("" "" "") local vals= while read -a vals; do case ${vals[0]} in version:) res[0]=${vals[1]} res[2]=${vals[2]} ;; srcversion:) res[1]=${vals[1]} ;; esac done < <(modinfo $1) } # Perform some module version sanity checking whenever we are installing # or removing 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 local -a kernels_info dkms_info 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 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}") get_module_verinfo $kernels_module; kernels_info=("${res[@]}") get_module_verinfo $dkms_module; dkms_info=("${res[@]}") if [[ ! ${dkms_info[1]} && ${kernels_info[1]} ]]; then # Use obsolete checksum info dkms_info[1]=${dkms_info[2]} kernels_info[1]=${kernels_info[2]} fi if [[ ${kernels_info[1]} && ${dkms_info[1]} && ${kernels_info[1]} = ${dkms_info[1]} && -n "${kernels_info[0]}" && -n "${dkms_info[0]}" && ${kernels_info[0]} = ${dkms_info[0]} && ! $force ]]; then echo $"" >&2 echo $"Good news! Module version $dkms_info 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 if [[ $kernels_info && $dkms_info && ! ( $(VER $dkms_info) > $(VER $kernels_info) ) && ! $force ]]; then error $"Module version $dkms_info for ${4}$module_suffix" \ $"is not newer than what is already found in kernel $1 ($kernels_info)." \ $"You may override by specifying --force." return 1 fi return 0 } moduleconfig_update_obsoletes() { # $@ = files to process # Do nothing if we have no obsoletes ( IFS=; [[ "${modules_conf_obsoletes[*]}" ]] ) || return 0 # Generate sed args to remove obsolete modules local mod_diff for ((index=0; index < ${#dest_module_name[@]}; index++)); do [[ ${modules_conf_obsoletes[$index]} ]] || continue for obsolete_module in ${modules_conf_obsoletes[$index]//,/ }; do # For module.conf style syntax sa_mc_o[${#sa_mc_o[*]}]="-e" sa_mc_o[${#sa_mc_o[*]}]="s/\(alias ${modules_conf_alias_type[$index]}[0-9]*\) $obsolete_module$/\1 ${dest_module_name[$index]}/g" # For /etc/sysconfig/kernel style syntax sa_sck_o[${#sa_sck_o[*]}]="-e" sa_sck_o[${#sa_sck_o[*]}]="s/\(INITRD_MODULES.*\)$obsolete_module\b\(.*\)/\1${dest_module_name[$index]}\2/" done done # Do all the changes at once, record the diffs for posterity for file in "$@"; do [[ $file && -w $file ]] || continue _tmpf="$temp_dir_name/${file##*/}.new" if [[ $file = /etc/sysconfig/kernel ]]; then [ -z "${sa_sck_o[@]}" ] || sed "${sa_sck_o[@]}" "$file" > "$_tmpf" else [ -z "${sa_mc_o[@]}" ] || sed "${sa_mc_o[@]}" "$file" > "$_tmpf" fi if [ -f "$_tmpf" ] && ! mod_diff=$(diff -u "$_tmpf" "$file"); then echo $"$file updated to replace obsoleted module references:" echo "$mod_diff" cp -fp "$_tmpf" "$file" rm -f "$_tmpf" fi done } moduleconfig_add() { # $1 = kernel version local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) local -a sa_mc_o=() sa_sck_o=() modconfig_files="/etc/modprobe.d/dkms.conf /etc/modprobe.d/dkms /etc/modules.conf /etc/modprobe.conf /etc/modprobe.d/$package_name.conf /etc/sysconfig/kernel" moduleconfig_update_obsoletes $modconfig_files for moduleconfig in $modconfig_files; do [[ -e $moduleconfig ]] || continue for ((index=0; index < ${#dest_module_name[@]}; index++)); do # Only add it if it can't be found already in config file if [[ ${modules_conf_alias_type[$index]} ]] && \ ! grep -qs "alias ${modules_conf_alias_type[$index]}[0-9]* ${dest_module_name[$index]}\b" $moduleconfig && \ [[ ${modules_conf_obsolete_only[$index]} != yes ]]; then if [[ $modconfig_files = /etc/modprobe.d/$package_name.conf ]] && [[ ! -e /etc/modprobe.d/$package_name.conf ]]; then touch /etc/modprobe.d/$package_name.conf echo $"created /etc/modprobe.d/$package_name.conf.">&2 fi aliases=$(awk "/^alias ${modules_conf_alias_type[$index]}/ {print \$2}" $moduleconfig) if [[ $aliases ]]; then alias_number=$(($(echo "$aliases" | sed "s/${modules_conf_alias_type[$index]}//" | sort -n | tail -n 1) + 1)) else alias_number=0 fi echo -e "alias ${modules_conf_alias_type[$index]}${alias_number} ${dest_module_name[$index]}" >> $moduleconfig echo $"$moduleconfig: added alias reference for '${dest_module_name[$index]}'" fi done # Add anything else for ((index=0; index < ${#modules_conf_array[@]}; index++)); do if [ -n "${modules_conf_array[$index]}" ] && \ ! grep -q "${modules_conf_array[$index]}" "$moduleconfig"; then echo -e $"$moduleconfig: added '${modules_conf_array[$index]}'" echo -e "${modules_conf_array[$index]}" >> $moduleconfig fi done done # Delete the temp dir rm -rf $temp_dir_name } moduleconfig_remove() { # $1 = kernel version local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) modconfig_files="" [ -e /etc/modprobe.d/dkms.conf ] && modconfig_files="/etc/modprobe.d/dkms.conf" [ -e /etc/modprobe.d/dkms ] && modconfig_files="/etc/modprobe.d/dkms" [ -e /etc/modules.conf ] && modconfig_files="$modconfig_files /etc/modules.conf" [ -e /etc/modprobe.conf ] && modconfig_files="$modconfig_files /etc/modprobe.conf" [ -e /etc/modprobe.d/$package_name.conf ] && modconfig_files="/etc/modprobe.d/$package_name.conf" for moduleconfig in $modconfig_files; do for ((index=0; index < ${#dest_module_name[@]}; index++)); do # Remove/Replace aliases (maybe) [[ ${modules_conf_alias_type[$index]} ]] || continue find "$install_tree/$1/" -name "${dest_module_name[$index]}.*" -quit 2>/dev/null && continue local conf_replacement="" for obsolete_module in ${modules_conf_obsoletes[$index]//,/ }; do find $install_tree/$1/ -name "$obsolete_module.*" -quit 2>/dev/null || continue conf_replacement=$obsolete_module break done if [[ ! $conf_replacement ]]; then grep -v "alias ${modules_conf_alias_type[$index]}[0-9]* ${dest_module_name[$index]}" $moduleconfig > $temp_dir_name/moduleconfig.new mv -f $temp_dir_name/moduleconfig.new $moduleconfig echo $"$moduleconfig: removed alias for '${dest_module_name[$index]}'" if [[ $modconfig_files = /etc/modprobe.d/$package_name.conf ]]; then rm -f /etc/modprobe.d/$package_name.conf echo $"$moduleconfig: deleted /etc/modprobe.d/$package_name.conf file" fi elif grep -q "alias ${modules_conf_alias_type[$index]}[0-9]* ${dest_module_name[$index]}$" $moduleconfig; then sed "s/\(alias ${modules_conf_alias_type[$index]}[0-9]*\) ${dest_module_name[$index]}$/\1 $conf_replacement/g" \ $moduleconfig > $temp_dir_name/moduleconfig.new mv -f $temp_dir_name/moduleconfig.new $moduleconfig echo $"$moduleconfig: alias for '${dest_module_name[$index]}' changed back to '$conf_replacement'" fi done # Remove static conf entries for ((index=0; index < ${#modules_conf_array[@]}; index++)); do [[ ${modules_conf_array[$index]} ]] || continue grep -v "${modules_conf_array[$index]}" "$moduleconfig" > $temp_dir_name/moduleconfig.new echo $"$moduleconfig: removed '${modules_conf_array[$index]}'" mv -f $temp_dir_name/moduleconfig.new $moduleconfig done done # Delete the temp dir rm -rf $temp_dir_name } etc_sysconfig_kernel_modify() ( [[ -e /etc/sysconfig/kernel && $remake_initrd ]] || return 0 # Make a temp directory to store files local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) if [[ $1 = add ]]; then . /etc/sysconfig/kernel for m in "${dest_module_name[@]}"; do for l in "${INITRD_MODULES}"; do [[ $m = $l ]] && continue 2 done sed -e "s/INITRD_MODULES=\"\(.*\)\"/INITRD_MODULES=\"\1 $m\"/" /etc/sysconfig/kernel > $temp_dir_name/kernel.new mv $temp_dir_name/kernel.new /etc/sysconfig/kernel done # Remove /etc/sysconfig/kernel entries elif [[ $1 = delete ]]; then for m in "${dest_module_name[@]}"; do sed -e "s/\(INITRD_MODULES.*\)$m\b\(.*\)/\1\2/" /etc/sysconfig/kernel > $temp_dir_name/kernel.new mv $temp_dir_name/kernel.new /etc/sysconfig/kernel done fi # Delete the temp dir rm -rf $temp_dir_name ) check_module_args() { [[ $module && $module_version ]] && return die 1 $"Invalid number of arguments passed." \ $"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: $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 } run_sign_tool() { # $1 = sign tool to run # $2 = module file to sign local logfile="$base_dir/log/make.log" if [[ -x "$1" ]]; then echo "Signing $2" >> "$logfile" "$1" "$kernelver" "$2" || \ report_build_problem 11 $"Bad exit status $? for sign tool." \ $"Consult $logfile for more information." else echo $"" warn $"The $1 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 # 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 # 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 the conf file for sanity read_conf_or_die "$kernelver" "$arch" "$conf" # Create the necessary dkms tree structure echo $"" echo $"Creating symlink $dkms_tree/$module/$module_version/source ->" echo $" $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" echo $"" echo $"DKMS: add completed." } # 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 "$1" # Check that kernel-source exists _check_kernel_dir "$1" || { case "$running_distribution" in Debian* | Ubuntu* ) die 1 $"Your kernel headers for kernel $1 cannot be found." \ $"Please install the linux-headers-$1 package," \ $"or use the --kernelsourcedir option to tell DKMS where it's located" ;; * ) die 1 echo $"Your kernel headers for kernel $1 cannot be found at" \ $"/lib/modules/$1/build or /lib/modules/$1/source." \ $"You can use the --kernelsourcedir option to tell DKMS where it's located." ;; esac } [[ $no_prepare_kernel ]] && return if [[ (! ( $(VER $1) < $(VER 2.6.5) ) || -d /etc/SuSEconfig) && \ -d "$kernel_source_dir" && \ -z "$ksourcedir_fromcli" ]]; then echo $"" echo $"Kernel preparation unnecessary for this kernel. Skipping..." no_clean_kernel="no-clean-kernel" return 1 fi # Prepare kernel for module build echo $"" echo $"Preparing kernel $1 for module build:" echo $"(This is not compiling a kernel, just preparing kernel symbols)" cd $kernel_source_dir [[ -r .config ]] && { config_contents=$(cat .config) echo $"Storing current .config to be restored when complete" } # Set kernel_config if [[ -e /etc/redhat-release || -e /etc/fedora-release ]]; then # Note this also applies to VMware 3.x if [[ -z $kernel_config && -d $kernel_source_dir/configs ]]; then local kernel_trunc=${1%%-*} # Try a .config specific to whatever kernel we are running if [[ $1 =~ $rh_kernels && -e $kernel_source_dir/configs/kernel-$kernel_trunc-$2-${BASH_REMATCH[1]}.config ]]; then kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$2-${BASH_REMATCH[1]}.config" elif [[ -e $kernel_source_dir/configs/kernel-$kernel_trunc-$2.config ]]; then # If that one does not exist, try a generic one. kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$2.config" else # If that does not exist, fall back to no config file kernel_config="" fi fi elif [[ (-e /etc/SuSE-release || -d /etc/SuSEconfig) && -z $kernel_config && -d $kernel_source_dir/arch ]]; then local kernel_trunc=${1%%-*} case $2 in i586|i686) config_arch="i386" ;; *) config_arch=$2 ;; esac for config_type in default smp bigsmp; do [[ $1 =~ $config_type ]] && kernel_config="$kernel_source_dir/arch/$config_arch/defconfig.$config_type" [[ -e $kernel_config ]] || kernel_config="" done [[ $kernel_config ]] || kernel_config="$kernel_source_dir/arch/$config_arch/defconfig.default" [[ -e $kernel_config ]] || kernel_config="" fi # Do preparation if [ -e /boot/vmlinuz.version.h ]; then echo $"Running UnitedLinux preparation routine" local kernel_config="/boot/vmlinuz.config" invoke_command "make mrproper" "make mrproper" background [[ $config_contents ]] && echo "$config_contents" > .config invoke_command "cp /boot/vmlinuz.version.h include/linux/version.h" "using /boot/vmlinux.version.h" invoke_command "cp -f $kernel_config .config" "using $kernel_config" invoke_command "make KERNELRELEASE=$1 cloneconfig" "make cloneconfig" background invoke_command "make -j$parallel_jobs CONFIG_MODVERSIONS=1 KERNELRELEASE=$1 dep" "make CONFIG_MODVERSIONS=1 dep" background elif grep -q rhconfig.h $kernel_source_dir/include/linux/{modversions,version}.h 2>/dev/null; then echo $"Running Red Hat style preparation routine" invoke_command "make clean" "make clean" background [[ $config_contents ]] && echo "$config_contents" > .config if [[ $kernel_config ]]; then echo $"using $kernel_config" cp -f "$kernel_config" .config elif [[ -e .config ]]; then warn $"Using $kernel_source_dir/.config" \ $"(I hope this is the correct config for this kernel)" else warn $"Cannot find a .config file to prepare your kernel with." \ $"Try using the --config option to specify where one can be found." \ $"Your build will likely fail because of this." fi # Hack to workaround broken tmp_include_depends for Red Hat if grep -q "/usr/src/build" $kernel_source_dir/tmp_include_depends 2>/dev/null; then sed 's/\/usr\/src\/build\/.*\/install//g' $kernel_source_dir/tmp_include_depends > $kernel_source_dir/tmp_include_depends.new mv -f $kernel_source_dir/tmp_include_depends.new $kernel_source_dir/tmp_include_depends fi invoke_command "make KERNELRELEASE=$1 oldconfig" "make oldconfig" background kerneldoth_contents=$(cat /boot/kernel.h 2>/dev/null) invoke_command "/usr/lib/dkms/mkkerneldoth --kernelver $1 --targetarch $2 --output /boot/kernel.h" "running mkkerneldoth" background else echo $"Running Generic preparation routine" invoke_command "make mrproper" "make mrproper" background [[ $config_contents ]] && echo "$config_contents" > .config if [[ $kernel_config ]]; then echo $"using $kernel_config" cp -f "$kernel_config" .config elif [[ -e .config ]]; then warn $"using $kernel_source_dir/.config" \ $"(I hope this is the correct config for this kernel)" else warn $"Warning! Cannot find a .config file to prepare your kernel with." \ $"Try using the --config option to specify where one can be found." \ $"Your build will likely fail because of this." fi invoke_command "make KERNELRELEASE=$1 oldconfig" "make oldconfig" background if [[ $(VER $1) < $(VER 2.5) ]]; then invoke_command "make -j$parallel_jobs KERNELRELEASE=$1 dep" "make dep" background else invoke_command "make -j$parallel_jobs KERNELRELEASE=$1 prepare-all scripts" "make prepare-all" background fi fi cd - >/dev/null } # 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 set_kernel_source_dir "$kernelver" local base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch" # Check that the right arguments were passed check_module_args build # 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 ]] && die 9 \ $" The $base_dir/dkms.conf for module $module includes a BUILD_EXCLUSIVE directive which" \ $"does not match this kernel/arch. This indicates that it should not be built." # Error out if source_tree is basically empty (binary-only dkms tarball w/ --force check) (($(ls $dkms_tree/$module/$module_version/source | wc -l | awk {'print $1'}) < 2)) && die 8 \ $"The directory $dkms_tree/$module/$module_version/source/" \ $"does not appear to have module source located within it. Build halted." prepare_kernel "$kernelver" "$arch" # Set up temporary build directory for build rm -rf "$dkms_tree/$module/$module_version/build" cp -a "$dkms_tree/$module/$module_version/source/" "$dkms_tree/$module/$module_version/build" cd "$dkms_tree/$module/$module_version/build" # Apply any patches for p in "${patch_array[@]}"; do [[ ! -e $dkms_tree/$module/$module_version/build/patches/$p ]] && \ report_build_problem 5 \ $" Patch $p as specified in dkms.conf cannot be" \ $"found in $dkms_tree/$module/$module_version/build/patches/." invoke_command "patch -p1 < ./patches/$p" "applying patch $p" || \ report_build_problem 6 $"Application of patch $p failed." \ $"Check $dkms_tree/$module/$module_version/build/ for more information." done # 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. do_build() { local base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch" echo $"" echo $"Building module:" invoke_command "$clean" "cleaning build area" background echo $"DKMS make.log for $module-$module_version for kernel $kernelver ($arch)" >> "$dkms_tree/$module/$module_version/build/make.log" date >> "$dkms_tree/$module/$module_version/build/make.log" local the_make_command="${make_command/#make/make -j$parallel_jobs KERNELRELEASE=$kernelver}" invoke_command "{ $the_make_command; } >> $dkms_tree/$module/$module_version/build/make.log 2>&1" "$the_make_command" background || \ report_build_problem 10 $"Bad return status for module build on kernel: $kernelver ($arch)" \ $"Consult $dkms_tree/$module/$module_version/build/make.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)" \ $"Consult the make.log in the build directory" \ $"$dkms_tree/$module/$module_version/build/ 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 "$dkms_tree/$module/$module_version/build/make.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 [[ ${strip[$count]} != no ]] && strip -g "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_uncompressed_suffix" if [ -n "${sign_tool}" ]; then run_sign_tool "${sign_tool}" "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_uncompressed_suffix" fi if [ "$module_compressed_suffix" = ".gz" ]; then gzip -9f "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_uncompressed_suffix" elif [ "$module_compressed_suffix" = ".xz" ]; then xz -f "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_uncompressed_suffix" fi cp -f "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_suffix" \ "$base_dir/module/${dest_module_name[$count]}$module_suffix" >/dev/null 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 if [[ ! ( $(VER $kernelver) < $(VER 2.6.6) ) && \ -d $kernel_source_dir && \ ! -h $kernel_source_dir && \ ! $ksourcedir_fromcli ]]; then echo $"Kernel cleanup unnecessary for this kernel. Skipping..." elif [[ ! $no_clean_kernel ]]; then cd "$kernel_source_dir" [[ $kerneldoth_contents ]] || invoke_command "make mrproper" "cleaning kernel tree (make mrproper)" background [[ $config_contents ]] || echo "$config_contents" > .config [[ $kerneldoth_contents ]] && echo "$kerneldoth_contents" > /boot/kernel.h cd - >/dev/null fi # Clean the build directory rm -rf "$dkms_tree/$module/$module_version/build" } sign_build() { [[ -x "$(command -v kmodsign)" && -d "/var/lib/shim-signed/mok/" ]] || return local base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch" if type update-secureboot-policy >/dev/null 2>&1; then echo $"Signing module:" SHIM_NOTRIGGER=y update-secureboot-policy --new-key for ko in `find "$base_dir/module/" -name "*.ko" -print`; do echo " - $ko" kmodsign sha512 \ /var/lib/shim-signed/mok/MOK.priv \ /var/lib/shim-signed/mok/MOK.der \ "$ko" done update-secureboot-policy --enroll-key fi } build_module() { prepare_build do_build sign_build clean_build echo $"" echo $"DKMS: build completed." } # 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. install_module() { # If the module has not been built, try to build it first. is_module_built "$module" "$module_version" "$kernelver" "$arch" || build_module local base_dir="$dkms_tree/$module/$module_version/$kernelver/$arch" check_module_args install # 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 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" | grep -v "$lib_tree/kernel/") 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##*/}" done # 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" # Make modules.conf changes as necessary echo $"" moduleconfig_add "$kernelver" etc_sysconfig_kernel_modify "add" invoke_command "do_depmod $kernelver" "depmod" background || { do_uninstall "$kernelver" "$arch" die 6 $"Problems with depmod detected. Automatically uninstalling this module." \ $"DKMS: Install Failed (depmod problems). Module rolled back to built state." exit 6 } # Do remake_initrd things (save old initrd) [[ $remake_initrd ]] && ! make_initrd "$kernelver" "$arch" backup && { do_uninstall "$kernelver" "$arch" die 7 $"Problems with mkinitrd detected. Automatically uninstalling this module." \ $"DKMS: Install Failed (mkinitrd problems). Module rolled back to built state." } echo $"" echo $"DKMS: install completed." # 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 } 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 ]]; } 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" && { echo $"Module $1/$2 already built for kernel $3/4" return 0 } module="$1" module_version="$2" kernelver="$3" arch="$4" build_module ) maybe_install_module() ( is_module_installed "$1" "$2" "$3" "$4" && { echo $"Module $1/$2 already installed on kernel $3/$4" return 0 } module="$1" module_version="$2" kernelver="$3" arch="$4" install_module ) build_modules() { local i=0 for ((i=0; i < ${#kernelver[@]}; i++)); do maybe_build_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}" done } install_modules() { local i=0 for ((i=0; i < ${#kernelver[@]}; i++)); do maybe_install_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}" done } check_module_exists() { is_module_added "$module" "$module_version" && return die 2 $"DKMS tree does not contain: $module-$module_version" \ $"Build cannot continue without the proper tree." } 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}" ]] && diff "${dkms_owned}" "${installed}" > /dev/null 2>&1; 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 $"" echo $"-------- Uninstall Beginning --------" echo $"Module: $module" echo $"Version: $module_version" echo $"Kernel: $1 ($2)" echo $"-------------------------------------" 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 $"" echo $"Status: 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" 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 (cd "$install_tree/$1" && rmdir -p --ignore-fail-on-non-empty "${dir_to_remove}" || true) 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." # Remove modules_conf entries from /etc/modules.conf if remake_initrd is set or if this is last instance removed if [[ $remake_initrd ]] || (do_status $module $module_version | grep -q "installed"); then echo $"" moduleconfig_remove "$1" fi fi done rm -f "$dkms_tree/$module/kernel-$1-$2" else echo $"" echo $"Status: 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 /lib/modules invoke_command "do_depmod $1" "depmod" background # Do remake_initrd things (remake initrd) if [[ $remake_initrd && $was_active ]] && ! make_initrd "$1" "$2" ''; then warn $"There was a problem remaking your initrd. You must manually remake it" \ $"before booting into this kernel." fi # 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" # Re-add entries to modules.conf if this module/version is still installed on another kernel # But only do this if it was just ACTIVE on the kernel we just uninstalled from [[ $was_active && $remake_initrd ]] && do_status $module $module_version | grep -q "installed" && moduleconfig_add "$1" echo $"" echo $"DKMS: uninstall completed." } # Check our preconditions, and then let do_install do all the hard work. uninstall_module() { # Check that the right arguments were passed check_module_args uninstall # Check that $module is in the dkms tree [[ -d $dkms_tree/$module ]] || die 2 \ $"There are no instances of module: $module" \ $"located in the DKMS tree." # Make sure that its installed in the first place [[ -d $dkms_tree/$module/$module_version ]] || die 3 \ $"The module/version combo: $module-$module_version" \ $"is not located in the DKMS tree." # Read the conf file read_conf_or_die "$kernelver" "$arch" # Only do stuff if module/module version is currently installed local kernel_symlink=$(readlink -f "$dkms_tree/$module/kernel-$kernelver-$arch") [[ $kernel_symlink = $dkms_tree/$module/$module_version/$kernelver/$arch ]] || die 5 \ $"The module $module $module_version is not currently installed." \ $"This module is not currently ACTIVE for kernel $kernelver ($arch)." do_uninstall "$kernelver" "$arch" } # Unregister a DKMS module. This uninstalls any installed modules along the way. remove_module() { # Check that the right arguments were passed if [[ ! ($module && $module_version) || $kernels_arches_default ]]; then die 1 $"Invalid number of parameters passed." \ $"Usage: remove <module>/<module-version> --all" \ $" or: remove <module>/<module-version> -k <kernel-version>" fi # Check that $module is in the dkms tree if ! [[ -d $dkms_tree/$module/$module_version ]]; then die 3 $"There are no instances of module: $module" \ $"$module_version located in the DKMS tree." fi local i for ((i=0; i < ${#kernelver[@]}; i++)); do # Make sure its there first before removing if ! [[ -d $dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]} ]]; then die 4 $"There is no instance of $module $module_version" \ $"for kernel ${kernelver[$i]} (${arch[$i]}) located in the DKMS tree." fi # 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 $"DKMS: Remove cancelled because --rpm_safe_upgrade scenario detected." done fi # Read the conf file read_conf_or_die "${kernelver[$i]}" "${arch[$i]}" do_uninstall "${kernelver[$i]}" "${arch[$i]}" # Delete the $kernel_version/$arch_used part of the tree rm -rf "$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}" [[ $(find $dkms_tree/$module/$module_version/${kernelver[$i]}/* -maxdepth 0 -type d 2>/dev/null) ]] || \ rm -rf "$dkms_tree/$module/$module_version/${kernelver[$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 | egrep -qv "(build|tarball|driver_disk|rpm|deb|source)$"; then echo $"" echo $"------------------------------" echo $"Deleting module version: $module_version" echo $"completely from the DKMS tree." echo $"------------------------------" rm -rf "$dkms_tree/$module/$module_version" echo $"Done." 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 # Its now safe to completely remove references in /etc/sysconfig/kernel for SuSE etc_sysconfig_kernel_modify "delete" 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" [[ -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 inconvienent. 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_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 while read status mvka; do IFS=/ read m v k a <<< "$mvka" case $status in 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 < <(module_status "$@") } # 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 } create_temporary_trees() { [[ $module || $module_version || ! -r dkms.conf ]] && return 0 . dkms.conf module="$PACKAGE_NAME" module_version="$PACKAGE_VERSION" source_tree=$(mktemp_or_die -d) dkms_tree=$(mktemp_or_die -d) local source_tree_dir="$source_tree/$PACKAGE_NAME-$PACKAGE_VERSION" mkdir -p "$source_tree_dir" cp -a * "$source_tree_dir" # intentionally skip .git or .hg add_module temporary_trees_del_command="rm -rf $source_tree $dkms_tree" } delete_temporary_trees() { [[ $temporary_trees_del_command ]] || return 0 $temporary_trees_del_command module= module_version= source_tree= dkms_tree= temporary_trees_del_command= } in_temporary_trees() { [[ $temporary_trees_del_command ]] } media_valid() { local mrx='^(floppy|iso|tar)$' [[ $media =~ $mrx ]] } make_driver_disk_floppy() { local image_name="$1" local source_dir="$2" local file local fs='ext2' [[ $distro = redhat* ]] && fs='vfat' rm -f "$image_name" invoke_command "dd if=/dev/zero of=$image_name bs=$(($size/20))k count=20" "making a blank floppy image" background case $fs in vfat) invoke_command "mkdosfs $image_name" "mkdosfs" background ;; ext2) invoke_command "mke2fs -F $image_name" "mke2fs" background ;; esac local mntdir=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) invoke_command "mount -o loop -t $fs $image_name $mntdir >/dev/null 2>&1" "loopback mounting disk image" [[ -d $mntdir/lost+found ]] && rmdir "$mntdir/lost+found" invoke_command "cp -r $source_dir/* $mntdir/" " copying files to floppy disk image" invoke_command "umount $mntdir" "unmounting disk image" rm -rf "$mntdir" } make_driver_disk_isotar() { local type="$1" local image_name="$2" local source_dir="$3" local file case $type in iso) invoke_command "mkisofs -v -r -J -pad -V $module -o $image_name ." "mkisofs" background ;; tar) invoke_command "tar cvf $image_name ." "tar" background ;; esac } make_driver_disk_media() { echo "Copying files $2" case $media in floppy*) make_driver_disk_floppy "$1" "$2" ;; iso*) make_driver_disk_isotar "iso" "$1" "$2" ;; tar*) make_driver_disk_isotar "tar" "$1" "$2" ;; esac } driver_disk_suffix() { case $media in floppy*) echo "img" ;; iso*) echo "iso" ;; tar*) echo "tar" ;; esac } make_driver_disk() { # Check that the right arguments were passed if ! [[ $module && $module_version && $distro && $kernelver ]]; then die 1 $"Invalid number of parameters passed." \ $"Usage: mkdriverdisk <module>/<module-version> -d <distro> -k <kernelver> [--media floppy|iso|tar]" fi # Default to floppy media [[ $media ]] || media="floppy" if ! media_valid; then die 1 $"Media $media is invalid." \ $"Usage: mkdriverdisk <module>/<module-version> -d <distro> -k <kernelver> [--media floppy|iso|tar]" fi # Check that source symlink works check_module_exists # Confirm that distro is supported case $distro in redhat3 | suse | UnitedLinux | ubuntu) ;; *) die 3 $"Invalid distro argument. Currently, the distros" \ $"supported are: redhat3, suse, UnitedLinux, ubuntu" ;; esac # Read the conf file read_conf_or_die "$kernelver" "$arch" case $distro in redhat*) make_redhat3_driver_disk ;; ubuntu) make_ubuntu_driver_disk ;; *) make_suse_driver_disk ;; esac } find_external_dependencies() { local mod count i local -a deps # Find all module dependencies for ((count=0; count < ${#dest_module_name[@]}; count++)); do for ((i=0; i < ${#kernelver[@]}; i++)); do set_module_suffix "${kernelver[$i]}" mod="$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}/module/${dest_module_name[$count]}$module_suffix" deps=(${deps[@]} $(modinfo "$mod" | sed -n 's/,/ /g; s/^depends: *//p')) done done # Prune internally satisfied dependencies for ((i=0; i < ${#deps[@]}; i++)); do for mod in ${dest_module_name[@]}; do [[ ${deps[i]} = $mod ]] && deps[i]= done done for dep in "${deps[@]}"; do echo $dep done | sort -u } make_suse_driver_disk() { [[ $release ]] || die 3 \ $"Invalid number of parameters passed for suse/UnitedLinux driver disk." \ $"Usage: mkdriverdisk <module>/<module-version> -d <distro> -k <kernelver>" \ $" -r <release-number>" local driver_disk_dir=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) local suffix="$(driver_disk_suffix)" local image_dir="$dkms_tree/$module/$module_version/driver_disk" local image_name="$module-$module_version-$distro-$release-dd.$suffix" echo $"" echo $"Creating driver disk:" local deps="$(find_external_dependencies)" local offset=0 # reserve a place for dependencies [[ ${deps[@]} ]] && offset=1 local count for ((count=0; count < ${#dest_module_name[@]}; count++)); do local i local topdir=$(printf "%02d" $(($count+1+offset))) for ((i=0; i < ${#kernelver[@]}; i++)); do set_module_suffix "${kernelver[$i]}" local srcdir=$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}/module local srcpath=$(compressed_or_uncompressed "$srcdir" "${dest_module_name[$count]}") if ! [[ -n "$srcpath" ]]; then rm -rf $temp_dir_name die 5 \ $"Cannot find module ${dest_module_name[$count]}$module_suffix for kernel ${kernelver[$i]} (${arch[$i]})." \ $"Module/version must be in built state before making a driver disk." fi # FIXME: add check for KMP binary RPMs to include in the driver disk suse_arch=${arch[$i]} case $suse_arch in i?86) suse_arch=i386 ;; esac echo "Marking ${kernelver[$i]}/${arch[$i]}/modules/${dest_module_name[$count]}$module_suffix..." mkdir -p "$driver_disk_dir/$topdir/$suse_arch-$release/install/lib/modules/${kernelver[$i]}${dest_module_location[$count]}" cp "$srcpath" "$driver_disk_dir/$topdir/$suse_arch-$release/install/lib/modules/${kernelver[$i]}${dest_module_location[$count]}/" case ${kernelver[$i]} in *-default) mkdir -p "$driver_disk_dir/$topdir/$suse_arch-$release/modules/" cp "$srcpath" "$driver_disk_dir/$topdir/$suse_arch-$release/modules/" ;; esac # Create directory for dependency information [[ ${deps[@]} ]] && mkdir -p "$driver_disk_dir/01/linux/$distro/$suse_arch-$release/modules" done # --- for arch_release in $(find $driver_disk_dir/$topdir -maxdepth 1 -mindepth 1 -type d | sed "s#$driver_disk_dir\/$topdir\/##"); do cd "$driver_disk_dir/$topdir/$arch_release/install/" invoke_command "tar cvzf update.tar.gz lib/" "making update.tar.gz for $arch_release" background cd - >/dev/null mkdir -p "$driver_disk_dir/$topdir/linux/$distro/$arch_release/install" mkdir -p "$driver_disk_dir/$topdir/linux/$distro/$arch_release/modules" echo $" copying update.tar.gz for $arch_release to disk image..." cp -f "$driver_disk_dir/$topdir/$arch_release/install/update.tar.gz" "$driver_disk_dir/$topdir/linux/$distro/$arch_release/install/" postkernels= archtest=${arch_release/-*} for ((i=0; i<${#kernelver[@]}; i++)); do [[ ${arch[$i]} = ${archtest} ]] && postkernels="${postkernels} ${kernelver[$i]}" done if [[ ${postkernels} ]]; then dstfile="$driver_disk_dir/$topdir/linux/$distro/$arch_release/install/update.post" echo $" creating update.post for $arch_release..." (cat << EOF #!/bin/sh kernlist="${postkernels}" for kernel in \${kernlist}; do if [ -e /boot/System.map-\${kernel} ]; then depmod -a -F /boot/System.map-\${kernel} \${kernel} fi done EOF ) > ${dstfile} chmod a+x ${dstfile} fi if [[ -d $driver_disk_dir/$topdir/$arch_release/modules/ ]]; then echo $" copying kernel modules for installation kernel to disk image..." cp -f $driver_disk_dir/$topdir/$arch_release/modules/* $driver_disk_dir/$topdir/linux/$distro/$arch_release/modules/ 2>/dev/null else warn $"No kernel modules found for -default kernel." fi rm -fr "$driver_disk_dir/$topdir/$arch_release" done done local dir if [[ ${deps[@]} ]]; then for dir in "$driver_disk_dir/01/linux/$distro/"*"/modules"; do for dep in "${deps[@]}"; do echo $dep >> "$dir/module.order" done done fi # FIXME: add suse-equivalent rpms/ directory, copy in KMP RPMs, run createrepo --pretty mkdir -p "$image_dir" rm -f "$image_dir/$image_name" cd "$driver_disk_dir" make_driver_disk_media "$image_dir/$image_name" "$driver_disk_dir" cd - >/dev/null rm -rf "$driver_disk_dir" echo $"" echo $"Disk image location: $dkms_tree/$module/$module_version/driver_disk/$image_name" echo $"" echo $"DKMS: mkdriverdisk completed." } make_ubuntu_driver_disk() { local suffix="$(driver_disk_suffix)" local image_dir="$dkms_tree/$module/$module_version/driver_disk" local image_name="$module-$module_version-$distro-dd.$suffix" local tempdir=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) # Check that the dh_make command is present if ! which dpkg-deb >/dev/null 2>&1 ; then die 1 $"dpkg-deb not present." \ $"Install the dpkg-dev package." fi local i for ((i=0; i < ${#kernelver[@]}; i++)); do set_module_suffix "${kernelver[$i]}" # Driver disks only recognize i386 as package arch local karch=${arch[$i]/i?86/i386} local kvers=${kernelver[$i]/-/_}; kvers=${kvers%%_*} # ubuntu-drivers/<kver>/*_<debarch>.deb local dd_prefix="ubuntu-drivers/$kvers" local dd_suffix="_${karch}.deb" maybe_build_module "$module" "$module_version" "${kernelver[$i]}" "${arch[$i]}" || { rm -rf "$tempdir" die 5 $"Unable to build $module/$module_version for Ubuntu driver disk." } mkdir -p "$tempdir/$dd_prefix" local deb_dir="$tempdir/$dd_prefix/debian" local deb_lib_dir="$deb_dir/lib/modules/${kernelver[$i]}/updates/dkms" mkdir -p "$deb_lib_dir" cp "$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}/module/"*"$module_uncompressed_suffix"* "$deb_lib_dir" pushd "$deb_dir" > /dev/null 2>&1 mkdir DEBIAN cat > DEBIAN/control <<EOF Package: ${module}-modules-${kernelver[$i]} Version: ${module_version}-1 Section: misc Priority: optional Architecture: $karch Depends: Maintainer: DKMS <dkms-devel@dell.com> Description: DKMS packaged binary driver update DKMS automagically generated debian package for driver update disks, used with Ubuntu installation programs (such as Ubiquity). EOF # Generate the DEBIAN/preinst file. # This is tricky as we need some parts evaluated now # and some parts evaluated at runtime cat >DEBIAN/preinst <<EOF #!/bin/bash [[ \$(uname -r) = ${kernelver[$i]} ]] || exit 1 exit 0 EOF chmod 0775 DEBIAN/preinst cd "$tempdir/$dd_prefix" dpkg-deb --build debian mv debian.deb "${module}_${module_version}-${kernelver[$i]}${dd_suffix}" rm -rf debian popd > /dev/null 2>&1 done echo "Copying source..." mkdir -p "$tempdir/ubuntu" cp -ar "$source_tree/$module-$module_version" "$tempdir/ubuntu/" mkdir -p "$image_dir" rm -f "$image_dir/$image_name" cd "$tempdir" make_driver_disk_media "$image_dir/$image_name" "$tempdir" cd - >/dev/null rm -rf "$tempdir" echo $"" echo $"Disk image location: $dkms_tree/$module/$module_version/driver_disk/$image_name" echo $"" echo $"DKMS: mkdriverdisk completed." } make_tarball() { make_common_test "mktarball" # Check for dkms_dbversion if ! [[ -e $dkms_tree/dkms_dbversion ]]; then echo $"" >&2 echo $"Could not find the file $dkms_tree/dkms_dbversion." >&2 echo $"Creating w/ default contents." >&2 echo "2.0.0" > $dkms_tree/dkms_dbversion fi # Read the conf file read_conf_or_die "$kernelver" "$arch" temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) 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 if ! [[ -d $dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]} ]]; then rm -rf "$temp_dir_name" 2>/dev/null 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_dir_name/dkms_main_tree/${kernelver[$i]}/${arch[$i]}" cp -rf "$dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]}" "$temp_dir_name/dkms_main_tree/${kernelver[$i]}" done fi # Store the dkms_dbversion in the tarball cp -f "$dkms_tree/dkms_dbversion" "$temp_dir_name/dkms_main_tree/" # Copy the source_tree or make special binaries-only structure if [[ $binaries_only ]]; then echo $"" echo $"Creating tarball structure to specifically accomodate binaries." mkdir $temp_dir_name/dkms_binaries_only echo "$module" > $temp_dir_name/dkms_binaries_only/PACKAGE_NAME echo "$module_version" > $temp_dir_name/dkms_binaries_only/PACKAGE_VERSION [[ ! $conf ]] && conf="$dkms_tree/$module/$module_version/source/dkms.conf" cp -f $conf $temp_dir_name/dkms_binaries_only/ 2>/dev/null else echo $"" echo $"Marking $dkms_tree/$module/$module_version/source for archiving..." mkdir -p $temp_dir_name/dkms_source_tree cp -rf $dkms_tree/$module/$module_version/source/* $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/" # Die if we will not be able to create the tarball due to permissions. if [[ $archive_location ]]; then tarball_name="${archive_location##*/}" if [[ ${archive_location%/*} != $archive_location && \ -d ${archive_location%/*} && -w ${archive_location%/*} ]]; then tarball_dest="${archive_location%/*}" elif [[ ${archive_location%/*} != $archive_location ]] && ! mkdir -p $tarball_dest; then die 9 $"Will not be able to create $archive_location due to a permissions problem." fi fi if [ ! -d $tarball_dest ]; then mkdir -p "$dkms_tree/$module/$module_version/tarball/" fi echo $"" echo $"Tarball location: $tarball_dest/$tarball_name" local tarball_ext=${tarball_name##*.} [[ $tarball_ext = tar ]] || tarball_name=${tarball_name%.$tarball_ext} # Make the tarball cd $temp_dir_name if tar -cf $temp_dir_name/$tarball_name ./* 2>/dev/null; then cd - >/dev/null echo $"" mv -f "$temp_dir_name/$tarball_name" "$tarball_dest/$tarball_name" rm -rf $temp_dir_name else cd - >/dev/null rm -rf $temp_dir_name die 6 $"Failed to make tarball." fi case $tarball_ext in gz) gzip -f -9 "$tarball_dest/$tarball_name" ;; bz2) bzip2 -f -9 "$tarball_dest/$tarball_name" ;; xz) xz -f -9 "$tarball_dest/$tarball_name" ;; esac echo $"" echo $"DKMS: mktarball completed." } # 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 # Figure out what kind of archive it is (tar.gz, tar, tar.bz, tar.xz, etc) # Note that this does not depend on the extensions being correct. local tar_options="" for xpand in gzip bzip xz; do $xpand -t $archive_location 2>/dev/null || continue case $xpand in gzip) tar_options=z ;; bzip2) tar_options=j ;; xz) tar_options=J ;; esac break done # Untar it into $tmp_location local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) trap 'rm -rf $temp_dir_name' EXIT tar -${tar_options}xf $archive_location -C $temp_dir_name if [[ ! $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 rm -rf $temp_dir_name 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 # Check that dkms_dbversion is not a future version # As far as I can tell, the only reason we bother with this is for detecting # whether we have arch support or not, which we can also determine by examining # the structure of the tarball. db_from_tarball=$(cat $temp_dir_name/dkms_main_tree/dkms_dbversion 2>/dev/null) db_from_dkms=$(cat $dkms_tree/dkms_dbversion 2>/dev/null) if [[ $db_from_tarball && $db_from_dkms && $(VER "$db_from_tarball") > $(VER "$db_from_dkms") ]]; then die 9 \ $"The tarball you are trying to load indicates it is database version" \ $"$db_from_tarball. This version of DKMS only supports $db_from_dkms or lower." 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 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 echo $"Creating $dkms_tree/$module/$module_version/source" mkdir -p "$dkms_tree/$module/$module_version/source" echo $"Copying dkms.conf to $dkms_tree/$module/$module_version/source..." cp -rf "$temp_dir_name/dkms_binaries_only/dkms.conf" "$dkms_tree/$module/$module_version/source" fi ;; *) die 8 $"$FUNCNAME:$LINENO: Cannot happen." \ $"Report this error to dkms-devel@dell.com";; esac break done # 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. # Is tarball from before DKMS 2.0 (prior to arch support) if [[ ! -e $temp_dir_name/dkms_main_tree/dkms_dbversion ]]; then [[ $loc = dkms_binaries_only ]] && rm -rf "$dkms_tree/$module/$module_version/source" die 10 $" This tarball was created with dkms < 2.0 and contains" \ $"no arch info. DKMS is refusing to install precompiled modules." fi # Load precompiled modules. for directory in "$temp_dir_name/dkms_main_tree"/*/*; do [[ -d $directory ]] || continue kernel_arch_to_load=${directory/*dkms_main_tree\/} 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 echo $"" echo $"DKMS: ldtarball completed." [[ $loc != dkms_binaries_only ]] || [[ -d $source_tree/$module-$module_version ]] } run_match() { set_kernel_source_dir "$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." else 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 $"" echo $"---- Match Beginning ----" echo $"Module: $template_module" echo $"Version: $template_version" echo $"-------------------------" # Figure out what to do from here if show_status "$template_module" "$template_version" "$kernelver" "$arch" 2>/dev/null | grep -q ": installed"; then echo $"" echo $"This module/version combo is already installed. Nothing to be done." elif show_status "$template_module" "$template_version" "$kernelver" "$arch" 2>/dev/null | grep -q ": built"; then echo $"" echo $"This module/version combo is built. Installing it:" module="$template_module" module_version="$template_version" install_module else echo $"" echo $"Building & Installing this module/version:" module="$template_module" module_version="$template_version" build_module install_module fi done < <(echo "$template_kernel_status") # Clean up the kernel tree if [[ ! ( $(VER $kernelver) < $(VER 2.6.6) ) && -d "$kernel_source_dir" && ! -h "$kernel_source_dir" && -z "$ksourcedir_fromcli" ]]; then echo $"Kernel cleanup unnecessary for this kernel. Skipping..." elif [[ ! $no_clean_kernel ]]; then cd "$kernel_source_dir" [[ $kerneldoth_contents ]] || invoke_command "make mrproper" "cleaning kernel tree (make mrproper)" background [[ $config_contents ]] && echo "$config_contents" > .config [[ $kerneldoth_contents ]] && echo "$kerneldoth_contents" > /boot/kernel.h cd - >/dev/null fi fi # Done echo $"" echo $"DKMS: match completed." } make_rpm() { make_common_test "mkrpm" # Check that the rpmbuild command is present if ! which rpmbuild >/dev/null 2>&1 ; then die 1 $"rpmbuild not present." \ $"Install the rpm-build package." fi # Read the conf file read_conf_or_die "$kernelver" "$arch" local rpm_basedir="$dkms_tree/$module/$module_version/rpm" echo $"" local sp for sp in "$dkms_tree/$module/$module_version/source/$module-dkms-mkrpm.spec" "/etc/dkms/template-dkms-mkrpm.spec"; do [[ -e $sp ]] || continue SPECFILE="$sp" break done if [[ ! $SPECFILE ]]; then die 5 $"Cannot find $sp which is needed by" \ $"DKMS in order use mkrpm." fi # Run a dkms mktarball for use in the rpm local mktarball_line if [[ ! $source_only || $binaries_only ]]; then mktarball_line="--binaries-only" local i echo $"" for ((i=0; i<${#kernelver[@]}; i++)); do if ! [[ -d $dkms_tree/$module/$module_version/${kernelver[$i]}/${arch[$i]} ]]; then die 5 $"You do not seem to have $module $module_version built for" \ $"${kernelver[$i]} (${arch[$i]}). All modules must be in" \ $"the built state before you can use mkrpm." fi echo $"Marking ${kernelver[$i]} (${arch[$i]}) for RPM..." mktarball_line="-k ${kernelver[$i]} -a ${arch[$i]} $mktarball_line" done else mktarball_line="none" fi local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) trap 'rm -rf $temp_dir_name' EXIT HUP TERM mkdir -p ${temp_dir_name}/{BUILD,RPMS,SRPMS,SPECS,SOURCES} cp ${SPECFILE} ${temp_dir_name}/SPECS/dkms_mkrpm.spec # If using legacy mode, install common postinst if ((legacy_postinst != 0)); then invoke_command "cp '$PREFIX/usr/lib/dkms/common.postinst' '${temp_dir_name}/SOURCES'" "copying legacy postinstall template" fi # Copy in the source tree if [[ ! $binaries_only ]]; then invoke_command "cp -Lpr '$dkms_tree/$module/$module_version/source' '${temp_dir_name}/SOURCES/$module-$module_version'" "Copying source tree" fi if invoke_command "LC_ALL=C rpmbuild --define \"_topdir ${temp_dir_name}\" --define \"version $module_version\" --define \"module_name $module\" --define \"kernel_versions ${kernelver[*]}\" --define \"mktarball_line $mktarball_line\" --define \"__find_provides /usr/lib/dkms/find-provides\" --define \"_use_internal_dependency_generator 0\" -ba ${temp_dir_name}/SPECS/dkms_mkrpm.spec > ${temp_dir_name}/rpmbuild.log 2>&1" "rpmbuild"; then mkdir -p ${rpm_basedir} cp -a ${temp_dir_name}/SRPMS/* ${temp_dir_name}/RPMS/*/* ${rpm_basedir}/ echo $"" cat ${temp_dir_name}/rpmbuild.log | grep ^Wrote | sed -e "s:${temp_dir_name}/:${rpm_basedir}/:" -e 's:SRPMS/::' -e 's:RPMS/.*/::' echo $"" echo $"DKMS: mkrpm completed." else cat ${temp_dir_name}/rpmbuild.log >&2 die 7 $"There was a problem creating your rpm." fi rm -rf $temp_dir_name trap > /dev/null 2>&1 } preproc_file() { local date_str="$(date -R)" echo "modifying $1..." sed -e "s/DEBIAN_PACKAGE/$debian_package/g" \ -e "s/DEBIAN_BUILD_ARCH/$debian_build_arch/g" \ -e "s/KERNEL_VERSION/$kernelver/g" \ -e "s/MODULE_NAME/$module/g" \ -e "s/MODULE_VERSION/$module_version/g" \ -e "s/DATE_STAMP/$date_str/" "$1" > "$1.dkms-pp" mv "$1.dkms-pp" "$1" } # Install a package on a debian system. debian_install() { local getroot tmpfile i local -a packages=("$@") for ((i=0; i < ${#packages[@]}; i++)); do dpkg-query -s "${packages[$i]}"| egrep -q '^Status:.* installed$' || continue unset package[$i] done # if they are already installed, we are OK. [[ ${package[@]} ]] || return if ((UID != 0)); then # figure out how to get root for getroot in su-to-root gksudo kdesu sudo; do which $getroot >/dev/null 2>&1 || continue case $getroot in su-to-root) getroot="$getroot -c" ;; gksudo) [[ $DISPLAY ]] || continue getroot="$getroot --description 'DKMS Debian package builder' " ;; kdesu) [[ $DISPLAY ]] || continue ;; esac break done fi if [[ -x /usr/sbin/synaptic && $DISPLAY ]] && tmpfile=$(mktemp_or_die); then # Pretty GUI install. trap 'rm -f "$tmpfile"' EXIT for ((i=0; i=${#packages[@]}; i++)); do [[ ${packages[$i]} ]] && echo "install ${packages[$i]}" >>$tmpfile done $getroot "sh -c '/usr/sbin/synaptic --set-selections --non-interactive --hide-main-window < $tmpfile'" else $getroot apt-get -y install "${packages[@]}" fi if (( $? != 0)); then die 4 $"Missing ${packages[@]}" \ $"and unable to install. Please ask an admin to install for you." fi } make_debian() { create_type="$1" create_temporary_trees trap "delete_temporary_trees" EXIT HUP TERM make_common_test "mk${create_type}" debian_package=${module//_/-} if [[ $source_only ]]; then debian_build_arch='all' else debian_build_arch=$(dpkg-architecture -qDEB_BUILD_ARCH) fi # Read the conf file read_conf_or_die "$kernelver" "$arch" debian_install fakeroot dpkg-dev debhelper # Skeleton to load templates from local system_mk="$dkms_tree/$module/$module_version/source/$module-dkms-mk${create_type}" local local_mk="/etc/dkms/template-dkms-mk${create_type}" if [[ -e ${system_mk} ]]; then echo $"Using ${system_mk}" DEBDIR=${system_mk} elif [[ -e ${local_mk} ]]; then echo $"Using ${local_mk}" DEBDIR=${local_mk} else die 5 $"Cannot find ${local_mk} which is needed by" \ $"DKMS in order to use mk${create_type}." fi # Prepare build directory and copy template local temp_dir=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) trap "rm -rf $temp_dir; delete_temporary_trees" EXIT HUP TERM local temp_dir_debian="$temp_dir/$debian_package-dkms-$module_version" invoke_command "cp -ar '$DEBDIR/' '$temp_dir_debian'" "copying template" pushd "$temp_dir_debian" > /dev/null 2>&1 for file in debian/*; do preproc_file "$file" chmod 755 "$file" done popd > /dev/null 2>&1 # If using legacy mode, install common postinst if ((legacy_postinst != 0)); then invoke_command "cp '$PREFIX/usr/lib/dkms/common.postinst' '$temp_dir_debian'" "copying legacy postinstall template" fi # Calculate destination directory deb_basedir=$dkms_tree/$module/$module_version/${create_type} mkdir -p ${deb_basedir} >/dev/null 2>&1 # Create deb pushd "$temp_dir_debian" > /dev/null 2>&1 case "$create_type" in dsc) invoke_command "cp -Lpr '$dkms_tree/$module/$module_version/source' '$temp_dir_debian/$module-$module_version'" "Copying source tree" invoke_command "dpkg-buildpackage -S -us -uc 1>/dev/null" "Building source package" || \ die 7 $"There was a problem creating your ${create_type}." echo $"" echo $"DKMS: mk${create_type} completed." invoke_command "mv '$temp_dir/${debian_package}-dkms_${module_version}_source.changes' '$temp_dir/${debian_package}-dkms_${module_version}.dsc' '$temp_dir/${debian_package}-dkms_${module_version}.tar.gz' '$deb_basedir'" "Moving built files to $deb_basedir" ;; deb) invoke_command "cp -Lpr '$dkms_tree/$module/$module_version/source' '$temp_dir_debian/$module-$module_version'" "Copying source tree" invoke_command "dpkg-buildpackage -rfakeroot -d -b -us -uc 1>/dev/null" "Building binary package" || \ die 7 $"There was a problem creating your ${create_type}." echo $"" echo $"DKMS: mk${create_type} completed." invoke_command "mv '$temp_dir/${debian_package}-dkms_${module_version}_${debian_build_arch}.deb' '$deb_basedir'" "Moving built files to $deb_basedir" ;; bmdeb) local archive_location="$dkms_tree/$module/$module_version/tarball/$module-$module_version.dkms.tar.gz" # Force binaries_only binaries_only="binaries-only" invoke_command "make_tarball" "Gathering binaries" if [[ -f $archive_location ]]; then invoke_command "cp '$archive_location' '$temp_dir_debian'" "Copying DKMS tarball into DKMS tree" else die 12 $"Unable to find created tarball." fi export KVER="$kernelver" export KARCH="$arch" invoke_command "dpkg-buildpackage -rfakeroot -d -b -us -uc 1>/dev/null" "Building binary package" || \ die 7 $"There was a problem creating your ${create_type}." echo $"" echo $"DKMS: mk${create_type} completed." invoke_command "mv '$temp_dir/${debian_package}-modules-${kernelver}_${module_version}_${debian_build_arch}.deb' '$deb_basedir'" "Moving built files to $deb_basedir" ;; esac popd > /dev/null 2>&1 if in_temporary_trees; then echo "Copying built files to "`pwd`"/.." >&2 cp "${deb_basedir}/"* .. fi # Cleanup invoke_command "rm $temp_dir -fr" "Cleaning up temporary files" delete_temporary_trees || \ die 7 $"There was a problem cleaning up temporary files." } make_common_test() { local create_type=$1 # Error if $module_version is set but $module is not check_module_args $create_type # Check that source symlink works check_module_exists # Make sure that its installed in the first place [[ -d $dkms_tree/$module/$module_version ]] || die 3 $"The module/version combo: $module-$module_version" \ $"is not located in the DKMS tree." } make_kmp_srpm() { local temp_dir_name=$(mktemp_or_die -d $tmp_location/dkms.XXXXXX) trap 'rm -rf $temp_dir_name' EXIT HUP TERM mkdir -p $temp_dir_name/{BUILD,RPMS,SRPMS,SPECS,SOURCES} pushd "$dkms_tree/$module/$module_version" > /dev/null 2>&1 # Want to change name of the top-level of the tarball from build to $module-$module_version cp -lr build ${module}-${module_version} tar cvjf $temp_dir_name/SOURCES/${module}-${module_version}.tar.bz2 ${module}-${module_version} > /dev/null 2>&1 rm -rf ${module}-${module_version} popd > /dev/null 2>&1 pushd "$temp_dir_name" > /dev/null 2>&1 invoke_command "rpmbuild --define \"_topdir ${temp_dir_name}\" --target=$arch -bs ${SPECFILE} > ${temp_dir_name}/rpmbuild.log 2>&1" "rpmbuild" grep ^Wrote $temp_dir_name/rpmbuild.log > /dev/null 2>&1 local RC="$?" if ((RC == 0)); then local kmp_basedir="$dkms_tree/$module/$module_version/rpm" mkdir -p $kmp_basedir RPMS=$(LANG=C cp -va ${temp_dir_name}/SRPMS/* $kmp_basedir | awk '{print $NF}') else echo $"rpmbuild error log:" cat $temp_dir_name/rpmbuild.log fi popd > /dev/null 2>&1 rm -rf $temp_dir_name trap > /dev/null 2>&1 return ${RC} } 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 convienent 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() { ((UID == 0)) && return die 1 $"You must be root to use this command." } # 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" } make_kmp() { make_common_test "mkkmp" # Read the conf file read_conf_or_die "$kernelver" "$arch" echo $"" if [[ $specfile && -e $dkms_tree/$module/$module_version/source/$specfile ]]; then echo $"Using $dkms_tree/$module/$module_version/source/$specfile" SPECFILE="$dkms_tree/$module/$module_version/source/$specfile" elif [[ -e $dkms_tree/$module/$module_version/source/$module-kmp.spec ]]; then echo $"Using $dkms_tree/$module/$module_version/source/$module-kmp.spec" SPECFILE="$dkms_tree/$module/$module_version/source/$module-kmp.spec" else die 5 $"Cannot find a suitable spec file which is needed by" \ $"DKMS in order use mkkmp. Please specify --spec=specfile." fi prepare_build make_kmp_srpm RC=$? clean_build if ((RC == 0)); then echo $"" echo $"KMP SRPM location: $RPMS" echo $"" echo $"DKMS: mkkmp completed." else die 7 $"There was a problem creating your KMP source rpm." fi # FIXME: hand SRPM to mock or build system to build } # 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 last_v last_m tenative local install_count next_depends local -a to_install=() local -a next_install=() local -a installed_modules=() local -A build_depends=() # Walk through our list of installed and built modules, and create # a list of modules that need to be reinstalled. # Assuming all versions of same module to be parsed sequentially. while read status mvka; do IFS='/' read m v k a <<< "$mvka" [[ ! $last_m ]] && last_m="$m" # autoinstall previous module's latest version after its deps. if [[ $last_m != $m ]]; then if [[ $tenative ]]; then to_install[${#to_install[@]}]="$tenative" build_depends["$last_m"]="${BUILD_DEPENDS[@]}" fi last_m="$m" last_v='0' tenative='' fi # 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 "$k" "$a" "$dkms_tree/$m/$v/source/dkms.conf" if [[ ! $AUTOINSTALL ]]; then continue fi # otherwise, only autoinstall the latest version we have hanging around. if [[ ($(VER $v) > $(VER $last_v)) ]]; then last_v="$v" tenative="$m/$v" fi done < <(module_status) # We may have exited the loop with $tenative set. If it is, # it contains something that should be updated. if [[ $tenative ]]; then to_install[${#to_install[@]}]="$tenative" build_depends["$m"]="${BUILD_DEPENDS[@]}" fi [[ $to_install ]] || return 0 while true; do install_count=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[@]}; 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"; install_module) installed_modules[${#installed_modules[@]}]="$m" install_count=$(($install_count +1)) else next_install[${#next_install[@]}]="$mv" fi done wait # Step 3: Keep going if at least one module was installed during # this iteration. [[ "$install_count" -gt 0 ]] || break; # Step 4: Remove modules that were installed during Step 2 from # the job queue. to_install=( "${next_install[@]}" ) done for mv in "${to_install[@]}"; do IFS=/ read m v <<< "$mv" echo "$m/$v autoinstall failed due to missing dependencies: ${build_depends[$m]}" done } make_redhat3_driver_disk () { # Check that the rpmbuild command is present if ! which rpmbuild >/dev/null 2>&1 ; then echo $"" >&2 echo $"Error! rpmbuild not present." >&2 echo $"Install the rpm-build package." >&2 exit 1 fi local kmodtool=$(rpm -ql redhat-rpm-config | grep kmodtool) #Check that the kmodtool is present if [ -z "$kmodtool" ]; then echo $"Error! kmodtool not present." >&2 echo $"Install redhat-rpm-config package." >&2 exit 1 fi # Check that the createrepo command is present if ! which createrepo >/dev/null 2>&1 ; then echo $"" >&2 echo $"Error! createrepo not present." >&2 echo $"Install the createrepo package." >&2 exit 1 fi echo $"" if [ -n "$specfile" -a -e "$dkms_tree/$module/$module_version/source/$specfile" ]; then echo $"Using $dkms_tree/$module/$module_version/source/$specfile" SPECFILE="$dkms_tree/$module/$module_version/source/$specfile" elif [ -e "/etc/dkms/template-dkms-redhat-kmod.spec" ]; then echo $"Using /etc/dkms/template-dkms-redhat-kmod.spec" SPECFILE="/etc/dkms/template-dkms-redhat-kmod.spec" else echo $"" >&2 echo $"Cannot find /etc/dkms/template-dkms-redhat-kmod.spec which is needed by" >&2 echo $"DKMS in order to make Redhat driver disk v3." >&2 exit 5 fi # Set up temporary build directory for build rm -rf "$dkms_tree/$module/$module_version/build" cp -a "$dkms_tree/$module/$module_version/source/" "$dkms_tree/$module/$module_version/build" cd "$dkms_tree/$module/$module_version/build" # Run the pre_build script if [ -n "$pre_build" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$pre_build" | sed 's/ .*//'` ]; then echo $"" echo $"Running the pre_build script:" $dkms_tree/$module/$module_version/build/$pre_build fi # Apply any patches local index=0 while [ $index -lt ${#patch_array[@]} ]; do if ! [ -e "$dkms_tree/$module/$module_version/build/patches/${patch_array[$index]}" ]; then echo $"" >&2 echo $"Error! Patch ${patch_array[$index]} as specified in dkms.conf cannot be" >&2 echo $"found in $dkms_tree/$module/$module_version/build/patches/." >&2 exit 5 fi invoke_command "patch -p1 < ./patches/${patch_array[$index]}" "applying patch ${patch_array[$index]}" if [ "$?" -ne 0 ]; then echo $"" >&2 echo $"Error! Application of patch ${patch_array[$index]} failed." >&2 echo $"Check $dkms_tree/$module/$module_version/build/ for more information." >&2 report_build_problem exit 6 fi index=$(($index+1)) done # Create temp dirs and copy files for build local temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX` trap 'rm -rf $temp_dir_name' EXIT HUP TERM mkdir -p ${temp_dir_name}/{disk,BUILD,RPMS,SRPMS,SPECS,SOURCES} cp ${SPECFILE} ${temp_dir_name}/SPECS/$module.spec cp -rax $dkms_tree/$module/$module_version/build/ $temp_dir_name/SOURCES/$module-$module_version/ # Clean the build directory rm -rf "$dkms_tree/$module/$module_version/build" cd $temp_dir_name/SOURCES invoke_command "tar -jcvf $temp_dir_name/SOURCES/$module-$module_version.tar.bz2 $module-$module_version/" "creating source tarball" local i=0 # Build RPMS while [ $i -lt ${#kernelver[@]} ]; do invoke_command "LC_ALL=C rpmbuild --define \"_topdir ${temp_dir_name}\" --define \"version $module_version\" --define \"module_name $module\" --define \"kernel_version ${kernelver[$i]}\" -bb --target ${arch[$i]} ${temp_dir_name}/SPECS/$module.spec > ${temp_dir_name}/rpmbuild.log 2>&1" "rpmbuild" if [ "$?" -ne 0 ]; then echo $"" >&2 echo $"Error! There was a problem creating your kmod." >&2 cat ${temp_dir_name}/rpmbuild.log >&2 exit 7 fi local kabi_whitelist=`rpm -ql kabi-whitelists | grep ${arch[$i]}` if [ $kabi_whitelist ]; then local module_file=`rpm -qlp ${temp_dir_name}/RPMS/${arch[$i]}/kmod-${module}-${module_version}* | grep ${module}.ko` cd ${temp_dir_name}/ rpm2cpio ${temp_dir_name}/RPMS/${arch[$i]}/kmod-${module}-${module_version}* | cpio -id --quiet .${module_file} cd - > /dev/null local mod_symbols=( $(modprobe --dump-modversions ${temp_dir_name}/${module_file} | cut -f2) ) local miss_sym_count=0 local missing_symbols for ((i=0; i < "${#mod_symbols[@]}"; i++)) do if [ -z "`grep -o ${mod_symbols[${i}]} ${kabi_whitelist}`" ]; then missing_symbols[$miss_sym_count]="${mod_symbols[${i}]}" miss_sym_count=$(($miss_sym_count+1)) fi done if [ $miss_sym_count -ne 0 ]; then echo $"" >&2 echo $"WARNING: ${module}-${module_version} is using following kernel symbols that are not in the ABI whitelist:" echo $"----------------------------------" for missing_symbol in ${missing_symbols[*]} do echo "$missing_symbol" done echo $"----------------------------------" echo $"" >&2 else echo $"NOTICE: ${module}-${module_version} module seems to use only official Red Hat ABI." fi else echo $"WARNING:${module}-${module_version} module is not checked against Red Hat ABI whitelist." echo $"Install 'kabi-whitelists' package and build driver disk again to run the ABI compliance test." fi i=$(($i + 1)) done i=0 while [ $i -lt ${#arch[@]} ]; do invoke_command "createrepo --pretty ${temp_dir_name}/RPMS/${arch[$i]}" "creating repo" if [ "$?" -ne 0 ]; then echo $"" >&2 echo $"Error! There was a problem creating repository." >&2 exit 7 fi i=$(($i + 1)) done echo "$module-$module_version driver disk" > "${temp_dir_name}/disk/rhdd3" mkdir ${temp_dir_name}/disk/rpms cp -rax ${temp_dir_name}/RPMS/* ${temp_dir_name}/disk/rpms/ local suffix="$(driver_disk_suffix)" local image_dir="$dkms_tree/$module/$module_version/driver_disk" local image_name="$module-$module_version-dd.$suffix" echo $"" echo $"Creating driver disk on $media media:" cd "${temp_dir_name}/disk" mkdir -p "$image_dir" rm -f "$image_dir/$image_name" make_driver_disk_media "$image_dir/$image_name" "${temp_dir_name}/disk" rm -rf $temp_dir_name echo $"" echo $"Disk image location: $image_dir/$image_name" echo $"" echo $"DKMS: mkdriverdisk completed." trap > /dev/null 2>&1 } ############################# #### #### #### Program Starts Here #### #### #### ############################# # Set a standard path PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/lib/dkms" # 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) dkms_tree="/var/lib/dkms" source_tree="/usr/src" install_tree="/lib/modules" tmp_location=${TMPDIR:-/tmp} verbose="" symlink_modules="" dkms_frameworkconf="/etc/dkms/framework.conf" # 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}" [[ ! ${addon_modules_dir} ]] && running_distribution="$(distro_version)" weak_modules="${WEAK_MODULES_BIN}" # Source in /etc/dkms_framework.conf [ -e $dkms_frameworkconf ] && . $dkms_frameworkconf 2>/dev/null # Clear out command line argument variables module="" module_version="" template_kernel="" distro="" media="" release="" conf="" kernel_config="" archive_location="" kernel_source_dir="" ksourcedir_fromcli="" action="" force="" force_version_override="" no_prepare_kernel="" no_clean_kernel="" binaries_only="" source_only="" all="" module_suffix="" module_uncompressed_suffix="" module_compressed_suffix="" rpm_safe_upgrade="" size="1440"; specfile="" legacy_postinst="1" 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|mk(driverdisk|tarball|rpm|deb|bmdeb|dsc|kmp)|build|add|status|ldtarball)$' # Parse command line arguments while (($# > 0)); do case $1 in --dkmsframework*) read_arg dkms_frameworkconf "$1" "$2" || shift #immediately load this config . $dkms_frameworkconf 2> /dev/null ;; --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" ;; --distro*|-d) read_arg distro "$1" "$2" || shift ;; --media*) read_arg media "$1" "$2" ||shift ;; --release*|-r) read_arg release "$1" "$2" || shift ;; --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:2.8" exit 0 ;; --no-prepare-kernel) no_prepare_kernel="no-prepare-kernel" ;; --no-clean-kernel) no_clean_kernel="no-clean-kernel" ;; --no-initrd) no_initrd="no-initrd" ;; --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 ;; --archive*) read_arg archive_location "$1" "$2" || shift ;; --legacy-postinst*) read_arg legacy_postinst "$1" "$2" || shift ;; --arch*|-a) read_arg _aa "$1" "$2" || shift arch[${#arch[@]}]="$_aa" ;; --size*) read_arg size "$1" "$2" || shift ;; --kernelsourcedir*) read_arg kernel_source_dir "$1" "$2" || shift ksourcedir_fromcli="true" ;; --directive*) read_arg _da "$1" "$2" || shift directive_array[${#directive_array[@]}]="$_da" ;; --spec*) read_arg specfile "$1" "$2" || shift ;; --no-depmod) no_depmod="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="$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 # 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 # If initramfs/initrd rebuild is not requested, skip it with Redhat's weak-modules if [[ $no_initrd && $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="" # Run the specified action if [ -z "$action" ]; then show_usage die 4 $"No action was specified." fi for action_to_run in $action; do setup_kernels_arches "$action_to_run" case "$action_to_run" in remove) check_root && remove_module ;; install) check_root && install_modules ;; autoinstall) check_root && autoinstall ;; match) check_root && have_one_kernel && run_match ;; uninstall) check_root && have_one_kernel && uninstall_module ;; mkdriverdisk) check_root && make_driver_disk ;; build) build_modules ;; add) add_module ;; mktarball) make_tarball ;; mkrpm) make_rpm ;; mkdeb) make_debian "deb" ;; mkbmdeb) make_debian "bmdeb" ;; mkdsc) make_debian "dsc" ;; mkkmp) have_one_kernel && make_kmp ;; status) show_status ;; ldtarball) # Make sure they're root if we're using --force if ((UID != 0)) && [[ $force = true ]]; then die 1 $"You must be root to use this command with the --force option." fi load_tarball && add_module ;; '') error $"No action was specified." show_usage ;; *) error $"Unknown action specified: $action_to_run" show_usage ;; esac done