#! /bin/bash
# ***********************************************************************************
#                                   S O B C O N T R O L
# 
#
#   Project:    DeskFlash for Linux
#   Created:    OPUS Trinkl + Trinkl GmbH / PT                            
#   Purpose:    Control kernel modules gabiacpi, sobgabi, sobcmos, sobdata, sobproc, smbios
#   Changes:    
#       27.06.2018, PTri: added optional parameters dfkrnl and dfkrnl2 
#                   (for having only gabiacpi, sobgabi and sobdata starting and stopping)
#       06.07.2018, PTri: Added tracing and optional parameters trace, fake and nofake for 
#                   investigating driver unload problem with sobgabi.
#                   Removed mdlstart and mdlstop as they seem to be obsolete.
#       09.07.2018, PTri: Removed optional parameters fake and nofake; Using reverse
#                   unload driver sequence than loading.
#   Version:	1.80
# ******************************************+****************************************


# *** GLOBAL VARIABLES (command line options after parsing)
g_mode="verbose"
g_action="NA"
g_driverset_load=(gabiacpi sobgabi sobdata sobproc sobcmos smbios)
g_driverset_unload=(smbios sobcmos sobproc sobdata)

g_trace_enable="false" # initialize this variable with true to have tracing any way. Otherwise use 'trace' parameter.
g_trace_clear="true"  # initialize this variable with true to empty the trace file every script start.
g_trace_file="/opt/deskview/deskflash/bin/sobcontrol.trc.txt"

modulecheck() {
# $1 = directory
# $2 = device

    trace_out "modulecheck enter, device = $2"

    # check location of binary file
    if [ ! -f $1/$2.ko ] ; then
        return 3    # Not installed
    fi

    # check, if device named is listed in proc/devices
    # devname=`cat /proc/devices | awk "\\$2==\"$2\" {print \\$2}"`
    devname=`/sbin/lsmod | awk "\\$1==\"$2\" {print \\$1}"`

    trace_out "modulecheck leave, device = $2" 
    if [ "${devname}.ko" = "$2.ko" ] ; then
       return 2        # Already started
    else
       return 1        # Installed, but not started
    fi
}

modulestart() {
# $1 = directory
# $2 = device
# $3 = device group (e.g. users)
# $4 = device mode (e. g. 777)

    trace_out "modulestart enter, dir=$1, device=$2, group=$3, mode=$4";

    # echo -n " insmod"
    # invoke insmod 
    # First try without force, then force to load the module
    /sbin/insmod $1/$2.ko 2>/dev/null 1>/dev/null || /sbin/insmod -f $1/$2.o 2>/dev/null 1>/dev/null || return 1

    # get major number from "/proc/devices" list
    devmajor=`cat /proc/devices | awk "\\$2==\"$2\" {print \\$1}"`

    # If device isn't listed in '/proc/devices' it has no IOCTL interface
    # otherwise we link it to /dev/<device>
    if [ "$devmajor" != "" ]; then 
        # Remove stale nodes and replace them, then give gid and perms
        rm -f /dev/$2

        # echo -n " mkmod"
        #echo mknod /dev/$device c $devajor 0
        mknod /dev/$2 c $devmajor 0

        #echo chgrp $devgroup "/dev/$device"
        chgrp $3 "/dev/$2"

        # Changing access rights enables module being started from
        # user environment. Use chmod 777 or chmod +x+r+w
        chmod $4 "/dev/$2"
    fi
    trace_out "modulestart leave"
    return 0
}

modulestop() {
# $1 = device
    trace_out "modulestop enter, device=$1";
    # invoke rmmod with all arguments we got
    /sbin/rmmod $1 2>/dev/null || return 1

    # Remove stale nodes
    rm -f /dev/$1
    trace_out "modulestop leave"

    return 0
}

#
# Check parameters and set action, quiet mode or directory
#

# e. g. "/lib/modules/2.4.10-4GB/misc"

message() {
# print out text without new line
# $1 = text
    if [ "$g_mode" != "quiet" ]; then echo -n "$1 "; fi;
    trace_out_raw $1
    return 0
}

messagenl() {
# print out text with new line
# $1 = text
    if [ "$g_mode" != "quiet" ]; then echo $1; fi;
    trace_out $1 
    return 0
}

trace_out() {
# print out text with new line
# $1 = text
    if [ "$g_trace_enable" == "true" ]; then 
        echo -n `date +"%d.%m.%Y %H:%M:%S "` >>"$g_trace_file";
        echo " $1 " >>"$g_trace_file"; 
    fi;
    return 0
}

trace_out_raw() {
# print out text with new line
# $1 = text
    if [ "$g_trace_enable" == "true" ]; then 
        echo -n `date +"%d.%m.%Y %H:%M:%S"` >>"$g_trace_file";
        echo -n " $1 " >>"$g_trace_file"; 
    fi;
    return 0
}

