#!/bin/bash
#
# Script invoked by startmol. It loads the molsymglue
# module when necessary (typically only for 2.2 kernels)
#
# Usage: symcheck [vmlinux] [System.map] 
# 
# Environment variables used:
#
#	BIN_DIR (also used by mol_uname)
#	LIB_DIR

SYMFILES=("$@")

function _mol_uname() {
    $BIN_DIR/mol_uname "$@" -- $MOD_DIR
}

[ ! "${SYMFILES[@]}" ] && {
    SYMFILES=( /lib/modules/`uname -r`/build/System.map \
	       /var/tmp/System.map-`_mol_uname -p` \
	       /boot/System.map-`uname -r` \
	       /boot/System.map \
	       /usr/src/linux/System.map )
}

# RSYMS - required symbols
RSYMS=( handle_mm_fault next_mmu_context flush_hash_page )
TMPFILE=/tmp/System.map-tmp

##############################################################
# Implementation
##############################################################

# Usage: sym_load_module_helper file required_flag symbols ...
function sym_load_module_helper () {
    i=0; ERR=0; XERR=0; FNAME="$1";
    shift 2

    for Y in "$@" ; do
	    X=`grep ' '$Y'$' $FNAME` || ERR=1
	    X=`echo $X | awk -- '{ print $1 }'`

	    [ $ERR -eq 1 ] && {
		    echo "ERROR: The kernel symbol '$Y' could not be found"
		    XERR=1; ERR=0
	    }
	    #echo $Y" = 0x"$X
	    SYM_STRING=( ${SYM_STRING[*]} msym_$Y=0x$X )
    done
    return $XERR
}

function sym_load_module () {
    SYM_STRING=""
    sym_load_module_helper $1 1 ${RSYMS[*]}

    MOD=$LIB_DIR/modules/`_mol_uname -p`/molsymglue.o
    echo -e "Loading MOL molsymglue kernel module\n   $MOD"

    /sbin/insmod -f $MOD ${SYM_STRING[*]} > /dev/null || {
        # the mol_uname dir might not exist
	MODS=`find $LIB_DIR -name molsymglue.o` 
	for x in $MODS ; do
	    echo -e "Loading MOL molsymglue kernel module\n   $MOD"
	    /sbin/insmod -f $x ${SYM_STRING[*]} > /dev/null && return 0
	done
	exit 1
    }
    return 0
}

function symbol_extract () {
    SUCCESS=0
    for x in "${SYMFILES[@]}" ; do

	# expand relative paths
	y="${x##[!/]*}"
	[ "$y" == "" ] && { y="$ORGDIR/$x"; }

	[ ! -f $y ] && {
	    echo "The file '$y' is missing"
	    continue
	}
	echo "Examining '$y'"

	# detect and convert vmlinux files by checking the file size
	S=`wc -c "$y" | sed "s,^ *,," | cut -d" " -f 1`
	[ $S -ge 700000 ] && {
	    rm -f $TMPFILE
	    nm "$y" | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)|\(\.\.ng$$\)\|\(LASH[RL]DI\)'\
			| sort > $TMPFILE
	    y=$TMPFILE
	}

	$BIN_DIR/symchecker.pl $y
	[ $? != 0 ] && continue

	CACHE_FILE="/var/tmp/System.map-`_mol_uname -p`"
	[ $CACHE_FILE != "$y" ] && {
	    echo "Caching kernel symbol file as $CACHE_FILE"
	    rm -f $CACHE_FILE
	    cp "$y" $CACHE_FILE
	}
	sym_load_module "$y" && SUCCESS=1
	rm -f $TMPFILE

	[ "$SUCCESS" == "1" ] && return 0;
    done
    return 1
}

function check_symbols () {
    unset LOADGLUE
    /sbin/lsmod | grep -q 'molsymglue' || {

        # If the following symbols are defined, 'molsymglue' does
	# not need to be loaded.
	#
	# Recent 2.4 kernels:
	#	handle_mm_fault, next_mmu_context, flush_hash_page, 
	#
	# Old 2.4 kernels:
	#	handle_mm_fault, next_mmu_context, mol_interface
	#
	# Otherwise, we must load molsymglue, defining
	#	msym_handle_mm_fault, msym_next_mmu_context, msym_flush_hash_page

	SYMS_NEW=( handle_mm_fault next_mmu_context flush_hash_page )
	SYMS_OLD=( handle_mm_fault next_mmu_context mol_interface )

	for x in ${SYMS_NEW[*]} ; do
	    grep -q $x /proc/ksyms  || LOADGLUE=1
	done

	[ "$LOADGLUE" ] && {
	    unset LOADGLUE
	    for x in ${SYMS_OLD[*]} ; do
		grep -q $x /proc/ksyms || LOADGLUE=1
	    done
	}
	# Debug
	#LOADGLUE=1
    }

    # As a last resort, extract the symbols by hand (molsymglue module)
    [ "$LOADGLUE" ] && {
	[ $UID != 0 ] && { echo "Please run 'startmol' as root" ; exit 1 ; }

	echo "Certain kernel symbols are missing. Trying to find a valid System.map file"

	symbol_extract || {
	    echo 
	    echo "========================================================================="
	    echo "  Unable to find the kernel symbol file. Start MOL by giving the"
	    echo "  command:"
	    echo 
	    echo "        startmol vmlinux"
	    echo 
	    echo "  where vmlinux is the image of the CURRENTLY running kernel. "
	    echo "  It is also possible to start MOL using the command"
	    echo 
	    echo "        startmol System.map"
	    echo 
	    echo "  where System.map is the symbol file of the running kernel."
	    echo "  For more information, please visit <http://www.maconlinux.org>"
	    echo "========================================================================="
	    echo 
	    exit 1
	}
    }
}

check_symbols

exit 0
