#!/bin/bash
#
#  Copyright (C) 2003 Dell Computer Corporation <gary_lerhaupt@dell.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
#
#  Dynamic Kernel Module Support (DKMS)
#  by Gary Lerhaupt <gary_lerhaupt@dell.com>

function invoke_command ()
{
    exitval=0
    exitval_file=`mktemp $tmp_location/dkms.XXXXXX`
    echo -en "$2..." 
    if [ "$3" == background ]; then
	(eval $1; echo "exitval=$?" >> "$exitval_file") &
	while [ -e "$exitval_file" ] && ! [ -s "$exitval_file" ]; do
	    sleep 3
	    echo -en "." 
	done
	. "$exitval_file"
    else
	eval $1; exitval=$?
    fi
    if [ $exitval -gt 0 ]; then
	echo -en "(bad exit status: $exitval)" 
	echo $1 >> "$exitval_file"
    else
	rm -f "$exitval_file"
    fi
    echo -en "\n" 
    return $exitval
}

function readlink()
{
    # $1 = the symlink to read
    read_link=""
    if [ -L "$1" ]; then
	read_link="$1"
	while [ -L "$read_link" ]; do
	    read_link=`ls -l $read_link | sed 's/.*-> //'`
	done
    fi
}

function remake_initrd()
{
    # If its Red Hat's version of mkinitrd, we know what to do, otherwise we don't
    exitval="0"
    mkinitrd --version >/dev/null
    if [ "$?" -eq 0 ]; then
      	echo $"" 
	initrd_dir="/boot"
	[ "$arch_used" == "ia64" ] && [ -d "/boot/efi/efi/redhat" ] && initrd_dir="/boot/efi/efi/redhat"
	echo $"Saving old initrd as $initrd_dir/initrd-${kernel_version}_old.img" 
	cp -f "$initrd_dir/initrd-${kernel_version}.img" "$initrd_dir/initrd-${kernel_version}_old.img"
	echo $"Making new initrd as $initrd_dir/initrd-${kernel_version}.img" 
	invoke_command "mkinitrd -f $initrd_dir/initrd-${kernel_version}.img ${kernel_version}" "mkinitrd" background
	exitval="$?"
	echo $"If your next boot fails, edit your bootloader file and revert" 
	echo $"to the _old initrd image." 
    else
	echo $""
	echo $"Calling mkinitrd (bad exit status 9 may occur)"
	invoke_command "mkinitrd >/dev/null 2>&1" "mkinitrd" background
	exitval="$?"
    fi

    # Rerun lilo if necessary
    if ! [ -e /boot/grub/grub.conf ] && [ -e /etc/lilo.conf ]; then
	invoke_command "/sbin/lilo" "Updating lilo"
    fi

    return $exitval
}

function show_usage ()
{
    echo $"Usage: $0 [action] [options]" 
    echo $"  [action]  = { add | remove | build | install | uninstall | match" 
    echo $"               | mkdriverdisk | mktarball | ldtarball | status }" 
    echo $"  [options] = [-k kernel-version] [-m module] [-v module-version]" 
    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]"  
}

function read_conf ()
{
    return_value=0
    # Find which conf file to check
    if [ -n "$1" ]; then
	read_conf_file="$1"
    elif [ -n "$conf" ]; then
	read_conf_file="$conf"
    else
	read_conf_file="$dkms_tree/$module/$module_version/source/dkms.conf"
    fi

    # Clear variables
    MAKE=""
    CLEAN=""
    REMAKE_INITRD=""
    remake_initrd=""
    PACKAGE_NAME=""
    PACKAGE_VERSION=""
    POST_ADD=""
    POST_BUILD=""
    POST_INSTALL=""
    POST_REMOVE=""
    PRE_BUILD=""
    BUILD_EXCLUSIVE_KERNEL=""
    BUILD_EXCLUSIVE_ARCH=""
    build_exclude=""

    # Clear arrays
    unset MAKE
    unset MAKE_MATCH
    unset MODULES_CONF
    unset modules_conf_array
    unset PATCH
    unset PATCH_MATCH
    unset patch_array
    unset BUILT_MODULE_NAME
    unset built_module_name
    unset BUILT_MODULE_LOCATION
    unset built_module_location
    unset DEST_MODULE_NAME
    unset dest_module_name
    unset DEST_MODULE_LOCATION
    unset dest_module_location
    unset MODULES_CONF_OBSOLETES
    unset modules_conf_obsoletes
    unset MODULES_CONF_ALIAS_TYPE
    unset modules_conf_alias_type
    unset MODULES_CONF_OBSOLETE_ONLY
    unset modules_conf_obsolete_only

    # Set variables supported in dkms.conf files (eg. $kernelver)
    kernelver="$kernel_version"
    [ -z "$kernel_source_dir" ] && kernel_source_dir="/lib/modules/$kernel_version/build"

    # Source in the dkms.conf
    . $read_conf_file 2>/dev/null

    # Source in the directive_array
    IFS='
'
    for directive in "${directive_array[*]}"; do
	directive_name=`echo $directive | sed 's/\([^=]\+\)=.*/\1/'`
	directive_value=`echo $directive | sed 's/[^=]\+=//'`
	[ -n "$directive" ] && export $directive_name="$directive_value"
	[ -n "$directive" ] && echo $"DIRECTIVE: $directive_name=\"$directive_value\""
    done
    unset IFS

    # 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"

    # Set module naming/location arrays
    index=0
    array_size=`echo -e "${#BUILT_MODULE_NAME[*]}\n${#BUILT_MODULE_LOCATION[*]}\n${#DEST_MODULE_NAME[*]}\n${#DEST_MODULE_LOCATION[*]}\n" | sort -n | tail -1`
    while [ "$index" -lt "$array_size" ]; 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]}
	[ `echo "${MODULES_CONF_OBSOLETE_ONLY[$index]}" | grep -ic "^y"` -gt 0 ] && modules_conf_obsolete_only[$index]="yes"

	# If unset, set by defaults
	[ -z "${built_module_name[$index]}" ] && [ "${#DEST_MODULE_LOCATION[*]}" -eq 1 ] && built_module_name[$index]=$module
	[ -z "${dest_module_name[$index]}" ] && dest_module_name[$index]=${built_module_name[$index]}
	[ -n "${built_module_location[$index]}" ] && [ `echo ${built_module_location[$index]} | grep -c "\/$"` -eq 0 ] && built_module_location[$index]="${built_module_location[$index]}/"

	# FAIL if no built_module_name
	if [ -z "${built_module_name[$index]}" ]; then
	    echo $"dkms.conf: Error! No 'BUILT_MODULE_NAME' directive specified for record #$index." >$std_err
	    return_value=1
	fi

	# FAIL if built_module_name has .o or .ko in it
	if [ `echo "${built_module_name[$index]}" | grep -c "\.k\?o$"` -gt 0 ]; then
	    echo $"dkms.conf: Error! 'BUILT_MODULE_NAME' directive includes phrase '.o' or '.ko' in record #$index." >$std_err
	    return_value=1
	fi

	# FAIL if dest_module_name has .o or .ko in it
	if [ `echo "${dest_module_name[$index]}" | grep -c "\.k\?o$"` -gt 0 ]; then
	    echo $"dkms.conf: Error! 'DEST_MODULE_NAME' directive includes phrase '.o' or '.ko' in record #$index." >$std_err
	    return_value=1
	fi
	
        # Fail if no DEST_MODULE_LOCATION 
	if [ -z "${DEST_MODULE_LOCATION[$index]}" ]; then
	    echo $"dkms.conf: Error! No 'DEST_MODULE_LOCATION' directive specified for record #$index.">$std_err
	    return_value=1
	fi
	
        # Fail if bad DEST_MODULE_LOCATION
	if [ `echo "${DEST_MODULE_LOCATION[$index]}" | grep -c "^/kernel"` -eq 0 ]; then
	    echo $"dkms.conf: Error! Directive 'DEST_MODULE_LOCATION' does not begin with '/kernel' in record #$index.">$std_err
	    return_value=1
	fi

	index=$(($index+1))
    done

    # Get the correct make command
    index=1
    make_command="${MAKE[0]}"
    while [ "$index" -lt "${#MAKE[*]}" ]; do
	if [ -n "${MAKE[$index]}" ] && [ -n "${MAKE_MATCH[$index]}" ] && [ `echo $kernel_version | egrep -c "${MAKE_MATCH[$index]}"` -gt 0 ]; then
	    make_command="${MAKE[$index]}"
	fi
	index=$(($index+1))
    done

    # Use the generic make command if kernel >= 2.5
    if [ -n "$gt2dot4" ]; then
	#make_command="make -C /lib/modules/$kernel_version/build SUBDIRS=$dkms_tree/$module/$module_version/build modules"
	#[ -d "$kernel_source_dir" ] && ! [ -h "$kernel_source_dir" ] && make_command="make -C /lib/modules/$kernel_version/build M=$dkms_tree/$module/$module_version/build"
	make_command="make -C /lib/modules/$kernel_version/build M=$dkms_tree/$module/$module_version/build"
    fi
    
    # Set modules_conf_array
    index=0
    while [ "$index" -lt "${#MODULES_CONF[*]}" ]; do
	[ -n "${MODULES_CONF[$index]}" ] && modules_conf_array[$index]="${MODULES_CONF[$index]}"
	index=$(($index+1))
    done

    # Set patch_array (including kernel specific patches)
    index=0
    count=0
    while [ "$index" -lt "${#PATCH[*]}" ]; do
	if [ -z "${PATCH_MATCH[$index]}" ] || [ `echo $kernel_version | egrep -c "${PATCH_MATCH[$index]}"` -gt 0 ]; then
	    patch_array[$count]="${PATCH[$index]}"
	    count=$(($count+1))
	fi
	index=$(($index+1))
    done

    # Set remake_initrd
    [ `echo "$REMAKE_INITRD" | grep -ic "^y"` -gt 0 ] && remake_initrd="yes"

    # Set build_exclude
    [ -n "$BUILD_EXCLUSIVE_KERNEL" ] && [ `echo $kernel_version | egrep -c "$BUILD_EXCLUSIVE_KERNEL"` -eq 0 ] && build_exclude="yes"
    [ -n "$BUILD_EXCLUSIVE_ARCH" ] && [ `echo $arch_used | egrep -c "$BUILD_EXCLUSIVE_ARCH"` -eq 0 ] && build_exclude="yes"


    # Fail if no make command
    if [ -z "$make_command" ]; then
	echo $"dkms.conf: Error! No 'MAKE' directive specified.">$std_err
	return_value=1
    fi

    # Fail if absolutely no DEST_MODULE_LOCATION
    if [ "${#dest_module_location[*]}" -eq 0 ]; then
	echo $"dkms.conf: Error! No 'DEST_MODULE_LOCATION' directive specified." >$std_err
	return_value=1
    fi

    # Fail if no PACKAGE_NAME
    if [ -z "$package_name" ]; then
	echo $"dkms.conf: Error! No 'PACKAGE_NAME' directive specified.">$std_err
	return_value=1
    fi

    # Fail if no PACKAGE_VERSION
    if [ -z "$package_version" ]; then
	echo $"dkms.conf: Error! No 'PACKAGE_VERSION' directive specified.">$std_err
	return_value=1
    fi

    # Set clean 
    [ -z "$clean" ] && clean="make clean"

    return $return_value
}

