Permalink
Fetching contributors…
Cannot retrieve contributors at this time
3822 lines (3420 sloc) 138 KB
#!/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
#
# 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"
# 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() {
KVER=$1
case ${current_os} in
Linux) DIR="/lib/modules/$KVER/build" ;;
GNU/kFreeBSD) DIR="/usr/src/kfreebsd-headers-$KVER/sys" ;;
esac
echo $DIR
}
_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"
echo $" | mkdriverdisk | mktarball | ldtarball | mkrpm | mkkmp | mkdeb | status }"
echo $" [options] = [-m module] [-v module-version] [-k kernel-version] [-a arch]"
echo $" [-d distro] [-c dkms.conf-location] [-q] [--force] [--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()
{
# $1 = the kernel to base the directory on
kernel_source_dir="$(_get_kernel_dir "$1")"
}
# 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"
# 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
set_module_suffix
read -a kernels_module < <(find_module "$lib_tree" "${4}")
if [ -z $kernels_module ]; 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
else
return 0
fi
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
if [[ $file = /etc/sysconfig/kernel ]]; then
sed "${sa_sck_o[*]}" "$file" > "$temp_dir_name/${file##*/}.new"
else
sed "${sa_mc_o[*]}" "$file" > "$temp_dir_name/${file##*/}.new"
fi
if ! mod_diff=$(diff -u "$temp_dir_name/${file##*/}.new" "$file"); then
echo $"$file updated to replace obsoleted module references:"
echo "$mod_diff"
cp -fp "$temp_dir_name/${file##*/}.new" "$file"
rm -f "$temp_dir_name/${file##*/}.new"
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
}
# 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 dkms.conf for this 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 [ "$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"
}
build_module()
{
prepare_build
do_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
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
force_installation $module && echo "Forcing installation of $module" \
&& force="true"
# 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")
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
}
# Make the newly installed modules available immediately
find /sys/devices -name modalias -print0 | xargs -0 cat | xargs modprobe -a -b -q
if [ -f /lib/systemd/system/systemd-modules-load.service ]; then
systemctl restart systemd-modules-load.service
fi
# 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 --parents --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 -rf "$dkms_tree/$module/kernel-$1-$2"
#Remove modules from dkms built tree
rm -rf "$dkms_tree/$module/$module_version/$1"
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 --force -9 "$tarball_dest/$tarball_name"
;;
bz2)
bzip2 --force -9 "$tarball_dest/$tarball_name"
;;
xz)
xz --force -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/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//_/-}
# 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