module_dir_find() {
# Purpose: find the module at different locations:
#    list below
#
# Parameters
#    $1 = module name
#

    trace_out "module_dir_find enter, module=$1"

    if [ "$MODULE_DIR_FIRST" != "" ] ; then
        MODULE_DIR=$MODULE_DIR_FIRST
        # messagenl "[module_dir_find] checking $MODULE_DIR/$1"
        if [ -f $MODULE_DIR/$1 ] ; then 
            trace_out "module_dir_find leave, module=$1"
            return 0; 
        fi
    fi

    # 1) standard module path
    # 2) normal deskview module path
    # 3) tmp path
    for MODULE_DIR in /lib/modules/`uname -r`/kernel/drivers/deskview/`basename $1 .ko`\
                      /lib/modules/`uname -r`/misc\
                      /lib/modules/`uname -r`/extra/primergy-deskflash/`basename $1 .ko`/Sources\
                      /lib/modules/`uname -r`/weak-updates/primergy-deskflash/`basename $1 .ko`/Sources\
                      /lib/modules/`uname -r`/updates/`basename $1 .ko`/Sources\
                      /lib/modules/`uname -r`/weak-updates/`basename $1 .ko`/Sources\
		      /lib/modules/`uname -r`/weak-updates/updates/`basename $1 .ko`/Sources\
                      /lib/modules/`uname -r`/extra/primergy-deskflash/`basename $1 .ko`\
                      /lib/modules/`uname -r`/weak-updates/primergy-deskflash/`basename $1 .ko`\
                      /lib/modules/`uname -r`/updates/`basename $1 .ko`\
                      /lib/modules/`uname -r`/weak-updates/`basename $1 .ko`\
                      /lib/modules/`uname -r`/weak-updates/updates/`basename $1 .ko`\
                      /opt/deskview/share/device/lib\
                      /opt/deskview/deskflash/device/lib\
                      /opt/deskview/inventory/device/lib\
                      /tmp/deskview/device/lib\
                      /tmp/deskview\
                      .;
    do
        # messagenl "[module_dir_find] checking $MODULE_DIR/$1"
        if [ -f $MODULE_DIR/$1 ] ; then 
            trace_out "module_dir_find leave, module=$1";
            return 0; 
        fi
    done 

    trace_out "module_dir_find leave, module=$1"
    return 1
}

#
# Parsing the command line options
#

for i ; do
case "$i" in
quiet|verbose)
    g_mode=$i ;;
start|stop|try-restart|restart|force-reload|reload) 
    g_action=$i  ;;
trace)
    g_trace_enable=true  ;;
force) # obsolete 
    ;;
dfkrnl)
    ;;
dfkrnl2)
    g_driverset_load=(sobdata gabiacpi sobgabi)
    g_driverset_unload=(sobdata)
    ;;
*)  
    MODULE_DIR=$i ;;
esac
done
   
base=${0##*/}
link=${base#*[SK][0-9][0-9]}

# Return values acc. to LSB for all commands but status:
# 0 - success
# 1 - generic or unspecified error
# 2 - invalid or excess argument(s)
# 3 - unimplemented feature (e.g. "reload")
# 4 - insufficient privilege
# 5 - kernel module is not installed
# 6 - program is not running

if [ "$g_trace_enable" == "true" ] ; then
    if [ "$g_trace_clear" == "true" ] ; then
        rm -f "$g_trace_file";
    fi
fi

trace_out "*** beginning tracing, action=$g_action, mode=$g_mode"

# 
# Perform the selected function start, stop, ...
#
case "$g_action" in
    start)
    messagenl "Starting"; 

    # Try to find the module in several locations using module_dir_find()
    for MODULE_NAME in ${g_driverset_load[@]}; do
        ret=0
        module_dir_find $MODULE_NAME.ko
        if [ $ret -eq 0 ]; then
            message $MODULE_NAME;
            modulecheck $MODULE_DIR $MODULE_NAME
            ret=$?
        fi 
        if [ $ret -eq 3 ]; then messagenl " ... not installed! ";
        elif [ $ret -eq 2 ]; then messagenl " ... already running! ";
        elif [ $ret -eq 5 ]; then echo -n " ... not found! ";
        elif [ $ret -eq 1 ]; then modulestart $MODULE_DIR $MODULE_NAME users 777; messagenl "	OK"; fi
    done
    ;;

    stop)
    messagenl "Stopping"; 
    
    for MODULE_NAME in ${g_driverset_unload[@]}; do
        ret=0
        module_dir_find $MODULE_NAME.ko
        if [ $ret -eq 0 ]; then
            message "$MODULE_NAME";
            modulecheck $MODULE_DIR $MODULE_NAME
            ret=$? 
        fi 
    
        if [ $ret -eq 3 ]; then messagenl " ... not installed! ";
        elif [ $ret -eq 2 ]; then modulestop $MODULE_NAME; messagenl "	OK";
        elif [ $ret -eq 1 ]; then messagenl " NA"; fi
    done 
    ;;

    try-restart)
    $0 stop  &&  $0 start
    ;;

    restart)
    $0 stop
    $0 start
    ;;

    force-reload)
    $0 stop && $0 start
    ;;

    reload)
    echo -n "deskflash shared objects basic: Reload not supported ! "
    ;;

    *)
    echo "Usage: $0 {start|stop|try-restart|restart|force-reload|reload [dfkrnl|dfkrnl2] [quiet] [trace] [<directory>]}"
    exit 1
    ;;
esac

trace_out "*** finished tracing"