function modulesconf_modify ()
{
    # Make a temp directory to store files
    temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX`

    # Make modules.conf changes as necessary
    if [ "$1" == "add" ]; then

	# Add aliases
	index=0
	while [ $index -lt ${#dest_module_name[*]} ]; do

  	    # Replace obsolete references in /etc/modules.conf with the new module name
	    if [ -n "${modules_conf_obsoletes[$index]}" ]; then
		for obsolete_module in `echo ${modules_conf_obsoletes[$index]} | tr ',' '\n'`; do
		    sed "s/\(alias ${modules_conf_alias_type[$index]}[0-9]*\) $obsolete_module$/\1 ${dest_module_name[$index]}/g" /etc/modules.conf > $temp_dir_name/modules.new
		    if ! `diff /etc/modules.conf $temp_dir_name/modules.new >/dev/null 2>&1`; then 
			cp -fp $temp_dir_name/modules.new /etc/modules.conf 2>/dev/null
			rm -f $temp_dir_name/modules.new 2>/dev/null
			echo $"Obsolete alias '$obsolete_module' changed to '${dest_module_name[$index]}' in /etc/modules.conf"
		    fi
		done
	    fi
	    
	    # Only add it if it can't be found already in /etc/modules.conf
	    if [ -n "${modules_conf_alias_type[$index]}" ] && [ `grep -c "alias ${modules_conf_alias_type[$index]}[0-9]* ${dest_module_name[$index]}\b" /etc/modules.conf` -eq 0 ] && [ "${modules_conf_obsolete_only[$index]}" != "yes" ]; then
		alias_number=$(( `grep "alias ${modules_conf_alias_type[$index]}" /etc/modules.conf | awk '{print $2}' | sed "s/${modules_conf_alias_type[$index]}//" | sort -n | tail -1` + 1 ))
		echo -e "alias ${modules_conf_alias_type[$index]}${alias_number} ${dest_module_name[$index]}" >> /etc/modules.conf
		echo $"Alias reference for '${dest_module_name[$index]}' added to /etc/modules.conf"
	    fi

	    index=$(($index+1))

	done
	
	# Add anything else
	index=0
	[ -n "$modules_conf_array" ] && echo $"Adding static entries for this module into /etc/modules.conf"
	while [ $index -lt ${#modules_conf_array[*]} ]; do
	    if [ -n "${modules_conf_array[$index]}" ] && [ `grep -c "${modules_conf_array[$index]}" "/etc/modules.conf"` -eq 0 ]; then
		echo -e "${modules_conf_array[$index]}" >> /etc/modules.conf
	    fi	    
	    index=$(($index+1))
	done

    # Remove modules_conf entries from /etc/modules.conf
    elif [ "$1" == "delete" ]; then

	index=0
	while [ $index -lt ${#dest_module_name[*]} ]; do

	    # Remove/Replace aliases (maybe)
	    if [ -n "${modules_conf_alias_type[$index]}" ] && [ `find /lib/modules/$kernel_version/ -name "${dest_module_name[$index]}.*" 2>/dev/null | wc -l | awk '{print $1}'` -eq 0 ]; then

		conf_replacement=""
		for obsolete_module in `echo ${modules_conf_obsoletes[$index]} | tr ',' '\n'`; do
		    if [ `find /lib/modules/$kernel_version/ -name "$obsolete_module.*" 2>/dev/null | wc -l | awk '{print $1}'` -gt 0 ] && [ -z "$conf_replacement" ]; then
			conf_replacement=$obsolete_module
		    fi
		done
		
		if [ -n "$conf_replacement" ] && [ `grep -c "alias ${modules_conf_alias_type[$index]}[0-9]* ${dest_module_name[$index]}$" /etc/modules.conf` -gt 0 ]; then
		    sed "s/\(alias ${modules_conf_alias_type[$index]}[0-9]*\) ${dest_module_name[$index]}$/\1 $conf_replacement/g" /etc/modules.conf > $temp_dir_name/modules.new
		    mv -f $temp_dir_name/modules.new /etc/modules.conf
		    echo $"Alias for '${dest_module_name[$index]}' changed back to '$conf_replacement' in /etc/modules.conf"
		elif [ -z "$conf_replacement" ]; then
		    grep -v "alias ${modules_conf_alias_type}[0-9]* ${dest_module_name[$index]}" /etc/modules.conf > $temp_dir_name/modules.new
		    mv -f $temp_dir_name/modules.new /etc/modules.conf
		    echo $"Alias for '${dest_module_name[$index]}' removed from /etc/modules.conf"
		fi
	    fi

	    index=$(($index+1))
	done

	# Remove static conf entries
	index=0
	[ -n "$modules_conf_array" ] && echo $"Removing static entries for this module from /etc/modules.conf"
	while [ $index -lt ${#modules_conf_array[*]} ]; do
	    if [ -n "${modules_conf_array[$index]}" ]; then
		grep -v "${modules_conf_array[$index]}" "/etc/modules.conf" > $temp_dir_name/modules.new
		mv -f $temp_dir_name/modules.new /etc/modules.conf
	    fi	    
	    index=$(($index+1))
	done
    fi

    # Delete the temp dir
    rm -rf $temp_dir_name
}

function etc_sysconfig_kernel_modify ()
{
    # Make a temp directory to store files
    temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX`

    if [ -e "/etc/sysconfig/kernel" ] && [ -n "$remake_initrd" ]; then

        # Make /etc/sysconfig/kernel changes as necessary
	if [ "$1" == "add" ]; then
	    etc_sysconfig_kernel_modify "delete"
	    for module_name_after in ${dest_module_name[*]}; do
		sed -e "s/INITRD_MODULES=\"\(.*\)\"/INITRD_MODULES=\"\1 $module_name_after\"/" /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 module_name_after in ${dest_module_name[*]}; do
		sed -e "s/\(INITRD_MODULES.*\)$module_name_after\b\(.*\)/\1\2/" /etc/sysconfig/kernel > $temp_dir_name/kernel.new
		mv $temp_dir_name/kernel.new /etc/sysconfig/kernel
	    done
	fi
    fi

    # Delete the temp dir
    rm -rf $temp_dir_name
}

function add_module ()
{

    # Set the kernel_version if it remains unset
    if [ -z "$kernel_version" ]; then
	kernel_version="$current_kernel"
    fi

    # Check that we have all the arguments
    if [ -z "$module" ] || [ -z "$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of arguments passed." >$std_err
	echo $"Usage: add [-m module] [-v module-version]" >$std_err
	exit 1
    fi

    if [ -z "$conf" ]; then
	conf="$source_tree/$module-$module_version/dkms.conf"
    fi
	
    # Check that /usr/src/$module-$module_version exists	
    if ! [ -d "$source_tree/$module-$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Could not find module source directory." >$std_err
	echo $"Directory: $source_tree/$module-$module_version does not exist." >$std_err
	exit 2
    fi

    # Do stuff for --rpm_safe_upgrade
    if [ -n "$rpm_safe_upgrade" ]; then
	pppid=`cat /proc/$PPID/status | grep PPid: | awk {'print $2'}`
	temp_dir_name=`mktemp $tmp_location/dkms_rpm_safe_upgrade_lock.$pppid.XXXXXX 2>/dev/null`
	echo "$module-$module_version" >> $temp_dir_name
	ps -o lstart --no-headers -p $pppid 2>/dev/null >> $temp_dir_name
    fi

    # Check that this module-version hasn't already been added
    if [ -d "$dkms_tree/$module/$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! DKMS tree already contains: $module-$module_version" >$std_err
	echo $"You cannot add the same module/version combo more than once." >$std_err
	exit 3
    fi

    # Check that the conf file exists or any other script specified
    if ! [ -e "$conf" ]; then
	echo $"" >$std_err
	echo $"Error! Could not locate dkms.conf file." >$std_err
	echo $"File: $conf does not exist." >$std_err
	exit 4
    fi

    # Check the conf file for sanity
    read_conf "$conf"
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"File: $conf" >$std_err
	echo $"does not represent a valid dkms.conf file." >$std_err
	exit 8
    fi
    
    # 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
    if [ -n "$post_add" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$post_add" | sed 's/ .*//'` ]; then
	echo $"" 
	echo $"Running the post_add script:" 
	$dkms_tree/$module/$module_version/source/$post_add
    fi
    
    echo $"" 
    echo $"DKMS: Add Completed." 
}

function prepare_kernel()
{
    # Set the kernel variables
    [ -z "$kernel_source_dir" ] && kernel_source_dir="/lib/modules/$kernel_version/build"

    # Check that kernel-source exists
    if ! [ -e "$kernel_source_dir/include" ]; then
	echo $"" >$std_err
	echo $"Error! Your kernel source for kernel $kernel_version cannot be found" >$std_err
	echo $"at: $kernel_source_dir." >$std_err
	echo $"You can use the --kernelsourcedir option to tell DKMS where it's located."
	exit 1	
    fi

    # Prepare kernel for module build
    echo $"" 
    echo $"Preparing kernel $kernel_version for module build:" 
    echo $"(This is not compiling a kernel, only just preparing kernel symbols)" 
    cd $kernel_source_dir
    config_contents=`cat .config 2>/dev/null`
    [ -n "$config_contents" ] && echo $"Storing current .config to be restored when complete"
    
    # Do preparation
    if [ -e /boot/vmlinuz.version.h ]; then
	echo $"Running UnitedLinux preparation routine"
	kernel_config="/boot/vmlinuz.config"
	invoke_command "make mrproper >/dev/null 2>&1" "make mrproper" background
	[ -n "$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=$kernel_version cloneconfig >/dev/null 2>&1" "make cloneconfig" background
	invoke_command "make CONFIG_MODVERSIONS=1 KERNELRELEASE=$kernel_version dep >/dev/null 2>&1" "make CONFIG_MODVERSIONS=1 dep" background
    elif `grep -q rhconfig.h $kernel_source_dir/include/linux/modversions.h 2>/dev/null`; then
	echo $"Running Red Hat preparation routine"
	invoke_command "make clean >/dev/null 2>&1" "make clean" background
	[ -n "$config_contents" ] && echo "$config_contents" > .config

        # If kernel_config is not set, look in default spot for .config (./configs/kernel-...)
	if [ -z "$kernel_config" ] && [ -d "$kernel_source_dir/configs" ]; then
	    kernel_trunc=`echo $kernel_version | sed 's/-.*//'`
	    for config_type in debug summit smp enterprise bigmem hugemem BOOT; do
		if [ `echo "$kernel_version" | grep "$config_type"` ]; then
		    [ "$config_type" == "BOOT" ] && arch_used="i386"
		    kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$arch_used-$config_type.config"
		fi
	    done
	    [ -z "$kernel_config" ] && kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$arch_used.config"
	fi
	
	# Warn if no config, otherwise use it
	if [ -z "$kernel_config" ]; then
	    echo $""
	    echo $"Warning! Cannot find a .config file to prepare your kernel with."
	    echo $"Try using the --config option to specify where one can be found."
	    echo $"Your build will likely fail because of this."
	else
	    echo $"using $kernel_config"
	    cp -f "$kernel_config" .config
	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=$kernel_version oldconfig >/dev/null 2>&1" "make oldconfig" background
	kerneldoth_contents=`cat /boot/kernel.h 2>/dev/null`
	invoke_command "dkms_mkkerneldoth --kernelver $kernel_version --output /boot/kernel.h" "running dkms_mkkerneldoth" background
    else 
	echo $"Running Generic preparation routine"
	invoke_command "make mrproper >/dev/null 2>&1" "make mrproper" background
	[ -n "$config_contents" ] && echo "$config_contents" > .config

        # If kernel_config is not set, look in default spot for .config (./configs/kernel-...)
	if [ -z "$kernel_config" ] && [ -d "$kernel_source_dir/configs" ]; then
	    kernel_trunc=`echo $kernel_version | sed 's/-.*//'`
	    for config_type in debug summit smp enterprise bigmem hugemem BOOT; do
		if [ `echo "$kernel_version" | grep "$config_type"` ]; then
		    [ "$config_type" == "BOOT" ] && arch_used="i386"
		    kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$arch_used-$config_type.config"
		fi
	    done
	    [ -z "$kernel_config" ] && kernel_config="$kernel_source_dir/configs/kernel-$kernel_trunc-$arch_used.config"
	fi
	
	# Warn if no config, otherwise use it
	if [ -z "$kernel_config" ]; then
	    echo $""
	    echo $"Warning! Cannot find a .config file to prepare your kernel with."
	    echo $"Try using the --config option to specify where one can be found."
	    echo $"Your build will likely fail because of this."
	else
	    echo $"using $kernel_config"
	    cp -f "$kernel_config" .config
	fi

	[ -n "$gt2dot4" ] && invoke_command "make KERNELRELEASE=$kernel_version modules_prepare >/dev/null 2>&1" "make prepare-all" background
	invoke_command "make KERNELRELEASE=$kernel_version oldconfig >/dev/null 2>&1" "make oldconfig" background
	[ -z "$gt2dot4" ] && invoke_command "make KERNELRELEASE=$kernel_version dep >/dev/null 2>&1" "make dep" background
    fi
    cd -
}

function install_module()
{
    # Set the kernel_version if it remains unset
    if [ -z "$kernel_version" ]; then
	kernel_version="$current_kernel"
    fi

    # Check that the right arguments were passed
    if [ -z "$module" ] || [ -z "$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: install [-m module] [-v module-version]" >$std_err
	exit 1
    fi

    # Check that $module-$module_version exists by checking the source symlink	
    if ! [ -d "$dkms_tree/$module/$module_version/source" ]; then
	echo $"" >$std_err
	echo $"Error! DKMS tree does not contain: $module-$module_version" >$std_err
	echo $"Build cannot continue without the proper tree." >$std_err
	exit 2
    fi

    # Make sure that kernel exists to install into
    if ! [ -e "/lib/modules/$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! The directory /lib/modules/$kernel_version doesn't exist." >$std_err
	echo $"You cannot install a module onto a non-existant kernel." >$std_err
	exit 6
    fi

    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"Your dkms.conf is not valid." $std_err
	exit 3
    fi

    # Make sure the $module_name_after exists
    for module_name_after in ${dest_module_name[*]}; do
	if ! [ -e "$dkms_tree/$module/$module_version/$kernel_version/module/$module_name_after$module_suffix" ]; then
    echo $"" >$std_err
	    echo $"Error! Could not locate $module_name_after$module_suffix for module $module in the DKMS tree." >$std_err
	    echo $"You must run a dkms build for kernel $kernel_version first." >$std_err
	    exit 4
	fi
    done

    # Check that its not already installed (kernel symlink)
    readlink "$dkms_tree/$module/kernel-${kernel_version}"
    kernel_symlink="$read_link"
    if [ "$kernel_symlink" == "$module_version/$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! This module/version combo is already installed" >$std_err
	echo $"for kernel: $kernel_version" >$std_err
	exit 5
    fi

    # Save the original_module if one exists, none have been saved before, and this is the first module for this kernel
    lib_tree="/lib/modules/$kernel_version"
    count=0
    while [ "$count" -lt "${#built_module_name[*]}" ]; do
	echo $""
	echo $"${dest_module_name[$count]}$module_suffix:"
	module_count=`find $lib_tree -name ${dest_module_name[$count]}$module_suffix | wc -l | awk {'print $1'}`
	echo $" - Original module"
	if ! [ -L "$dkms_tree/$module/kernel-$kernel_version" ]; then
	    archive_pref1="$lib_tree/updates/${dest_module_name[$count]}$module_suffix"
	    archive_pref2="$lib_tree${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix"
	    [ "$module_count" -eq 1 ] && archive_pref3="`find $lib_tree -name ${dest_module_name[$count]}$module_suffix`"
	    original_module=""
	    found_orginal=""
	    for original_module in $archive_pref1 $archive_pref2 $archive_pref3; do
		if [ -e "$original_module" ]; then
		    echo $"   - Found $original_module"
		    echo $"   - Storing in $dkms_tree/$module/original_module/$kernel_version/"
		    echo $"   - Archiving for uninstallation purposes"
		    mkdir -p "$dkms_tree/$module/original_module/$kernel_version/"
		    cp -f "$original_module" "$dkms_tree/$module/original_module/$kernel_version/"
		    found_original="yes"
		    break
		fi
	    done
	    if [ -z "$found_original" ] && [ "$module_count" -gt 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 [ -z "$found_original" ]; then
		echo $"   - No original module exists within this kernel"
	    fi
	elif [ -L "$dkms_tree/$module/kernel-$kernel_version" ] && [ -e "$dkms_tree/$module/original_module/$kernel_version/${dest_module_name[$count]}$module_suffix" ]; then
	    echo $"   - An original module was already stored during a previous install"
	else
	    echo $"   - This kernel never originally had a module by this name"
	fi
	    
	if [ "$module_count" -gt 1 ]; then
	    echo $" - Multiple same named modules!"
	    echo $"   - $module_count named ${dest_module_name[$count]}$module_suffix in $lib_tree/"
	    echo $"   - All instances of this module will now be stored for reference purposes ONLY"
	    echo $"   - Storing in $dkms_tree/$module/original_module/$kernel_version/collisions/"
	    for module_dup in `find $lib_tree -name ${dest_module_name[$count]}$module_suffix`; do
		dup_tree=`echo $module_dup | sed "s#^$lib_tree##" | sed "s#${dest_module_name[$count]}$module_suffix##"`
		echo $"     - Stored $module_dup"
		mkdir -p "$dkms_tree/$module/original_module/$kernel_version/collisions/$dup_tree"
		mv -f $module_dup "$dkms_tree/$module/original_module/$kernel_version/collisions/$dup_tree"
	    done
	fi

        # Copy module to its location
	echo $" - Installation"
 	echo $"   - Installing to /lib/modules/$kernel_version${dest_module_location[$count]}/" 
	mkdir -p /lib/modules/$kernel_version${dest_module_location[$count]}
	cp -f "$dkms_tree/$module/$module_version/$kernel_version/module/${dest_module_name[$count]}$module_suffix" "/lib/modules/$kernel_version${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix"

	count=$(($count + 1))
    done
    
    # Create the kernel-<kernelver> symlink to designate this version as active
    rm -f "$dkms_tree/$module/kernel-$kernel_version" 2>/dev/null
    ln -s "$module_version/$kernel_version" "$dkms_tree/$module/kernel-$kernel_version" 2>/dev/null

    # Run the post_install script
    if [ -n "$post_install" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$post_install" | sed 's/ .*//'` ]; then
	echo $""
	echo $"Running post_install:"  
	$dkms_tree/$module/$module_version/source/$post_install
    fi

    # Make modules.conf changes as necessary
    echo $""
    modulesconf_modify "add"
    etc_sysconfig_kernel_modify "add"

    # Run depmod if System.map-<kernel_version> exists
    if [ -e "/boot/System.map-$kernel_version" ]; then
	invoke_command "depmod -au $kernel_version -F /boot/System.map-$kernel_version" "depmod" background 
	if [ "$?" -ne 0 ]; then
	    unresolved_symbols="`depmod -a $kernel_version -F /boot/System.map-$kernel_version 2>&1`"
	    count=0
	    while [ "$count" -lt "${#built_module_name[*]}" ]; do
		if [ `echo "$unresolved_symbols" | grep -c "${dest_module_name[$count]}$module_suffix$"` -gt 0 ]; then
		    echo $""
		    echo $"Problems with depmod detected.  Automatically uninstalling this module."
		    sleep 2
		    do_uninstall
		    echo $""
		    echo $"DKMS: Install Failed (depmod problems).  Module rolled back to built state."
		    exit 6
		fi
		count=$(($count + 1))
	    done
	fi
    fi

    # Do remake_initrd things (save old initrd)
    if [ -n "$remake_initrd" ]; then
	remake_initrd
	if [ "$?" -ne 0 ]; then
	    echo $"Problems with mkinitrd detected.  Automatically uninstalling this module."
	    sleep 2
	    do_uninstall
	    echo $""
	    echo $"DKMS: Install Failed (mkinitrd problems).  Module rolled back to built state."
	    exit 7
	fi
    fi
     
    echo $"" 
    echo $"DKMS: Install Completed." 
}


function build_module()
{
    # Set the kernel_version if it remains unset
    if [ -z "$kernel_version" ]; then
	kernel_version="$current_kernel"
    fi

    # Check that the right arguments were passed
    if [ -z "$module" ] || [ -z "$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: build [-m module] [-v module-version]" >$std_err
	exit 1
    fi
    
    # Set the kernel variables
    [ -z "$kernel_source_dir" ] && kernel_source_dir="/lib/modules/$kernel_version/build"

    # Check that source symlink works
    if ! [ -d "$dkms_tree/$module/$module_version/source" ]; then
	echo $"" >$std_err
	echo $"Error! DKMS tree does not contain: $module-$module_version" >$std_err
	echo $"Build cannot continue without the proper tree." >$std_err
	exit 2
    fi

    # Check that the module has not already been built for this kernel
    if [ -d "$dkms_tree/$module/$module_version/$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! This module/version has already been built on: $kernel_version" >$std_err
	echo $"The directory: $dkms_tree/$module/$module_version/$kernel_version already" >$std_err
	echo $"exists.  Use the dkms remove function before trying to build again." >$std_err
	exit 3
    fi
	
    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"Your dkms.conf is not valid." >$std_err
	exit 4
    fi

    # Error out if build_exclude is set
    if [ -n "$build_exclude" ]; then
	echo "" >$std_err
	echo "Error!  The dkms.conf for this module includes a BUILD_EXCLUSIVE directive which" >$std_err
	echo "does not match this kernel/arch.  This indicates that it should not be built." >$std_err
	exit 9
    fi

    # Error out if source_tree is basically empty (binary-only dkms tarball w/ --force check)
    if [ `ls $dkms_tree/$module/$module_version/source | wc -l | awk {'print $1'}` -lt 2 ]; then
	echo "" >$std_err
	echo $"Error! The directory $dkms_tree/$module/$module_version/source/" >$std_err
	echo $"does not appear to have module source located within it.  Build halted." >$std_err
	exit 8
    fi
    
    should_prepare="$1"
    [ -n "$gt2dot4" ] && [ -d "$kernel_source_dir" ] && ! [ -h "$kernel_source_dir" ] && should_prepare="no-prepare-kernel"

    # Prepare the kernel for the module build
    if [ "$should_prepare" != "no-prepare-kernel" ]; then
	prepare_kernel
    elif [ -n "$gt2dot4" ]; then
	echo $""
	echo $"Kernel preparation unnecessary for this kernel.  Skipping..."
    fi
    
    # Set up temporary build directory for build
    rm -rf "$dkms_tree/$module/$module_version/build"
    cp -rf "$dkms_tree/$module/$module_version/source/" "$dkms_tree/$module/$module_version/build"

    # Run the pre_build script
    if [ -n "$pre_build" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$pre_build" | sed 's/ .*//'` ]; then
	echo $"" 
	echo $"Running the pre_build script:" 
	$dkms_tree/$module/$module_version/source/$pre_build
    fi

    cd "$dkms_tree/$module/$module_version/build"
    echo $"" 
    echo $"Building module:" 

    # Apply any patches
    index=0
    while [ $index -lt ${#patch_array[*]} ]; do
	if ! [ -e "$dkms_tree/$module/$module_version/build/patches/${patch_array[$index]}" ]; then
	    echo $"" >$std_err
	    echo $"Error!  Patch ${patch_array[$index]} as specified in dkms.conf cannot be" >$std_err
	    echo $"found in $dkms_tree/$module/$module_version/build/patches/." >$std_err
	    exit 5
	fi
	invoke_command "patch -p1 < ./patches/${patch_array[$index]}" "applying patch ${patch_array[$index]}"
	if [ "$?" -ne 0 ]; then
	    echo $"" >$std_err
	    echo $"Error! Application of patch ${patch_array[$index]} failed." >$std_err
	    echo $"Check $dkms_tree/$module/$module_version/build/ for more information." >$std_err
	    exit 6
	fi
	index=$(($index+1))
    done

    # Build
    invoke_command "$clean >/dev/null 2>&1" "cleaning build area" background
    echo $"DKMS make.log for $module-$module_version for kernel $kernel_version" >> "$dkms_tree/$module/$module_version/build/make.log"
    echo $"`date`" >> "$dkms_tree/$module/$module_version/build/make.log"
    the_make_command=`echo $make_command | sed "s/^make/make KERNELRELEASE=$kernel_version/"`
    invoke_command "$the_make_command >> $dkms_tree/$module/$module_version/build/make.log 2>&1" "$the_make_command" background

    # Make sure good return status
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad return status from module build for kernel: $kernel_version" >$std_err
	echo $"Consult the make.log in the build directory" >$std_err
	echo $"$dkms_tree/$module/$module_version/build/ for more information." >$std_err
	exit 10
    fi	

    # Make sure all the modules built successfully
    count=0
    while [ "$count" -lt "${#built_module_name[*]}" ]; do
	if ! [ -e "${built_module_location[$count]}${built_module_name[$count]}$module_suffix" ]; then
	    echo $"" >$std_err
	    echo $"Error!  Module build ${built_module_name[$count]}$module_suffix failed for kernel: $kernel_version" >$std_err
	    echo $"Consult the make.log in the build directory" >$std_err
	    echo $"$dkms_tree/$module/$module_version/build/ for more information." >$std_err
	    exit 7
	fi
	count=$(($count+1))
    done
    cd -

    # Build success, so create DKMS structure for a built module
    mkdir -p "$dkms_tree/$module/$module_version/$kernel_version/log"
    [ -n "$kernel_config" ] && cp -f "$kernel_config" "$dkms_tree/$module/$module_version/$kernel_version/log/"  
    mv -f "$dkms_tree/$module/$module_version/build/make.log" "$dkms_tree/$module/$module_version/$kernel_version/log/make.log" 2>/dev/null   

    # Save a copy of the new module
    mkdir "$dkms_tree/$module/$module_version/$kernel_version/module" >/dev/null
    count=0
    while [ "$count" -lt "${#built_module_name[*]}" ]; do
	cp -f "$dkms_tree/$module/$module_version/build/${built_module_location[$count]}${built_module_name[$count]}$module_suffix" "$dkms_tree/$module/$module_version/$kernel_version/module/${dest_module_name[$count]}$module_suffix" >/dev/null
	count=$(($count+1))
    done

    # Run the post_build script
    if [ -n "$post_build" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$post_build" | sed 's/ .*//'` ]; then
	echo $"" 
	echo $"Running the post_build script:" 
	$dkms_tree/$module/$module_version/source/$post_build 
    fi
    
    # Run the clean commands
    cd "$dkms_tree/$module/$module_version/build"
    invoke_command "$clean >/dev/null 2>&1" "cleaning build area" background
    cd -
    if [ "$should_prepare" != "no-prepare-kernel" ] && [ -z $no_clean_kernel ]; then
	cd "$kernel_source_dir"
	[ -z "$kerneldoth_contents" ] && invoke_command "make mrproper >/dev/null 2>&1" "cleaning kernel tree (make mrproper)" background
	[ -n "$config_contents" ] && echo "$config_contents" > .config
	[ -n "$kerneldoth_contents" ] && echo "$kerneldoth_contents" > /boot/kernel.h
	cd -
    fi

    # Clean the build directory
    rm -rf "$dkms_tree/$module/$module_version/build/*"

    echo $"" 
    echo $"DKMS: Build Completed." 
}

function do_uninstall()
{
    echo $"" 
    echo $"--- Uninstall Beginning ---" 
    echo $"Module:  $module"  
    echo $"Version: $module_version" 
    echo $"Kernel:  $kernel_version" 
    echo $"---------------------------" 

    # If kernel-<kernelver> symlink points to this module, check for original_module and put it back
    was_active=""
    readlink "$dkms_tree/$module/kernel-${kernel_version}"
    kernel_symlink="$read_link"
    if [ "$kernel_symlink" == "$module_version/$kernel_version" ]; then
	was_active="true"
	echo $"" 
	echo $"Status: Before uninstall, this module version was ACTIVE on this kernel."
	count=0
	while [ "$count" -lt "${#built_module_name[*]}" ]; do
	    echo $""
	    echo $"${dest_module_name[$count]}$module_suffix:"
	    echo $" - Uninstallation"
	    echo $"   - Deleting from: /lib/modules/$kernel_version${dest_module_location[$count]}/" 
	    rm -f "/lib/modules/$kernel_version${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix"
	    echo $" - Original module"
	    if [ -e "$dkms_tree/$module/original_module/$kernel_version/${dest_module_name[$count]}$module_suffix" ]; then
		echo $"   - Archived original module found in the DKMS tree" 
		echo $"   - Moving it to: /lib/modules/$kernel_version${dest_module_location[$count]}/" 
		mv -f "$dkms_tree/$module/original_module/$kernel_version/${dest_module_name[$count]}$module_suffix" "/lib/modules/$kernel_version${dest_module_location[$count]}/" 2>/dev/null
	    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
		[ -n "$remake_initrd" ] || [ `dkms status -m $module -v $module_version | grep -c "installed"` -eq 1 ] && echo $"" && modulesconf_modify "delete"
	    fi
	    count=$(($count+1))
	done
	rm -f "$dkms_tree/$module/kernel-$kernel_version"
    else
	echo $"" 
	echo $"Status: This module version was INACTIVE for this kernel." 
    fi

    # Run the post_remove script
    if [ -n "$post_remove" ] && [ -x `echo "$dkms_tree/$module/$module_version/source/$post_remove" | sed 's/ .*//'` ]; then
	echo $"" 
	echo $"Running the post_remove script:" 
	$dkms_tree/$module/$module_version/source/$post_remove
    fi
    
    # Do remake_initrd things (remake initrd)
    if [ -n "$remake_initrd" ] && [ -n "$was_active" ]; then
	remake_initrd
	if [ "$?" -ne 0 ]; then
	    echo $""
	    echo $"WARNING! WARNING! WARNING!"
	    echo $"There was a problem remaking your initrd.  You must manually remake it"
	    echo $"before booting into this kernel."
	    echo $""
	fi
    fi

    # Delete the original_module if nothing for this kernel is installed anymore
    if [ -n "$was_active" ] && [ -d "$dkms_tree/$module/original_module/$kernel_version" ] && ! [ -d "$dkms_tree/$module/original_module/$kernel_version/collisions" ]; then
	echo $"" 
	echo $"Removing original_module from DKMS tree for kernel $kernel_version" 
	rm -rf "$dkms_tree/$module/original_module/$kernel_version" 2>/dev/null
    elif [ -n "$was_active" ] && [ -d "$dkms_tree/$module/original_module/$kernel_version/collisions" ]; then
	echo $""
	echo $"Keeping directory $dkms_tree/$module/original_module/$kernel_version/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
    if [ `find "$dkms_tree/$module/original_module" -path "$dkms_tree/$module/original_module/*" 2>/dev/null | wc -l | awk '{print $1}'` -eq 0 ]; then
	rm -rf "$dkms_tree/$module/original_module" 2>/dev/null
    fi

    # 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
    [ -n "$was_active" ] && [ -n "$remake_initrd" ] && [ `dkms status -m $module -v $module_version | grep -c "installed"` -gt 0 ] && modulesconf_modify "add"
    
    echo $"" 
    echo $"DKMS: Uninstall Completed." 
}

function uninstall_module ()
{
    # Set the kernel_version if it remains unset
    if [ -z "$kernel_version" ]; then
	kernel_version="$current_kernel"
    fi

    # Check that the right arguments were passed
    if [ -z "$module" ] || [ -z "$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: uninstall [-m module] [-v module-version]" >$std_err
	echo $"   or: uninstall [-m module] [-v module-version] [-k kernel-version]" >$std_err
	exit 1
    fi

    # Check that $module is in the dkms tree
    if ! [ -d "$dkms_tree/$module" ]; then
	echo $"" >$std_err
	echo $"Error! There are no instances of module: $module" >$std_err
	echo $"located in the DKMS tree." >$std_err
	exit 2
    fi

    # Make sure that its installed in the first place
    if ! [ -d "$dkms_tree/$module/$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! The module/version combo: $module-$module_version" >$std_err
	echo $"is not located in the DKMS tree." >$std_err
	exit 3
    fi

    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"Your dkms.conf is not valid." >$std_err
	exit 4
    fi

    # Only do stuff if module/module version is currently installed
    readlink "$dkms_tree/$module/kernel-${kernel_version}"
    kernel_symlink="$read_link"
    if [ "$kernel_symlink" == "$module_version/$kernel_version" ]; then
	do_uninstall
    else
	echo $"" >$std_err
	echo $"Error! The module $module $module_version is not currently installed." >$std_err
	echo $"This module is not currently ACTIVE for kernel $kernel_version." >$std_err
	exit 5
    fi
}

function remove_module ()
{
    # Check that the right arguments were passed
    if [ -z "$module" ] || [ -z "$module_version" ] || $([ -z "$kernel_version" ] && [ -z "$all" ]); then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: remove [-m module] [-v module-version] --all" >$std_err
	echo $"   or: remove [-m module] [-v module-version] [-k kernel-version]" >$std_err
	exit 1
    fi

    # Check that kernel_version and all aren't both set simultaneously
    if [ -n "$kernel_version" ] && [ -n "$all" ]; then
	echo $"" >$std_err
	echo $"Error!  There is confusion over what to remove." >$std_err
	echo $"You cannot set both --all and specify a kernel-version." >$std_err
	exit 2
    fi

    # Check that $module is in the dkms tree
    if ! [ -d "$dkms_tree/$module/$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! There are no instances of module: $module" >$std_err
	echo $"$module_version located in the DKMS tree." >$std_err
	exit 3
    fi

    # If $kernel_version is set, make sure its there first before removing
    if [ -n "$kernel_version" ] && ! [ -d "$dkms_tree/$module/$module_version/$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! There is no instance of $module $module_version" >$std_err
	echo $"for kernel $kernel_version located in the DKMS tree." >$std_err
	exit 4
    fi

    # Do --rpm_safe_upgrade check (exit out and don't do remove if inter-release RPM upgrade scenario occurs)
    if [ -n "$rpm_safe_upgrade" ]; then
	pppid=`cat /proc/$PPID/status | grep PPid: | awk {'print $2'}`
	time_stamp=`ps -o lstart --no-headers -p $pppid 2>/dev/null`
	for lock_file in `ls $tmp_location/dkms_rpm_safe_upgrade_lock.$pppid.* 2>/dev/null`; do
	    lock_head=`head -1 $lock_file 2>/dev/null`
	    lock_tail=`tail -1 $lock_file 2>/dev/null`
	    if [ "$lock_head" == "$module-$module_version" ] && [ "$lock_tail" == "$time_stamp" ] && [ -n "$time_stamp" ]; then
		echo $""
		echo $"DKMS: Remove cancelled because --rpm_safe_upgrade scenario detected."
		rm -f $lock_file
		exit 0
	    fi
	done
    fi

    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"File: $dkms_tree/$module/$module_version/source/dkms.conf does not represent" >$std_err
	echo $"a valid dkms.conf file." >$std_err
	exit 5
    fi

    # If kernel_version is unset, remove all installations of $module_version, otherwise just one kernel
    kernel_list=""
    if [ -z "$kernel_version" ]; then
	kernel_list="`ls $dkms_tree/$module/$module_version | grep -v "build\b" | grep -v "tarball\b" | grep -v "driver_disk\b" | grep -v "rpm\b"`"
    else
	kernel_list="$kernel_version"
    fi

    # Iterate over the kernel_list
    for kernel_in_tree in $kernel_list; do
	if [ -d "$dkms_tree/$module/$module_version/$kernel_in_tree" ] && ! [ -h "$dkms_tree/$module/$module_version/$kernel_in_tree" ]; then
	    kernel_version="$kernel_in_tree"
	    read_conf
	    if [ "$?" -ne 0 ]; then
		echo $"" >$std_err
		echo $"Error! Bad conf file." >$std_err
		echo $"Your dkms.conf is not valid." >$std_err
		exit 6
	    fi
	    do_uninstall
	    
            # Delete the $kernel_version part of the tree
	    rm -rf "$dkms_tree/$module/$module_version/$kernel_version"
	fi
    done

    # Delete the $module_version part of the tree if no other $module_version/$kernel_version dirs exist
    if [ -z "`find $dkms_tree/$module/$module_version/* -maxdepth 0 -type d | grep -v build$ | grep -v tarball$ | grep -v driver_disk$ | grep -v rpm$`"  ]; 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}'` -eq 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
}

show_status ()
{
    # Error if $module_version is set but $module is not
    if [ -n "$module_version" ] && [ -z "$module" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: status" >$std_err
	echo $"   or: status [-m module]" >$std_err
	echo $"   or: status [-k kernel-version]" >$std_err
	echo $"   or: status [-m module] [-v module-version]" >$std_err
	exit 1	
    fi

    # Determine which modules to show status for
    status_shown=""
    modules_needing_status=""
    versions_needing_status=""
    kernels_needing_status=""
    if [ -n "$module" ]; then
	modules_needing_status="$module"
    else
	for filename in `ls "$dkms_tree"`; do
	    if [ -d "$dkms_tree/$filename" ] && ! [ -h "$dkms_tree/$filename" ]; then
		modules_needing_status="$modules_needing_status $filename"
	    fi
	done
    fi

    # Iterate over the modules
    for module_in_tree in $modules_needing_status; do

	# Make sure its in the tree
	if [ -d "$dkms_tree/$module_in_tree" ]; then
	
	    # Determine which versions to show status for
	    versions_needing_status=""
	    if [ -n "$module_version" ]; then
		versions_needing_status="$module_version"
	    else
		for filename in `ls "$dkms_tree/$module_in_tree"`; do
		    if [ -d "$dkms_tree/$module_in_tree/$filename" ] && ! [ -h "$dkms_tree/$module_in_tree/$filename" ] && [ "$filename" != "original_module" ]; then
			versions_needing_status="$versions_needing_status $filename"
		    fi
		done    
	    fi
	    
	    # Iterate over the versions
	    for version_in_tree in $versions_needing_status; do
		
     	        # Make sure its in the tree
		if [ -d "$dkms_tree/$module_in_tree/$version_in_tree" ]; then
		    
	            # Determine which kernels to show status for
		    kernels_needing_status=""
		    if [ -n "$kernel_version" ]; then
			kernels_needing_status="$kernel_version"
		    else
			for filename in `ls $dkms_tree/$module_in_tree/$version_in_tree | grep -v "build\b" | grep -v "tarball\b" | grep -v "driver_disk\b" | grep -v "rpm\b"`; do
			    if [ -d "$dkms_tree/$module_in_tree/$version_in_tree/$filename" ] && ! [ -h "$dkms_tree/$module_in_tree/$version_in_tree/$filename" ]; then
				kernels_needing_status="$kernels_needing_status $filename"
			    fi
			done    
		    fi

		    # Source in the dkms.conf
		    conf="$dkms_tree/$module_in_tree/$version_in_tree/source/dkms.conf"
		    read_conf $conf

	            # Iterate over the kernels
		    for kernel_in_tree in $kernels_needing_status; do

     	                # Make sure its in the tree
			if [ -d "$dkms_tree/$module_in_tree/$version_in_tree/$kernel_in_tree" ]; then
			    readlink "$dkms_tree/$module_in_tree/kernel-${kernel_in_tree}"
			    kernel_symlink="$read_link"
			    extra_status=""
			    if [ -n "`find "$dkms_tree/$module_in_tree/original_module/$kernel_in_tree/" -type f -maxdepth 1 2>/dev/null`" ]; then
				extra_status=" (original_module exists)"
			    fi
			    if [ "$kernel_symlink" == "$version_in_tree/$kernel_in_tree" ]; then
				activity_state="installed"
				count=0
				while [ "$count" -lt "${#dest_module_name[*]}" ]; do
				    if ! `diff "$dkms_tree/$module_in_tree/$version_in_tree/$kernel_in_tree/module/${dest_module_name[$count]}$module_suffix" "/lib/modules/$kernel_in_tree${dest_module_location[$count]}/${dest_module_name[$count]}$module_suffix" >/dev/null 2>&1`; then
					extra_status="$extra_status (WARNING! Diff between built and installed module!)"
				    fi
				    count=$(($count+1))
				done
			    else
				activity_state="built"
				count=0
				while [ "$count" -lt "${#dest_module_name[*]}" ]; do
				    if ! [ -e "$dkms_tree/$module_in_tree/$version_in_tree/$kernel_in_tree/module/${dest_module_name[$count]}$module_suffix" ]; then
					extra_status="$extra_status (WARNING! Missing some built modules!)"
				    fi
				    count=$(($count+1))
				done
			    fi
			    status_shown="true"
			    echo "$module_in_tree, $version_in_tree, $kernel_in_tree: $activity_state$extra_status" 
			fi
			
		    done

		    if [ "$kernels_needing_status" == "" ]; then
			status_shown="true"
			echo "$module_in_tree, $version_in_tree: added" 
		    fi
		    
		fi
		
	    done
	    
	fi
	
    done
    
    if [ -z "$status_shown" ]; then
	echo $"" >$std_err
	echo $"Nothing found within the DKMS tree for this status command." >$std_err
	echo $"If your modules were not installed with DKMS, they will not show up here." >$std_err
    fi
}

make_driver_disk ()
{
    # Check that the right arguments were passed
    if [ -z "$module" ] || [ -z "$module_version" ] || [ -z "$distro" ] || [ -z "$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: mkdriverdisk [-d distro] [-m module] [-v module-version] [-k kernel-version]" >$std_err
	exit 1
    fi   

    # Check that source symlink works
    if ! [ -d "$dkms_tree/$module/$module_version/source" ]; then
	echo $"" >$std_err
	echo $"Error! DKMS tree does not contain: $module-$module_version" >$std_err
	echo $"Build cannot continue without the proper tree." >$std_err
	exit 2
    fi

    # Confirm that distro is supported
    if [ "$distro" != "redhat" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid distro argument." >$std_err
	echo $"Currently the only supported distro for this action is: redhat" >$std_err 
	exit 3
    fi

    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"Your dkms.conf is not valid." >$std_err
	exit 4
    fi

    # Create a list of modules to put into modules.cgz (make sure they exist too)
    kernel_version=`echo $kernel_version | cut -d "," --output-delimiter " " -f 1-`
    kernel_version_list=""
    modules_cgz_list=""
    temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX`
    for kernel in $kernel_version; do 
	count=0
	while [ "$count" -lt "${#dest_module_name[*]}" ]; do
	    if ! [ -e "$dkms_tree/$module/$module_version/$kernel/module/${dest_module_name[$count]}$module_suffix" ]; then
		echo $"" >$std_err
		echo $"Error! Cannot find module ${dest_module_name[$count]}$module_suffix for kernel $kernel." >$std_err
		echo $"Module/version must be in built state before making a driver disk." >$std_err
		rm -rf $temp_dir_name
		exit 5
	    fi
	    if [ -z "$kernel_version_list" ]; then
		kernel_version_list="kernel$kernel"
	    else
		kernel_version_list="$kernel_version_list-kernel$kernel"
	    fi
	    mkdir -p $temp_dir_name/$kernel
	    cp "$dkms_tree/$module/$module_version/$kernel/module/${dest_module_name[$count]}$module_suffix" "$temp_dir_name/$kernel/"
	    modules_cgz_list="$kernel/${dest_module_name[$count]}$module_suffix\n${modules_cgz_list}"
	    count=$(($count+1))
	done
    done

    # Create directory and necessary files
    mkdir -p "$dkms_tree/$module/$module_version/driver_disk"
   
    # Copy files for the driver disk (or warn if not present)
    files_for_driverdisk="modinfo disk-info modules.dep pcitable"
    files_into_driverdisk="modules.cgz rhdd-6.1"
    for file in $files_for_driverdisk; do
	if ! [ -e "$dkms_tree/$module/$module_version/source/redhat_driver_disk/$file" ]; then
	    echo $"Warning! File: $file not found in $dkms_tree/$module/$module_version/source/redhat_driver_disk/" >$std_err
	else
	    files_into_driverdisk="$file $files_into_driverdisk"
	    cp -f "$dkms_tree/$module/$module_version/source/redhat_driver_disk/$file" "$dkms_tree/$module/$module_version/driver_disk/" 2>/dev/null
	fi
    done
    echo "$module-$module_version driver disk" > "$dkms_tree/$module/$module_version/driver_disk/rhdd-6.1"

    # Make sure the kernel_version_list is not too long
    if [ `echo $kernel_version_list | wc -m | awk {'print $1'}` -gt 200 ]; then
	kernel_version_list="manykernels"
    fi

    # Create dos disk image
    image_name="$module-$module_version-$kernel_version_list-dd.img"  
    echo $""
    echo $"Creating driver disk:"
    cd $temp_dir_name
    invoke_command "echo -e '$modules_cgz_list' | cpio -oH crc 2>/dev/null | gzip -9 > ./modules.cgz" "compressing modules.cgz" background
    cp -f ./modules.cgz "$dkms_tree/$module/$module_version/driver_disk/"
    cd -
    rm -rf $temp_dir_name
    cd "$dkms_tree/$module/$module_version/driver_disk/"
    rm -f $image_name
    invoke_command "dd if=/dev/zero of="./$image_name" bs=72k count=20 >/dev/null 2>&1" "making a blank floppy image" background
    invoke_command "mkdosfs ./$image_name >/dev/null 2>&1" "mkdosfs" background
    mkdir ./mnt
    invoke_command "mount -o loop -t vfat $image_name ./mnt >/dev/null 2>&1" "loopback mounting disk image"
    for file in $files_into_driverdisk; do
	invoke_command "cp -f ./$file ./mnt/" "  copying $file to disk image"
    done
    invoke_command "umount ./mnt" "unmounting disk image"
    rm -rf ./mnt
    cd -
    echo $""
    echo $"Disk image location: $dkms_tree/$module/$module_version/driver_disk/$image_name"
    echo $""
    echo $"Done."
}

make_tarball()
{
    # Error if $module_version is set but $module is not
    if [ -z "$module" ] || [ -z "$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: mktarball [-m module] [-v module-version]" >$std_err
	exit 1	
    fi

    # Check that source symlink works
    if ! [ -d "$dkms_tree/$module/$module_version/source" ]; then
	echo $"" >$std_err
	echo $"Error! DKMS tree does not contain: $module-$module_version" >$std_err
	echo $"Build cannot continue without the proper tree." >$std_err
	exit 2
    fi

    # Make sure that its installed in the first place
    if ! [ -d "$dkms_tree/$module/$module_version" ]; then
	echo $"" >$std_err
	echo $"Error! The module/version combo: $module-$module_version" >$std_err
	echo $"is not located in the DKMS tree." >$std_err
	exit 3
    fi

    # Create a list of possible built kernels for this module
    built_for_kernels=`dkms status -m $module -v $module_version | awk '{print $3}' | grep ":" | sed 's/://'`

    if [ -z "$built_for_kernels" ]; then
	echo $"" >$std_err
	echo $"Error!  There are no built modules for any kernels for $module" >$std_err
	echo $"$module_version.  Cannot create an empty tarball." >$std_err
	exit 4
    fi

    # Read the conf file
    read_conf
    if [ "$?" -ne 0 ]; then
	echo $"" >$std_err
	echo $"Error! Bad conf file." >$std_err
	echo $"Your dkms.conf is not valid." >$std_err
	exit 5
    fi

    # If they specified a kernel(s), make sure everything is sane
    kernel_version=`echo $kernel_version | cut -d "," --output-delimiter " " -f 1-`
    for kernel in $kernel_version; do
	if [ `echo "$built_for_kernels" | grep -c "$kernel$"` -eq 0 ]; then
	    echo $"" >$std_err
	    echo $"Error! The kernel $kernel does not have modules built for" >$std_err
	    echo $"$module $module_version.  Cannot create archive." >$std_err
	    exit 6
	fi
    done

    # Create a temp directory and populate it
    temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX`
    mkdir -p $temp_dir_name/dkms_main_tree

    # Copy the source_tree or make special binaries-only structure
    if [ -z "$binaries_only" ]; then
	echo $""
	echo $"Marking $source_tree/$module-$module_version for archiving..."
	mkdir -p $temp_dir_name/dkms_source_tree
	cp -rf $source_tree/$module-$module_version/* $temp_dir_name/dkms_source_tree
    else
	echo $""
	echo $"Binaries only specified.  Creating special tarball structure to accomodate."
	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
	[ -z "$conf" ] && conf="$dkms_tree/$module/$module_version/source/dkms.conf"
	cp -f $conf $temp_dir_name/dkms_binaries_only/ 2>/dev/null
    fi

    # Determine the kernel_versions to put in the tarball
    kernel_version_list=""
    for kernel in $built_for_kernels; do
	if [ -z "$kernel_version" ] || [ `echo "$kernel_version" | grep -c "$kernel\b"` -gt 0 ]; then
	    if [ -z "$kernel_version_list" ]; then
		kernel_version_list="kernel$kernel"
	    else
		kernel_version_list="$kernel_version_list-kernel$kernel"
	    fi
	    echo $"Marking kernel $kernel for archiving..."
	    cp -rf "$dkms_tree/$module/$module_version/$kernel" $temp_dir_name/dkms_main_tree/
	fi
    done

    # Make the tarball
    cd $temp_dir_name
    if [ `echo $kernel_version_list | wc -m | awk {'print $1'}` -gt 200 ]; then
	kernel_version_list="manykernels"
    fi
    tar -czf $temp_dir_name/$module-$module_version-$kernel_version_list.$arch_used.dkms.tar.gz ./* 2>/dev/null
    cd -
    if [ "$?" -eq 0 ]; then
	mkdir -p $dkms_tree/$module/$module_version/tarball
	mv -f $temp_dir_name/$module-$module_version-$kernel_version_list.$arch_used.dkms.tar.gz $dkms_tree/$module/$module_version/tarball/
	echo $""
	echo $"Tarball location: $dkms_tree/$module/$module_version/tarball/$module-$module_version-$kernel_version_list.$arch_used.dkms.tar.gz"
	echo $""
	echo $"Done."
	rm -rf $temp_dir_name
    else
	echo $"" >$std_err
	echo $"Error! Failed to make tarball." >$std_err
	rm -rf $temp_dir_name
	exit 6
    fi
}

load_tarball()
{
    # Error out of --config was not set with the tarball location
    if [ -z "$archive_location" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: ldtarball [--archive=tarball-location]" >$std_err
	exit 1	
    fi

    # Error out if $archive_location does not exist
    if ! [ -e "$archive_location" ]; then
	echo $"" >$std_err
	echo $"Error! Cannot locate $archive_location." >$std_err
	echo $"File does not exist." >$std_err
	exit 2
    fi

    # Figure out what kind of archive it is (tar.gz, tar, tar.bz, etc)
    tar_options=""
    if `gzip -t $archive_location 2>/dev/null`; then
	tar_options="${tar_options}z"
    fi
    if `bzip2 -t $archive_location 2>/dev/null`; then
	tar_options="${tar_options}j"
    fi

    # Untar it into $tmp_location
    temp_dir_name=`mktemp -d $tmp_location/dkms.XXXXXX`
    tar -${tar_options}xf $archive_location -C $temp_dir_name 

    # Make sure its a sane tarball
    PACKAGE_NAME=""
    PACKAGE_VERSION=""
    is_from_mktarball=""
    is_binaries_only=""
    if ! [ -d "$temp_dir_name/dkms_main_tree" ]; then
	conf=`find $temp_dir_name/ -name dkms.conf 2>/dev/null | head -1`
	if [ -z "$conf" ]; then
	    echo $"" >$std_err
	    echo $"Error! Tarball does not appear to be a correctly formed" >$std_err
	    echo $"DKMS archive. No dkms.conf found within it." >$std_err
	    rm -rf $temp_dir_name
	    exit 3
	fi
	read_conf "$conf"
	if [ "$?" -ne 0 ]; then
	    echo $"" >$std_err
	    echo $"Error! Bad conf file." >$std_err
	    echo $"File: $conf does not represent a valid dkms.conf file" >$std_err
	    rm -rf $temp_dir_name
	    exit 4
	fi
	tarball_source_tree_name=`echo $conf | sed "s#$temp_dir_name\/##" | sed 's/dkms.conf//' | sed 's/\/$//'`
    elif ! [ -d "$temp_dir_name/dkms_source_tree" ] && [ -d "$temp_dir_name/dkms_binaries_only" ]; then
	PACKAGE_NAME=`cat $temp_dir_name/dkms_binaries_only/PACKAGE_NAME 2>/dev/null`
	PACKAGE_VERSION=`cat $temp_dir_name/dkms_binaries_only/PACKAGE_VERSION 2>/dev/null`
	if [ -z "$PACKAGE_NAME" ] || [ -z "$PACKAGE_VERSION" ]; then
	    echo $"" >$std_err
	    echo $"Error! Tarball does not appear to be a correctly formed" >$std_err
	    echo $"DKMS archive." >$std_err
	    rm -rf $temp_dir_name
	    exit 5
	fi
	if [ "`dkms status -m $PACKAGE_NAME -v $PACKAGE_VERSION 2>/dev/null`" == "" ] && [ -z "$force" ]; then
	    echo $"" >$std_err
	    echo $"Error! Tarball is a DKMS binaries-only archive, but your DKMS tree" >$std_err
	    echo $"does not have the source installed for $PACKAGE_NAME-$PACKAGE_VERSION." >$std_err
	    echo $"To load a DKMS binaries-only archive, you must already have the module" >$std_err
	    echo $"source in your DKMS tree." >$std_err
	    echo $"" >$std_err
	    echo $"This can be overridden by using --force, but this is not recommended since" >$std_err
	    echo $"it will eliminate your ability to actually build for this module." >$std_err
	    exit 6
	elif [ "`dkms status -m $PACKAGE_NAME -v $PACKAGE_VERSION 2>/dev/null`" == "" ] && [ -n "$force" ]; then
	    if [ -e "$temp_dir_name/dkms_binaries_only/dkms.conf" ]; then
		echo $""
		echo $"Binaries-only DKMS tarball to be loaded for $PACKAGE_NAME-$PACKAGE_VERSION"
		echo $"even though source for this module is not added to the DKMS tree.  This"
		echo $"will allow you to install the pre-built binaries contained within this"
		echo $"tarball, but will prevent you from building new modules for other kernels."
		echo $""
		echo $"Creating $source_tree/$PACKAGE_NAME-$PACKAGE_VERSION..."
		rm -rf $source_tree/$PACKAGE_NAME-$PACKAGE_VERSION
		mkdir -p $source_tree/$PACKAGE_NAME-$PACKAGE_VERSION
		echo $"Copying dkms.conf to $source_tree/$PACKAGE_NAME-$PACKAGE_VERSION..."
		cp -rf $temp_dir_name/dkms_binaries_only/dkms.conf $source_tree/$PACKAGE_NAME-$PACKAGE_VERSION
	    else
		echo $"" >$std_err
		echo $"Binaries-only DKMS tarball does not seem to contain a dkms.conf file for" >$std_err
		echo $"this module.  Unable to load this tarball into the DKMS tree." >$std_err
		exit 7
	    fi
	fi
	is_from_make_tarball="true"
	is_binaries_only="true"
    elif [ -d "$temp_dir_name/dkms_source_tree" ]; then
	. $temp_dir_name/dkms_source_tree/dkms.conf 2>/dev/null
	if [ -z "$PACKAGE_NAME" ] || [ -z "$PACKAGE_VERSION" ]; then
	    echo $"" >$std_err
	    echo $"Error! Tarball does not appear to be a correctly formed" >$std_err
	    echo $"DKMS archive." >$std_err
	    rm -rf $temp_dir_name
	    exit 8
	fi
	is_from_mktarball="true"
	tarball_source_tree_name="dkms_source_tree"
    else
	echo $"" >$std_err
	echo $"Error! Tarball does not appear to be a correctly formed" >$std_err
	echo $"DKMS archive." >$std_err
	rm -rf $temp_dir_name
	exit 8
    fi

    # Make sure we got what we needed from the tarball
    module="$PACKAGE_NAME"
    module_version="$PACKAGE_VERSION"

    echo $""
    echo $"Loading tarball for module: $module / version: $module_version"
    echo $""

    # Load the source from the tarball
    if [ -z "$is_binaries_only" ]; then
	if [ "`dkms status -m $module -v $module_version 2>/dev/null`" != "" ] && [ -z "$force" ]; then
	    echo $"Warning! Source for $module-$module_version already exists.  Skipping..."
	else
	    echo $"Loading $source_tree/$module-$module_version..."
	    rm -rf $source_tree/$module-$module_version
	    mkdir -p $source_tree/$module-$module_version
	    cp -rf $temp_dir_name/$tarball_source_tree_name/* $source_tree/$module-$module_version
	fi

	mkdir -p $dkms_tree/$module/$module_version
    fi

    # Load kernel directories
    dirs_to_load=`find $temp_dir_name/dkms_main_tree -type d -maxdepth 1 -mindepth 1 2>/dev/null`
    for directory in $dirs_to_load; do
	dkms_dir_location="$dkms_tree/$module/$module_version/`echo $directory | sed 's/.*\///'`"
	if [ -d "$dkms_dir_location" ] && [ -z "$force" ]; then
	    echo $"Warning! $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
    
    # Create source symlink
    if [ -h "$dkms_tree/$module/$module_version/source" ] && [ -z "$force" ]; then
	echo $"Warning! $dkms_tree/$module/$module_version/source already exists.  Skipping..."
    else
	echo $"Creating $dkms_tree/$module/$module_version/source symlink..."
	rm -f "$dkms_tree/$module/$module_version/source"
	ln -s "$source_tree/$module-$module_version" "$dkms_tree/$module/$module_version/source"
    fi
    
    # Clean up /tmp
    rm -rf $temp_dir_name
}

run_match ()
{
    # Error if $template_kernel or $kernel_version are unset
    if [ -z "$template_kernel" ] || [ -z "$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! Invalid number of parameters passed." >$std_err
	echo $"Usage: match [--templatekernel=kernel-version] [-k kernel-version]" >$std_err
	echo $"   or: match [--templatekernel=kernel-version] [-k kernel-version] [-m module]" >$std_err
	exit 1	
    fi  

    # Error out if $template_kernel = $kernel_version
    if [ "$template_kernel" == "$kernel_version" ]; then
	echo $"" >$std_err
	echo $"Error! The templatekernel and the specified kernel version are the same." >$std_err
	exit 2
    fi

    # Set the IFS to split on new-lines and not on spaces
    IFS='
'
    # Read in the status of template_kernel
    template_kernel_status=`$0 status -k $template_kernel | grep ": installed"`
    
    # If $module is set, grep the status only for that module
    if [ -n "$module" ]; then

        # Make sure that its installed in the first place
	if ! [ -d "$dkms_tree/$module/" ]; then
	    echo $"" >$std_err
	    echo $"Error! The module: $module is not located in the DKMS tree." >$std_err
	    unset IFS
	    exit 3
	fi

	template_kernel_status=`echo "$template_kernel_status" | grep "^$module,"`
    fi

    echo $""
    echo $"Matching modules in kernel: $kernel_version" 
    echo $"to the configuration of kernel: $template_kernel" 

    # 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

        # Iterate over the kernel_status and match kernel to the template_kernel
	for template_line in $template_kernel_status; do
	    template_module=`echo "$template_line" | sed 's/\(.*\), .*, .*:.*/\1/'`
	    template_version=`echo "$template_line" | sed 's/.*, \(.*\), .*: .*/\1/'`
	    
	    # 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 [ `$0 status -m "$template_module" -v "$template_version" -k "$kernel_version" 2>/dev/null | grep -c ": installed"` -eq 1 ]; then
		echo $"" 
		echo $"This module/version combo is already installed.  Nothing to be done." 
	    elif [ `$0 status -m "$template_module" -v "$template_version" -k "$kernel_version" 2>/dev/null | grep -c ": built"` -eq 1 ]; then
		unset IFS
		echo $"" 
		echo $"This module/version combo is built.  Installing it:" 
		module="$template_module"
		module_version="$template_version"
		install_module
		IFS='
'
	    else
		unset IFS
		echo $"" 
		echo $"Building & Installing this module/version:" 
		module="$template_module"
		module_version="$template_version"
		build_module "no-prepare-kernel"
		install_module
		IFS='
'
	    fi
	done
    fi

    # Return the IFS to its old state
    unset IFS

    # Clean up the kernel tree
    cd "/lib/modules/$kernel_version/build"
    invoke_command "make mrproper >/dev/null 2>&1" "Cleaning kernel tree (make mrproper)" background
    if [ -n "$config_contents" ]; then
	echo "$config_contents" > .config
	echo "$kerneldoth_contents" > /boot/kernel.h
    fi
    cd -
    
    # Done
    echo $"" 
    echo $"Match Completed."
}

#############################
####                     #### 
#### Program Starts Here ####
####                     ####
#############################

# Set important variables
current_kernel=`uname -r`
dkms_tree="/var/dkms"
source_tree="/usr/src"
tmp_location="/tmp"
dkms_frameworkconf="/etc/dkms_framework.conf"

# Source in /etc/dkms_framework.conf
. /etc/dkms_framework.conf 2>/dev/null

# Clear out command line argument variables
module=""
module_version=""
kernel_version=""
template_kernel=""
distro=""
conf=""
kernel_config=""
archive_location=""
kernel_source_dir=""
action=""
force=""
no_prepare_kernel=""
no_clean_kernel=""
binaries_only=""
all=""
gt2dot4=""
module_suffix=""
rpm_safe_upgrade=""
arch_used=""
std_err="/dev/stderr"
unset directive_array

# Parse command line arguments
while [ $# -gt 0 ]; do
    case $1 in
	--module*|-m)
	    if echo $1 | grep '=' >/dev/null ; then
		module=`echo $1 | sed 's/^.*=//'`
            else
                module="$2"
                shift
            fi
            ;;
	-v)
	    if echo $1 | grep '=' >/dev/null ; then
		module_version=`echo $1 | sed 's/^.*=//'`
            else
                module_version="$2"
                shift
            fi
            ;;
	--kernelver*|-k)
	    if echo $1 | grep '=' >/dev/null ; then
		kernel_version=`echo $1 | sed 's/^.*=//'`
            else
                kernel_version="$2"
                shift
            fi
            ;;
	--distro*|-d)
	    if echo $1 | grep '=' >/dev/null ; then
		distro=`echo $1 | sed 's/^.*=//'`
	    else
		distro="$2"
		shift
	    fi
	    ;;
	--templatekernel*)
	    if echo $1 | grep '=' >/dev/null ; then
		template_kernel=`echo $1 | sed 's/^.*=//'`
            else
                template_kernel="$2"
                shift
            fi
            ;;
	-c)
	    if echo $1 | grep '=' >/dev/null ; then
		conf=`echo $1 | sed 's/^.*=//'`
            else
                conf="$2"
                shift
            fi
            ;;
	--quiet|-q)
	    exec >/dev/null 2>&1
	    ;;
	--version|-V)
	    echo $"dkms: 1.12"
	    exit 0
	    ;;
	--no-prepare-kernel)
	    no_prepare_kernel="no-prepare-kernel"
	    ;;
	--no-clean-kernel)
	    no_clean_kernel="no-clean-kernel"
	    ;;
	--binaries-only)
	    binaries_only="binaries-only"
	    ;;
	--force)
	    force="true"
	    ;;
	--all)
	    all="true"
	    ;;
	--rpm_safe_upgrade)
	    rpm_safe_upgrade="true"
	    ;;
	--dkmstree*)
	    if echo $1 | grep '=' >/dev/null ; then
		dkms_tree=`echo $1 | sed 's/^.*=//'`
            else
                dkms_tree="$2"
                shift
            fi
            ;;
	--sourcetree*)
	    if echo $1 | grep '=' >/dev/null ; then
		source_tree=`echo $1 | sed 's/^.*=//'`
            else
                source_tree="$2"
                shift
            fi
            ;;
	--config*)
	    if echo $1 | grep '=' >/dev/null ; then
		kernel_config=`echo $1 | sed 's/^.*=//'`
            else
                kernel_config="$2"
                shift
            fi
	    ;;
	--archive*)
	    if echo $1 | grep '=' >/dev/null ; then
		archive_location=`echo $1 | sed 's/^.*=//'`
            else
                archive_location="$2"
                shift
            fi
	    ;;
	--kernelsourcedir*)
	    if echo $1 | grep '=' >/dev/null ; then
		kernel_source_dir=`echo $1 | sed 's/^.*=//'`
            else
                kernel_source_dir="$2"
                shift
            fi
	    ;;
	--directive*)
	    if echo $1 | grep '=' >/dev/null ; then
		directive_array[${#directive_array[*]}]=`echo $1 | sed 's/[^=]\+=//'`
            else
                directive_array[${#directive_array[*]}]="$2"
                shift
            fi
	    ;;
	-*|--*)
	    echo $"" >&2
	    echo $"Error!  Unknown option: $1" >&2
	    show_usage
	    exit 2
	    ;;
	*)
	    action="$action $1"
	    ;;
    esac
    shift
done

# Test kernel variant to know module_suffix
kernel_test="$kernel_version"
[ -z "$kernel_test" ] && kernel_test=`uname -r`
[ `echo "$kernel_test" | cut -d "." -f 1-1` -gt 1 ] && [ `echo "$kernel_test" | cut -d "." -f 2-2` -gt 4 ] && gt2dot4="true"
[ -z "$gt2dot4" ] && module_suffix=".o" || module_suffix=".ko"

# Set the arch_used (hack to get ia32e when needed)
[ `uname -m` == "x86_64" ] && [ `cat /proc/cpuinfo | grep -c "Intel"` -gt 0 ] && [ `ls /lib/modules/$kernel_test/build/configs 2>/dev/null | grep -c "ia32e"` -gt 0 ] && arch_used="ia32e" || arch_used=`uname -m`

# Run the specified action
#for action_to_run in `echo $action | sed 's/,/ /g'`; do
for action_to_run in $action; do
    case "$action_to_run" in
	add)
	    add_module
	    ;;
	remove)
	    # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    remove_module
	    ;;
	build)
	    build_module $no_prepare_kernel
	    ;;
	install)
            # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    install_module
	    ;;
	match)
	    # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    run_match
	    ;;
	uninstall)
	    # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    uninstall_module
	    ;;
	mkdriverdisk)
	    # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    make_driver_disk
	    ;;	
	mktarball)
	    make_tarball
	    ;;	
	ldtarball)
	    # Make sure they're root
	    if [ `id -u` -ne 0 ]; then
		echo $"You must be root to use this command." >$std_err
		exit 1
	    fi
	    load_tarball
	    ;;
	status)
	    show_status
	    ;;
	"")
	    echo "" >&2
	    echo $"Error! No action was specified.">$std_err
	    show_usage
	    ;;
	*)
	    echo "" >&2
	    echo $"Error! Unknown action specified: $action_to_run" >$std_err
	    show_usage
	    ;;
    esac
done
